qml.transforms.to_zx¶
- to_zx(tape, expand_measurements=False)[source]¶
This transform converts a PennyLane quantum tape to a ZX-Graph in the PyZX framework. The graph can be optimized and transformed by well-known ZX-calculus reductions.
- Parameters
tape (QNode or QuantumTape or Callable or Operation) – The PennyLane quantum circuit.
expand_measurements (bool) – The expansion will be applied on measurements that are not in the Z-basis and rotations will be added to the operations.
- Returns
The transformed circuit as described in
qml.transform
. Executing this circuit will provide the ZX graph in the form of a PyZX graph.- Return type
graph (pyzx.Graph) or qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function]
Example
You can use the transform decorator directly on your
QNode
, quantum function and executing it will produce a PyZX graph. You can also use the transform directly on theQuantumTape
.import pyzx dev = qml.device('default.qubit', wires=2) @qml.transforms.to_zx @qml.qnode(device=dev) def circuit(p): qml.RZ(p[0], wires=1), qml.RZ(p[1], wires=1), qml.RX(p[2], wires=0), qml.Z(0), qml.RZ(p[3], wires=1), qml.X(1), qml.CNOT(wires=[0, 1]), qml.CNOT(wires=[1, 0]), qml.SWAP(wires=[0, 1]), return qml.expval(qml.Z(0) @ qml.Z(1)) params = [5 / 4 * np.pi, 3 / 4 * np.pi, 0.1, 0.3] g = circuit(params)
>>> g Graph(20 vertices, 23 edges)
It is now a PyZX graph and can apply function from the framework on your Graph, for example you can draw it:
>>> pyzx.draw_matplotlib(g) <Figure size 800x200 with 1 Axes>
Alternatively you can use the transform directly on a quantum tape and get PyZX graph.
operations = [ qml.RZ(5 / 4 * np.pi, wires=1), qml.RZ(3 / 4 * np.pi, wires=1), qml.RX(0.1, wires=0), qml.Z(0), qml.RZ(0.3, wires=1), qml.X(1), qml.CNOT(wires=[0, 1]), qml.CNOT(wires=[1, 0]), qml.SWAP(wires=[0, 1]), ] tape = qml.tape.QuantumTape(operations) g = qml.transforms.to_zx(tape)
>>> g Graph(20 vertices, 23 edges)
Usage Details
Here we give an example of how to use optimization techniques from ZX calculus to reduce the T count of a quantum circuit and get back a PennyLane circuit.
Let’s start by starting with the mod 5 4 circuit from a known benchmark library the expanded circuit before optimization is the following QNode:
dev = qml.device("default.qubit", wires=5) @qml.transforms.to_zx @qml.qnode(device=dev) def mod_5_4(): qml.X(4), qml.Hadamard(wires=4), qml.CNOT(wires=[3, 4]), qml.adjoint(qml.T(wires=[4])), qml.CNOT(wires=[0, 4]), qml.T(wires=[4]), qml.CNOT(wires=[3, 4]), qml.adjoint(qml.T(wires=[4])), qml.CNOT(wires=[0, 4]), qml.T(wires=[3]), qml.T(wires=[4]), qml.CNOT(wires=[0, 3]), qml.T(wires=[0]), qml.adjoint(qml.T(wires=[3])) qml.CNOT(wires=[0, 3]), qml.CNOT(wires=[3, 4]), qml.adjoint(qml.T(wires=[4])), qml.CNOT(wires=[2, 4]), qml.T(wires=[4]), qml.CNOT(wires=[3, 4]), qml.adjoint(qml.T(wires=[4])), qml.CNOT(wires=[2, 4]), qml.T(wires=[3]), qml.T(wires=[4]), qml.CNOT(wires=[2, 3]), qml.T(wires=[2]), qml.adjoint(qml.T(wires=[3])) qml.CNOT(wires=[2, 3]), qml.Hadamard(wires=[4]), qml.CNOT(wires=[3, 4]), qml.Hadamard(wires=4), qml.CNOT(wires=[2, 4]), qml.adjoint(qml.T(wires=[4]),) qml.CNOT(wires=[1, 4]), qml.T(wires=[4]), qml.CNOT(wires=[2, 4]), qml.adjoint(qml.T(wires=[4])), qml.CNOT(wires=[1, 4]), qml.T(wires=[4]), qml.T(wires=[2]), qml.CNOT(wires=[1, 2]), qml.T(wires=[1]), qml.adjoint(qml.T(wires=[2])) qml.CNOT(wires=[1, 2]), qml.Hadamard(wires=[4]), qml.CNOT(wires=[2, 4]), qml.Hadamard(wires=4), qml.CNOT(wires=[1, 4]), qml.adjoint(qml.T(wires=[4])), qml.CNOT(wires=[0, 4]), qml.T(wires=[4]), qml.CNOT(wires=[1, 4]), qml.adjoint(qml.T(wires=[4])), qml.CNOT(wires=[0, 4]), qml.T(wires=[4]), qml.T(wires=[1]), qml.CNOT(wires=[0, 1]), qml.T(wires=[0]), qml.adjoint(qml.T(wires=[1])), qml.CNOT(wires=[0, 1]), qml.Hadamard(wires=[4]), qml.CNOT(wires=[1, 4]), qml.CNOT(wires=[0, 4]), return qml.expval(qml.Z(0))
The circuit contains 63 gates; 28
qml.T()
gates, 28qml.CNOT()
, 6qml.Hadmard()
and 1qml.X()
. We applied theqml.transforms.to_zx
decorator in order to transform our circuit to a ZX graph.You can get the PyZX graph by simply calling the QNode:
>>> g = mod_5_4() >>> pyzx.tcount(g) 28
PyZX gives multiple options for optimizing ZX graphs (
pyzx.full_reduce()
,pyzx.teleport_reduce()
, …). Thepyzx.full_reduce()
applies all optimization passes, but the final result may not be circuit-like. Converting back to a quantum circuit from a fully reduced graph may be difficult to impossible. Therefore we instead recommend usingpyzx.teleport_reduce()
, as it preserves the circuit structure.>>> g = pyzx.simplify.teleport_reduce(g) >>> pyzx.tcount(g) 8
If you give a closer look, the circuit contains now 53 gates; 8
qml.T()
gates, 28qml.CNOT()
, 6qml.Hadmard()
and 1qml.X()
and 10qml.S()
. We successfully reduced the T-count by 20 and have ten additional S gates. The number of CNOT gates remained the same.The
from_zx()
transform can now convert the optimized circuit back into PennyLane operations:tape_opt = qml.transforms.from_zx(g) wires = qml.wires.Wires([4, 3, 0, 2, 1]) wires_map = dict(zip(tape_opt.wires, wires)) tapes_opt_reorder, fn = qml.map_wires(input=tape_opt, wire_map=wires_map)[0][0] tape_opt_reorder = fn(tapes_opt_reorder) @qml.qnode(device=dev) def mod_5_4(): for g in tape_opt_reorder: qml.apply(g) return qml.expval(qml.Z(0))
>>> mod_5_4() tensor(1., requires_grad=True)
Note
It is a PennyLane adapted and reworked circuit_to_graph function.
Copyright (C) 2018 - Aleks Kissinger and John van de Wetering