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):
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()
)
- 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
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_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─┤