Compilation transforms
Transforms for transpiling textbook gates into native trapped-ion gates.
The main transform in this module, ionizer.transforms.ionize(),
performs end-to-end transpilation and optimization of circuits. It calls a
number of helper transforms which can also be used individually.
All transforms contain a mechanism for under-the-hood equivalence checking (up
to a global phase) through the verify_equivalence flag. When set, an error
will be raised if the transpiled circuit is not equivalent to the original. For
details and example usage see Equivalence validation and
ionizer.utils.flag_non_equivalence().
- transforms.ionize(verify_equivalence=False)
Apply a sequence of passes to transpile and optimize a circuit over the trapped-ion gate set \(GPI\), \(GPI2\), and \(MS\).
The following sequence of passes is performed:
Decompose all operations into Paulis/Pauli rotations, Hadamard, and \(CNOT\)
Cancel inverses and merge single-qubit rotations
Convert everything except \(RZ\) to \(GPI\), \(GPI2\), and \(MS\) gates
Virtually apply \(RZ\) gates
Repeatedly apply single-qubit gate fusion and commutation through \(MS\) gates, and perform simplification based on a database of circuit identities.
Note
When
verify_equivalenceis set toTrue, equivalence checking up to a global phase is performed with respect to the initial and final circuit matrices only. It is not checked for intermediate transforms.- Parameters:
tape (pennylane.QuantumTape) – A quantum tape to transform.
verify_equivalence (bool) – Whether to perform background equivalence checking (up to global phase) of the circuit before and after the transform.
- Returns:
qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function]: The transformed circuit as described in
qml.transform.
Example
import pennylane as qml from ionizer.transforms import ionize dev = qml.device("default.qubit", wires=3) @qml.qnode(dev) @ionize def circuit(): qml.Hadamard(wires=0) qml.PauliX(wires=1) qml.RX(0.2, wires=2) qml.CRY(0.3, wires=[0, 1]) return qml.probs()
>>> qml.draw(circuit)() 0: ─────────────────────────────────────╭MS──────────────────────────────────────╭MS──GPI2(-1.57)─┤ Probs 1: ──GPI2(1.57)──GPI(-0.86)──GPI2(1.42)─╰MS──GPI2(-1.57)──GPI(2.43)──GPI2(-1.42)─╰MS──────────────┤ Probs 2: ──GPI2(1.57)──GPI(-1.47)──GPI2(1.57)───────────────────────────────────────────────────────────┤ Probs
- transforms.commute_through_ms_gates(direction='right', verify_equivalence=False)
Commute \(GPI\) and \(GPI2\) gates with special angle values through
MSgates.The following gates commute with \(MS\) gates when applied to either qubit in the \(MS\) gate: \(GPI2(0)\), \(GPI2(\pm \pi)\), \(GPI(0)\), \(GPI(\pm \pi)\).
When there are multiple adjacent \(MS\) gates, commuting \(GPI\) and \(GPI2\) gates are pushed as far as possible in the specified direction (see example).
This function is based on PennyLane’s commute_controlled transform.
- Parameters:
tape (pennylane.QuantumTape) – A quantum tape to transform.
direction (str) – Either
"right"(default) or"left"to indicate the direction gates should move (from a circuit diagram perspective).verify_equivalence (bool) – Whether to perform background equivalence checking (up to global phase) of the circuit before and after the transform.
- Returns:
qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function]: The transformed circuit as described in
qml.transform.
Example
import pennylane as qml from pennylane import numpy as np from functools import partial dev = qml.device("default.qubit", wires=3) @qml.qnode(dev) @partial(commute_through_ms_gates, direction="left") def circuit(): MS(wires=[0, 1]) MS(wires=[1, 2]) GPI2(np.pi, wires=0) GPI(0, wires=1) GPI(0.3, wires=2) return qml.probs()
>>> qml.draw(circuit)() 0: ──GPI2(3.14)─╭MS────────────────┤ Probs 1: ──GPI(0.00)──╰MS─╭MS────────────┤ Probs 2: ─────────────────╰MS──GPI(0.30)─┤ Probs
- transforms.virtualize_rz_gates(verify_equivalence=False)
Apply \(RZ\) gates virtually by adjusting the phase of adjacent \(GPI\) and \(GPI2\) gates.
This transform reads a circuit from left to right, and applies the following circuit identities (expressed in matrix order):
\(GPI(x) RZ(z) = GPI(x - z/2)\)
\(GPI2(x) RZ(z) = RZ(z) GPI2(x - z)\)
\(RZ\) are pushed as far right as possible, until \(MS\) gates are encountered or the end of the circuit is reached. Any \(RZ(\phi)\) that are not absorbed into native gates are then implemented as
\[RZ(\phi) = GPI(0) GPI(-\phi/2).\]- Parameters:
tape (pennylane.QuantumTape) – A quantum tape to transform
verify_equivalence (bool) – Whether to perform background equivalence checking (up to global phase) of the circuit before and after the transform.
- Returns:
qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function]: The transformed circuit as described in
qml.transform.
Example
import pennylane as qml from pennylane import numpy as np dev = qml.device("default.qubit", wires=2) @qml.qnode(dev) @virtualize_rz_gates def circuit(): qml.RZ(0.3, wires=0) GPI(0.5, wires=0) GPI2(0.2, wires=1) qml.RZ(np.pi/2, wires=1) GPI2(0.4, wires=1) GPI(-np.pi/2, wires=1) MS(wires=[0, 1]) qml.RZ(0.8, wires=1) return qml.probs()
>>> qml.draw(circuit)() 0: ──GPI(0.35)───────────────────────────╭MS────────────────────────┤ Probs 1: ──GPI2(0.20)──GPI2(-1.17)──GPI(-2.36)─╰MS──GPI(-0.40)──GPI(0.00)─┤ Probs
- transforms.single_qubit_fusion_gpi(verify_equivalence=False)
Simplify sequences of \(GPI\) and \(GPI2\) gates using gate fusion and circuit identities.
Any sequence of more than 3 gates will be fused and re-implemented up to global phase using \(GPI\) and \(GPI2\) (see
ionizer.utils.extract_gpi2_gpi_gpi2_angles()).Sequences of two or three gates (including those obtained through gate fusion) are then checked against the database of known circuit identities for simplifications (see
ionizer.identity_hunter.lookup_gate_identity()).This transform is based on PennyLane’s single_qubit_fusion transform.
- Parameters:
tape (pennylane.QuantumTape) – A quantum tape to transform.
verify_equivalence (bool) – Whether to perform background equivalence checking (up to global phase) of the circuit before and after the transform.
- Returns:
qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function]: The transformed circuit as described in
qml.transform.
Example
import pennylane as qml from pennylane import numpy as np dev = qml.device("default.qubit", wires=3) @qml.qnode(dev) @single_qubit_fusion_gpi def circuit(): # Known circuit identity GPI(np.pi/4, wires=0) GPI2(-3 * np.pi/4, wires=0) # Already three gates, but no known identity GPI2(0.2, wires=1) GPI2(0.4, wires=1) GPI(-np.pi/2, wires=1) # Squished down to three gates GPI2(0.1, wires=2) GPI2(0.2, wires=2) GPI(0.3, wires=2) GPI(0.4, wires=2) GPI2(0.5, wires=2) return qml.probs()
>>> qml.draw(circuit)() 0: ──GPI2(0.79)───────────────────────────┤ Probs 1: ──GPI2(0.20)───GPI2(0.40)──GPI(-1.57)──┤ Probs 2: ──GPI2(-1.57)──GPI(2.65)───GPI2(-0.97)─┤ Probs
- transforms.convert_to_gpi(exclude_list=None, verify_equivalence=False)
Transpile desired gates in a circuit to trapped-ion gates.
- Parameters:
tape (pennylane.QuantumTape) – A quantum tape to transform.
exclude_list (list[str]) – A list of names of gates to exclude from conversion (see the ionize transform for an example).
verify_equivalence (bool) – Whether to perform background equivalence checking (up to global phase) of the circuit before and after the transform.
- Returns:
qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function]: The transformed circuit as described in
qml.transform.
Example
import pennylane as qml from pennylane import numpy as np dev = qml.device("default.qubit", wires=3) @qml.qnode(dev) @partial(convert_to_gpi, exclude_list=["IsingYY"]) def circuit(): # Gates with known decompositions qml.Hadamard(wires=0) qml.PauliX(wires=1) qml.RX(0.2, wires=2) # Should not be decomposed qml.IsingYY(0.1, wires=[0, 1]) qml.IsingYY(0.2, wires=[0, 2]) # Gets expanded into two RY and two CNOT gates, which are then decomposed qml.CRY(0.3, wires=[0, 1]) return qml.probs()
>>> qml.draw(circuit)() 0: ──GPI(0.00)───GPI2(-1.57)─╭IsingYY(0.10)─╭IsingYY(0.20)──GPI2(1.57)────────────────────────╭MS───GPI2(3.14)──GPI2(-1.57)──GPI2(1.57)─────────────╭MS──GPI2(3.14)──GPI2(-1.57)─┤ Probs 1: ──GPI(0.00)───────────────╰IsingYY(0.10)─│───────────────GPI2(3.14)──GPI(0.07)──GPI2(3.14)─╰MS───GPI2(3.14)──GPI2(3.14)───GPI(-0.07)──GPI2(3.14)─╰MS──GPI2(3.14)──────────────┤ Probs 2: ──GPI2(1.57)──GPI(-1.47)───GPI2(1.57)────╰IsingYY(0.20)───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ Probs