qml.transforms.parity_synth¶
- parity_synth(tape)[source]¶
Pass for applying ParitySynth to phase polynomials in a circuit.
ParitySynth has been proposed by Vandaele et al. in arXiv:2104.00934 as a technique to synthesize phase polynomials into elementary quantum gates, namely
CNOTandRZ. For this, it synthesizes the parity table of the phase polynomial, and defers the remaining parity matrix synthesis to RowCol.This pass walks over the input circuit and aggregates all
CNOTandRZoperators into a subcircuit that describes a phase polyonomial. Other gates form the boundaries of these subcircuits, and whenever one is encountered the phase polynomial of the aggregated subcircuit is resynthesized with the ParitySynth algorithm. This implies that while this pass works on circuits containing any operations, it is recommended to maximize the subcircuits that represent phase polynomials (i.e. consist ofCNOTandRZgates) to enhance the effectiveness of the pass. This might be possible through decomposition or re-ordering of commuting gates. Note that higher-level program structures, such as nested functions and control flow, are synthesized independently, i.e., boundaries of such structures are always treated as boundaries of phase polynomial subcircuits as well. Similarly, dynamic wires create boundaries around the operations using them, potentially causing the separation of consecutive phase polynomial operations into multiple subcircuits.Example
In the following, we apply the pass to a simple quantum circuit that has optimization potential in terms of commuting gates that can be interchanged to unlock a cancellation of a self-inverse gate (
CNOT) with itself. Concretely, the circuit is:import pennylane as qml qml.capture.enable() dev = qml.device("lightning.qubit", wires=2) @qml.qnode(dev) def circuit(x: float, y: float, z: float): qml.CNOT((0, 1)) qml.RZ(x, 1) qml.CNOT((0, 1)) qml.RX(y, 1) qml.CNOT((1, 0)) qml.RZ(z, 1) qml.CNOT((1, 0)) return qml.state()
We can draw the circuit and observe the last
RZgate being wrapped in a pair ofCNOTgates that commute with it:>>> print(qml.draw(circuit)(0.52, 0.12, 0.2)) 0: ─╭●───────────╭●───────────╭X───────────╭X─┤ State 1: ─╰X──RZ(0.52)─╰X──RX(0.12)─╰●──RZ(0.20)─╰●─┤ State
Now we apply the
parity_synth_passto the circuit and quantum just-in-time (qjit) compile the circuit into a reduced MLIR module:qjit_circuit = qml.qjit(qml.transforms.parity_synth(circuit)) specs = qml.specs(qjit_circuit, level="device")(0.52, 0.12, 0.2)
Looking at the resources of the compiled module, we find only five gates left in the program; the
CNOTs have been cancelled successfully.>>> print(specs.resources["gate_types"]) {'RX': 1, 'RZ': 2, 'CNOT': 2}
Note that for this circuit, ParitySynth is run twice; once for the first three gates and once for the last three gates. This is because
RXis not a phase polynomial operation, so that it forms a boundary for the phase polynomial subcircuits that are re-synthesized by the pass.