qml.compile¶
- compile(tape, pipeline=None, basis_set=None, num_passes=1, expand_depth=None)[source]¶
Compile a circuit by applying a series of transforms to a quantum function.
The default set of transforms includes (in order):
pushing all commuting single-qubit gates as far right as possible (
commute_controlled()
)cancellation of adjacent inverse gates (
cancel_inverses()
)merging adjacent rotations of the same type (
merge_rotations()
)
Warning
The
expand_depth
argument is deprecated and will be removed in version 0.40.- Parameters
tape (QNode or QuantumTape or Callable) – A quantum circuit.
pipeline (list[Callable]) – 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, a default of
pennylane.ops.__all__
will be used. This decomposes templates and operator arithmetic.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) – The depth to use for tape expansion into the basis gates.
- Returns
The compiled circuit. The output type is explained in
qml.transform
.- Return type
qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function]
Example
>>> dev = qml.device('default.qubit', wires=[0, 1, 2])
You can apply the transform directly on a
QNode
:@qml.compile @qml.qnode(device=dev) def circuit(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.Y(2) qml.CY(wires=[1, 2]) return qml.expval(qml.Z(0))
The default compilation pipeline is applied before execution.
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.Y(2) qml.CY(wires=[1, 2]) return qml.expval(qml.Z(0))
Visually, the original function looks like this:
>>> 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_qnode = qml.compile(qnode) >>> 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
toqml.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_qnode = qml.compile( qnode, pipeline=[ partial(qml.transforms.commute_controlled, direction="left"), partial(qml.transforms.merge_rotations, atol=1e-6), qml.transforms.cancel_inverses ], basis_set=["CNOT", "RX", "RY", "RZ"], num_passes=2 ) 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─┤