qml.compile

compile = <function compile>[source]

Compile a circuit by applying a series of transforms to a quantum function.

The default set of transforms includes (in order):

Parameters
  • qfunc (function) – A quantum function.

  • pipeline (list[single_tape_transform, qfunc_transform]) – A list of tape and/or quantum function transforms to apply.

  • basis_set (list[str]) – A list of basis gates. When expanding the tape, expansion will continue until gates in the specific set are reached. If no basis set is specified, no expansion will be done.

  • num_passes (int) – The number of times to apply the set of transforms in pipeline. The default is to perform each transform once; however, doing so may produce a new circuit where applying the set of transforms again may yield further improvement, so the number of such passes can be adjusted.

  • expand_depth (int) – When basis_set is specified, the depth to use for tape expansion into the basis gates.

Returns

the transformed quantum function

Return type

function

Example

Consider the following quantum function:

def qfunc(x, y, z):
    qml.Hadamard(wires=0)
    qml.Hadamard(wires=1)
    qml.Hadamard(wires=2)
    qml.RZ(z, wires=2)
    qml.CNOT(wires=[2, 1])
    qml.RX(z, wires=0)
    qml.CNOT(wires=[1, 0])
    qml.RX(x, wires=0)
    qml.CNOT(wires=[1, 0])
    qml.RZ(-z, wires=2)
    qml.RX(y, wires=2)
    qml.PauliY(wires=2)
    qml.CY(wires=[1, 2])
    return qml.expval(qml.PauliZ(wires=0))

Visually, the original function looks like this:

>>> dev = qml.device('default.qubit', wires=[0, 1, 2])
>>> qnode = qml.QNode(qfunc, dev)
>>> print(qml.draw(qnode)(0.2, 0.3, 0.4))
 0: ──H──RX(0.4)──────╭X─────────RX(0.2)──╭X───────┤ ⟨Z⟩
 1: ──H───────────╭X──╰C──────────────────╰C──╭CY──┤
 2: ──H──RZ(0.4)──╰C───RZ(-0.4)──RX(0.3)───Y──╰CY──┤

We can compile it down to a smaller set of gates using the qml.compile transform.

>>> compiled_qfunc = qml.compile()(qfunc)
>>> compiled_qnode = qml.QNode(compiled_qfunc, dev)
>>> print(qml.draw(compiled_qnode)(0.2, 0.3, 0.4))
 0: ──H───RX(0.6)───────────────────┤ ⟨Z⟩
 1: ──H──╭X─────────────────╭CY─────┤
 2: ──H──╰C────────RX(0.3)──╰CY──Y──┤

You can change up the set of transforms by passing a custom pipeline to qml.compile. The pipeline is a list of transform functions. Furthermore, you can specify a number of passes (repetitions of the pipeline), and a list of gates into which the compiler will first attempt to decompose the existing operations prior to applying any optimization transforms.

compiled_qfunc = qml.compile(
    pipeline=[
        qml.transforms.commute_controlled(direction="left"),
        qml.transforms.merge_rotations(atol=1e-6),
        qml.transforms.cancel_inverses
    ],
    basis_set=["CNOT", "RX", "RY", "RZ"],
    num_passes=2
)(qfunc)

compiled_qnode = qml.QNode(compiled_qfunc, dev)
>>> print(qml.draw(compiled_qnode)(0.2, 0.3, 0.4))
 0: ──RZ(1.57)──RX(1.57)──RZ(1.57)───RX(0.6)───────────────────────────────────────────────────────────────────────┤ ⟨Z⟩
 1: ──RZ(1.57)──RX(1.57)──RZ(1.57)──╭X────────RZ(1.57)──────────────────────────────────────────╭C─────────────╭C──┤
 2: ──RZ(1.57)──RX(1.57)──RZ(1.57)──╰C────────RX(0.3)───RZ(1.57)──RY(3.14)──RZ(1.57)──RY(1.57)──╰X──RY(-1.57)──╰X──┤