- Compilation/
Two-qubit Synthesis
Two-qubit Synthesis
Two-qubit gate synthesis takes in a 4 \times 4 unitary matrix U and synthesizes a circuit with an optimal \text{CNOT} gate count. This pass is implemented as qp.ops.two_qubit_decomposition in PennyLane.
The resulting circuits can take one of the following four forms, depending on how many CNOT gates are necessary.
| CNOTs | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
| Circuit | -A- -B- | -C--╭●--A- -D--╰X--B- | -A--╭X--RZ(α)--╭X--C- -B--╰●--RX(β)--╰●--D- | -C--╭X--RZ(δ)--╭●---------╭X--A- -D--╰●--RY(β)--╰X--RY(α)--╰●--B- |
A, B, C, D \in \text{SU}(2) are general single-qubit gates and, together with the angles \alpha, \beta, \delta \in \mathbb{R}, can be determined algebraically directly from the input matrix U (the exact process is described in the details tab).
In a NISQ setting, where costs for CNOT gates dominate, applying this pass to two-qubit gates may reduce the overall CNOT gate count.
Inputs
- Unitary matrix U \in \mathbb{C}^{4\times 4}
Outputs
- Decomposed circuit with an optimal \text{CNOT} gate count
Example
A tensor product of two operators requires 0 CNOT gates.
import pennylane as qp
import numpy as np
U = qp.matrix(qp.exp(-1j * 0.5 * X(0)), wire_order=range(2))
U @= qp.matrix(qp.exp(-1j * 0.5 * Y(1)), wire_order=range(2))
ops = qp.ops.two_qubit_decomposition(U, range(2))
circ = qp.tape.QuantumScript(ops, [])
assert np.allclose(U, qp.matrix(circ, wire_order=range(2)))
print(qp.drawer.tape_text(circ))
0: ──RZ──RY──RZ─┤
1: ──RZ──RY──RZ─┤
Note that a ZYZ decomposition is used to represent the \text{SU}(2) gate on each wire. This leads to a redundancy because the input matrix on wire 1 is already a R_Y rotation.
A general \text{SU}(4) element requires 3 CNOT gates.
SU4_generators = list(qp.pauli.pauli_group(2))
arbitrary_op = qp.dot(np.arange(16), SU4_generators)
U = qp.matrix(qp.exp(-1j * arbitrary_op))
ops = qp.ops.two_qubit_decomposition(U, range(2))
circ = qp.tape.QuantumScript(ops, [])
print(qp.drawer.tape_text(circ))
0: ──RZ──RY──RZ─╭X──RZ─╭●─────╭X──RZ──RY──RZ─┤
1: ──RZ──RY──RZ─╰●──RY─╰X──RY─╰●──RZ──RY──RZ─┤
There are intermediate cases with 1 and 2 CNOTs, respectively. Here is an example where 2 CNOT gates are required.
U = qp.matrix(qp.exp(-1j * 0.5 * X(0) @ Y(1)), wire_order=range(2))
ops = qp.ops.two_qubit_decomposition(U, range(2))
circ = qp.tape.QuantumScript(ops, [])
assert np.allclose(U, qp.matrix(circ, wire_order=range(2)))
print(qp.drawer.tape_text(circ))
0: ──RZ──RY──RZ─╭X──RZ─╭X──RZ──RY──RZ─┤
1: ──RZ──RY──RZ─╰●──RX─╰●──RZ──RY──RZ─┤
While the CNOT count is optimal, the overall decomposition may not be. This is because this pass always targets a fixed ansatz structure and may introduce some redundant single-qubit gates, as illustrated by this example.
>>> def circ():
... qp.CNOT((0, 1))
... qp.RX(0.5, 0)
... qp.RY(0.5, 1)
>>> U = qp.matrix(circ, wire_order=range(2))()
>>> print("Input circuit:\n")
>>> print(qp.draw(circ)(), "\n")
Input circuit:
0: ─╭●──RX(0.50)─┤
1: ─╰X──RY(0.50)─┤
>>> ops = qp.ops.two_qubit_decomposition(U, range(2))
>>> circ_re = qp.tape.QuantumScript(ops, [])
>>> assert np.allclose(U, qp.matrix(circ_re, wire_order=range(2)))
>>> print("Synthesized circuit:\n")
>>> print(qp.drawer.tape_text(circ_re, decimals=2))
Synthesized circuit:
0: ──RZ(2.01)──RY(0.00)──RZ(9.44)─╭●──RZ(8.96)──RY(0.50)──RZ(11.00)─┤
1: ──RZ(4.71)──RY(1.02)──RZ(1.57)─╰X──RZ(1.00)──RY(1.09)──RZ(11.28)─┤
Typical usage
This pass is necessary when the input unitary is provided as a matrix rather than a gate decomposition. In a NISQ setting, where costs for CNOT gates dominate, applying this pass to two-qubit gates may reduce the overall CNOT gate count.
References
[1] "Minimal Universal Two-qubit Quantum Circuits", Vivek V. Shende, Igor L. Markov, Stephen S. Bullock, arxiv:quant-ph/0308033, 2003
[2] "Recognizing Small-Circuit Structure in Two-Qubit Operators and Timing Hamiltonians to Compute Controlled-Not Gates", Vivek V. Shende, Stephen S. Bullock, Igor L. Markov, arXiv:quant-ph/0308045, 2003
[3] "Finding Small Two-Qubit Circuits", Vivek V. Shende, Igor L. Markov, and Stephen S. Bullock, preprint, 2004
Cite this page
@misc{PennyLane-2QSynthesis,
title = "Two-qubit Synthesis",
author = "Korbinian Kottmann",
year = "2025",
howpublished = "\url{https://pennylane.ai/compilation/two-qubit-synthesis}"
}Page author(s)
Korbinian Kottmann
Korbinian likes simulating quantum systems, whether it be via tensor network methods during his PhD, or with quantum computers at Xanadu. Currently, he works on quantum compilation to make simulation algorithms go brrr.