qml.tape.expand_tape

expand_tape(tape, depth=1, stop_at=None, expand_measurements=False)[source]

Expand all objects in a tape to a specific depth.

Parameters:
  • tape (QuantumTape) – The tape to expand

  • depth (int) – the depth the tape should be expanded

  • stop_at (Callable) – A function which accepts a queue object, and returns True if this object should not be expanded. If not provided, all objects that support expansion will be expanded.

  • expand_measurements (bool) – If True, measurements will be expanded to basis rotations and computational basis measurements.

Returns:

The expanded version of tape.

Return type:

QuantumTape

See also

decompose() for a transform that performs the same job and fits into the current transform architecture.

Warning

This method cannot be used with a tape with non-commuting measurements, even if expand_measurements=False.

>>> from pennylane.tape import expand_tape
>>> mps = [qml.expval(qml.X(0)), qml.expval(qml.Y(0))]
>>> tape = qml.tape.QuantumScript([], mps)
>>> expand_tape(tape)
Traceback (most recent call last):
    ...
pennylane.exceptions.QuantumFunctionError: Only observables that are qubit-wise commuting Pauli words can be returned on the same wire, some of the following measurements do not commute:
[expval(X(0)), expval(Y(0))]

Since commutation is determined by pauli word arithmetic, non-pauli words cannot share wires with other measurements, even if they commute:

>>> measurements = [qml.expval(qml.Projector([0], 0)), qml.probs(wires=0)]
>>> tape = qml.tape.QuantumScript([], measurements)
>>> expand_tape(tape)
Traceback (most recent call last):
    ...
pennylane.exceptions.QuantumFunctionError: Only observables that are qubit-wise commuting Pauli words can be returned on the same wire, some of the following measurements do not commute:
[expval(Projector(array([0]), wires=[0])), probs(wires=[0])]

For this reason, we recommend the use of decompose() instead.

>>> from pennylane.tape import expand_tape
>>> ops = [qml.Permute((2,1,0), wires=(0,1,2)), qml.X(0)]
>>> measurements = [qml.expval(qml.X(0))]
>>> tape = qml.tape.QuantumScript(ops, measurements)
>>> expanded_tape = expand_tape(tape)
>>> print(expanded_tape.draw())
0: ─╭SWAP──RX─╭GlobalPhase─┤  <X>
2: ─╰SWAP─────╰GlobalPhase─┤

Specifying a depth greater than one decomposes operations multiple times.

>>> expanded_tape2 = expand_tape(tape, depth=2)
>>> print(expanded_tape2.draw())
0: ─╭●─╭X─╭●──RX─┤  <X>
2: ─╰X─╰●─╰X─────┤

The stop_at callable allows the specification of terminal operations that should no longer be decomposed. In this example, the X operator is not decomposed because stop_at(qml.X(0)) == True.

>>> def stop_at(obj):
...     return isinstance(obj, qml.X)
>>> expanded_tape = expand_tape(tape, stop_at=stop_at)
>>> print(expanded_tape.draw())
0: ─╭SWAP──X─┤  <X>
2: ─╰SWAP────┤

Warning

If an operator does not have a decomposition, it will not be decomposed, even if stop_at(obj) == False. If you want to decompose to reach a certain gateset, you will need an extra validation pass to ensure you have reached the gateset.

>>> def stop_at(obj):
...     return getattr(obj, "name", "") in {"RX", "RY"}
>>> tape = qml.tape.QuantumScript([qml.RZ(0.1, 0)])
>>> expand_tape(tape, stop_at=stop_at).circuit
[RZ(0.1, wires=[0])]

If more than one observable exists on a wire, the diagonalizing gates will be applied and the observable will be substituted for an analogous combination of qml.Z operators. This will happen even if expand_measurements=False.

>>> mps = [qml.expval(qml.X(0)), qml.expval(qml.X(0) @ qml.X(1))]
>>> tape = qml.tape.QuantumScript([], mps)
>>> expanded_tape = expand_tape(tape)
>>> print(expanded_tape.draw())
0: ──RY─┤  <Z> ╭<Z@Z>
1: ──RY─┤      ╰<Z@Z>

Setting expand_measurements=True applies any diagonalizing gates and converts the measurement into a wires+eigvals representation.

Warning

Many components of PennyLane do not support the wires + eigvals representation. Setting expand_measurements=True should be used with extreme caution.

>>> tape = qml.tape.QuantumScript([], [qml.expval(qml.X(0))])
>>> expand_tape(tape, expand_measurements=True).circuit
[H(0), expval(eigvals=[ 1. -1.], wires=[0])]