qml.draw

draw(qnode, wire_order=None, show_all_wires=False, decimals=2, max_length=100, show_matrices=True, expansion_strategy=None)[source]

Create a function that draws the given qnode or quantum function.

Parameters
  • qnode (QNode or Callable) – the input QNode or quantum function that is to be drawn.

  • wire_order (Sequence[Any]) – the order (from top to bottom) to print the wires of the circuit

  • show_all_wires (bool) – If True, all wires, including empty wires, are printed.

  • decimals (int) – How many decimal points to include when formatting operation parameters. None will omit parameters from operation labels.

  • max_length (int) – Maximum string width (columns) when printing the circuit

  • show_matrices=False (bool) – show matrix valued parameters below all circuit diagrams

  • expansion_strategy (str) –

    The strategy to use when circuit expansions or decompositions are required. Note that this is ignored if the input is not a QNode.

    • gradient: The QNode will attempt to decompose the internal circuit such that all circuit operations are supported by the gradient method.

    • device: The QNode will attempt to decompose the internal circuit such that all circuit operations are natively supported by the device.

Returns

A function that has the same argument signature as qnode. When called, the function will draw the QNode/qfunc.

Example

@qml.qnode(qml.device('lightning.qubit', wires=2))
def circuit(a, w):
    qml.Hadamard(0)
    qml.CRX(a, wires=[0, 1])
    qml.Rot(*w, wires=[1], id="arbitrary")
    qml.CRX(-a, wires=[0, 1])
    return qml.expval(qml.Z(0) @ qml.Z(1))
>>> print(qml.draw(circuit)(a=2.3, w=[1.2, 3.2, 0.7]))
0: ──H─╭●─────────────────────────────────────────╭●─────────┤ ╭<Z@Z>
1: ────╰RX(2.30)──Rot(1.20,3.20,0.70,"arbitrary")─╰RX(-2.30)─┤ ╰<Z@Z>

By specifying the decimals keyword, parameters are displayed to the specified precision.

>>> print(qml.draw(circuit, decimals=4)(a=2.3, w=[1.2, 3.2, 0.7]))
0: ──H─╭●─────────────────────────────────────────────────╭●───────────┤ ╭<Z@Z>
1: ────╰RX(2.3000)──Rot(1.2000,3.2000,0.7000,"arbitrary")─╰RX(-2.3000)─┤ ╰<Z@Z>

Parameters can be omitted by requesting decimals=None:

>>> print(qml.draw(circuit, decimals=None)(a=2.3, w=[1.2, 3.2, 0.7]))
0: ──H─╭●────────────────────╭●──┤ ╭<Z@Z>
1: ────╰RX──Rot("arbitrary")─╰RX─┤ ╰<Z@Z>

If the parameters are not acted upon by classical processing like -a, then qml.draw can handle string-valued parameters as well:

>>> @qml.qnode(qml.device('lightning.qubit', wires=1))
... def circuit2(x):
...     qml.RX(x, wires=0)
...     return qml.expval(qml.Z(0))
>>> print(qml.draw(circuit2)("x"))
0: ──RX(x)─┤  <Z>

When requested with show_matrices=True (the default), matrix valued parameters are printed below the circuit. For show_matrices=False, they are not printed:

>>> @qml.qnode(qml.device('default.qubit', wires=2))
... def circuit3():
...     qml.QubitUnitary(np.eye(2), wires=0)
...     qml.QubitUnitary(-np.eye(4), wires=(0,1))
...     return qml.expval(qml.Hermitian(np.eye(2), wires=1))
>>> print(qml.draw(circuit3)())
0: ──U(M0)─╭U(M1)─┤
1: ────────╰U(M1)─┤  <𝓗(M0)>
M0 =
[[1. 0.]
[0. 1.]]
M1 =
[[-1. -0. -0. -0.]
[-0. -1. -0. -0.]
[-0. -0. -1. -0.]
[-0. -0. -0. -1.]]
>>> print(qml.draw(circuit3, show_matrices=False)())
0: ──U(M0)─╭U(M1)─┤
1: ────────╰U(M1)─┤  <𝓗(M0)>

The max_length keyword warps long circuits:

rng = np.random.default_rng(seed=42)
shape = qml.StronglyEntanglingLayers.shape(n_wires=3, n_layers=3)
params = rng.random(shape)

@qml.qnode(qml.device('lightning.qubit', wires=3))
def longer_circuit(params):
    qml.StronglyEntanglingLayers(params, wires=range(3))
    return [qml.expval(qml.Z(i)) for i in range(3)]

print(qml.draw(longer_circuit, max_length=60)(params))
0: ──Rot(0.77,0.44,0.86)─╭●────╭X──Rot(0.45,0.37,0.93)─╭●─╭X
1: ──Rot(0.70,0.09,0.98)─╰X─╭●─│───Rot(0.64,0.82,0.44)─│──╰●
2: ──Rot(0.76,0.79,0.13)────╰X─╰●──Rot(0.23,0.55,0.06)─╰X───

───Rot(0.83,0.63,0.76)──────────────────────╭●────╭X─┤  <Z>
──╭X────────────────────Rot(0.35,0.97,0.89)─╰X─╭●─│──┤  <Z>
──╰●────────────────────Rot(0.78,0.19,0.47)────╰X─╰●─┤  <Z>

The wire_order keyword specifies the order of the wires from top to bottom:

>>> print(qml.draw(circuit, wire_order=[1,0])(a=2.3, w=[1.2, 3.2, 0.7]))
1: ────╭RX(2.30)──Rot(1.20,3.20,0.70)─╭RX(-2.30)─┤ ╭<Z@Z>
0: ──H─╰●─────────────────────────────╰●─────────┤ ╰<Z@Z>

If the device or wire_order has wires not used by operations, those wires are omitted unless requested with show_all_wires=True

>>> empty_qfunc = lambda : qml.expval(qml.Z(0))
>>> empty_circuit = qml.QNode(empty_qfunc, qml.device('lightning.qubit', wires=3))
>>> print(qml.draw(empty_circuit, show_all_wires=True)())
0: ───┤  <Z>
1: ───┤
2: ───┤

Drawing also works on batch transformed circuits:

from functools import partial

@partial(qml.gradients.param_shift, shifts=[(0.1,)])
@qml.qnode(qml.device('default.qubit', wires=1))
def transformed_circuit(x):
    qml.RX(x, wires=0)
    return qml.expval(qml.Z(0))

print(qml.draw(transformed_circuit)(np.array(1.0, requires_grad=True)))
0: ──RX(1.10)─┤  <Z>

0: ──RX(0.90)─┤  <Z>

The function also accepts quantum functions rather than QNodes. This can be especially helpful if you want to visualize only a part of a circuit that may not be convertible into a QNode, such as a sub-function that does not return any measurements.

>>> def qfunc(x):
...     qml.RX(x, wires=[0])
...     qml.CNOT(wires=[0, 1])
>>> print(qml.draw(qfunc)(1.1))
0: ──RX(1.10)─╭●─┤
1: ───────────╰X─┤