qml.compile

compile(tape, pipeline=None, basis_set=None, num_passes=1, expand_depth=5)[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.40)────╭X──────────RX(0.20)─╭X────┤  <Z>
1: ──H───────────╭X─╰●───────────────────╰●─╭●─┤
2: ──H──RZ(0.40)─╰●──RZ(-0.40)──RX(0.30)──Y─╰Y─┤

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.60)─────────────────┤  <Z>
1: ──H─╭X──────────────────╭●────┤
2: ──H─╰●─────────RX(0.30)─╰Y──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.60)─────────────────────────────────────────────────────
1: ──RZ(1.57)──RX(1.57)──RZ(1.57)─╭X─────────RZ(1.57)─────────────────────────────────────────╭●
2: ──RZ(1.57)──RX(1.57)──RZ(1.57)─╰●─────────RX(0.30)──RZ(1.57)──RY(3.14)──RZ(1.57)──RY(1.57)─╰X

────────────────┤  <Z>
─────────────╭●─┤
───RY(-1.57)─╰X─┤