qml.change_op_basis

change_op_basis(compute_op, target_op, uncompute_op=None)[source]

Construct an operator that represents the product of the operators provided; particularly a compute-uncompute pattern.

Parameters:
  • compute_op (Operator | Callable) – A single operator or Callable with no inputs that applies quantum operations.

  • target_op (Operator | Callable) – A single operator or Callable with no inputs that applies quantum operations.

  • uncompute_op (None | Operator | Callable) – An optional single operator or Callable with no inputs that applies quantum operations. None corresponds to uncompute_op=qml.adjoint(compute_op).

Returns:

the operator representing the compute-uncompute pattern.

Return type:

ChangeOpBasis

Raises:

TypeError – if any arguments are not Callables or Operator s, or a Callable argument has input parameters.

Example

Consider the following example involving a ChangeOpBasis. The compute, uncompute pattern is composed of a Quantum Fourier Transform (QFT), followed by a PhaseAdder, and finally an inverse QFT.

import pennylane as qml
from functools import partial

qml.decomposition.enable_graph()

dev = qml.device("default.qubit")
@qml.qnode(dev)
def circuit():
    qml.H(0)
    qml.CNOT([1,2])
    qml.ctrl(
        qml.change_op_basis(qml.QFT([1,2]), qml.PhaseAdder(1, x_wires=[1,2])),
        control=0
    )
    return qml.state()

circuit2 = qml.decompose(circuit, max_expansion=1)

When this circuit is decomposed, the compute_op and uncompute_op are not controlled, resulting in a much more resource-efficient decomposition:

>>> print(qml.draw(circuit2)())
0: ──H──────╭●────────────────┤  State
1: ─╭●─╭QFT─├PhaseAdder─╭QFT†─┤  State
2: ─╰X─╰QFT─╰PhaseAdder─╰QFT†─┤  State

A Callable can also be provided as an argument to ChangeOpBasis. This can be a function that applies a series of Operation s. Since ChangeOpBasis requires this Callable to have no input arguments, functools.partial can be used to absorb any necessary parameters.

def my_compute_op(a, reg1, reg2):
    qml.BasisState(np.zeros(len(reg2)), reg2)
    qml.QFT(reg1)
    qml.RX(a, reg1[0])

def my_target_op(wires):
    qml.PauliX(wires[0])

dev = qml.device("default.qubit")
@qml.qnode(dev)
def circuit():
    # Use partial to absorb any input parameters
    compute = partial(my_compute_op, 0.1, [0], [1])
    target = partial(my_target_op, [0])
    qml.change_op_basis(compute, target)
    return qml.state()

circuit3 = qml.decompose(circuit, max_expansion=1)
>>> print(qml.draw(circuit3)())
0: ─╭RX(0.10)@QFT@|Ψ⟩──X─╭(RX(0.10)@QFT@|Ψ⟩)†─┤  State
1: ─╰RX(0.10)@QFT@|Ψ⟩────╰(RX(0.10)@QFT@|Ψ⟩)†─┤  State

See also

ChangeOpBasis