gray_synth_toffoli#

gray_synth_toffoli(qc: QuantumCircuit) QuantumCircuit[source]#

Replace Toffoli gates with a gray-synthesis decomposition.

Qrisp’s default Toffoli implementation is optimised for T-depth, since the majority of Qrisp algorithms target fault-tolerant execution where T gates dominate cost. The default decomposition does not have a higher CNOT count than the gray-synthesis variant, but it requires more SWAP gates when routed onto linear nearest-neighbour connectivity.

The gray-synthesis decomposition uses 6 CNOT gates and does not inherently satisfy linear connectivity either, but the router consistently resolves the gap with a single SWAP whose constituent CNOTs partially cancel with a Toffoli CNOT β€” resulting in 7 physical CNOTs and a displaced target qubit.

Parameters:
qcQuantumCircuit

The input quantum circuit.

Returns:
QuantumCircuit

A new circuit with every Toffoli replaced by the gray-synthesis decomposition.

Examples

We showcase the distinction in Toffoli decompositions.

>>> from qrisp import QuantumCircuit, PassManager
>>> from qrisp import gray_synth_toffoli, decompose
>>> qc = QuantumCircuit(3)
>>> qc.ccx(0, 1, 2)
>>> print(qc)

qb_95: ──■──
         β”‚
qb_96: ──■──
       β”Œβ”€β”΄β”€β”
qb_97: ─ X β”œ
       β””β”€β”€β”€β”˜
>>> pm_0 = PassManager()
>>> pm_0 += decompose()
>>> decomposed_qc = pm_0.run(qc)
>>> print(decomposed_qc)
       β”Œβ”€β”€β”€β”€β”€β”
qb_95: ─ Tdg β”œβ”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€
       β”œβ”€β”€β”€β”€β”€β”€β”Œβ”€β”€β”€β”  β”‚  β”Œβ”€β”€β”€β”β”Œβ”€β”΄β”€β”  β”‚  β”Œβ”€β”€β”€β”€β”€β”β”Œβ”€β”€β”€β” β”Œβ”€β”€β”€β” β”Œβ”€β”΄β”€β”
qb_96: ─ Tdg β”œβ”€ X β”œβ”€β”€β”Όβ”€β”€β”€ T β”œβ”€ X β”œβ”€β”€β”Όβ”€β”€β”€ Tdg β”œβ”€ X β”œβ”€β”€ T β”œβ”€β”€ X β”œ
       β””β”¬β”€β”€β”€β”¬β”˜β””β”€β”¬β”€β”˜β”Œβ”€β”΄β”€β”β”œβ”€β”€β”€β”€β””β”€β”€β”€β”˜β”Œβ”€β”΄β”€β”β””β”€β”€β”€β”€β”€β”˜β””β”€β”¬β”€β”˜β”Œβ”΄β”€β”€β”€β”΄β”β”œβ”€β”€β”€β”€
qb_97: ── H β”œβ”€β”€β”€β– β”€β”€β”€ X β”œβ”€ T β”œβ”€β”€β”€β”€β”€β”€ X β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€ Tdg β”œβ”€ H β”œ
        β””β”€β”€β”€β”˜      β””β”€β”€β”€β”˜β””β”€β”€β”€β”˜     β””β”€β”€β”€β”˜            β””β”€β”€β”€β”€β”€β”˜β””β”€β”€β”€β”˜

While this implementation has only a T-depth of 4, the CX gates essentially β€œcycle” through the connectivity requirements. On a linear chain connectivity, several swaps would be required.

>>> pm_1 = PassManager()
>>> pm_1 += gray_synth_toffoli
>>> pm_1 += decompose()
>>> optimized_qc = pm_1.run(qc)
>>> print(optimized_qc)
       β”Œβ”€β”€β”€β”                                                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
qb_95: ─ T β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β– β”€β”€β”€β”€ gphase β”œβ”€β”€β– β”€β”€
       β”œβ”€β”€β”€β”€                   β”‚                     β”‚  β”Œβ”€β”΄β”€β”β”Œβ”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Œβ”€β”΄β”€β”
qb_96: ─ T β”œβ”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€ X β”œβ”€ P(-Ο€/4) β”œβ”€ X β”œ
       β”œβ”€β”€β”€β”€β”Œβ”€β”€β”€β”β”Œβ”€β”΄β”€β”β”Œβ”€β”€β”€β”€β”€β”β”Œβ”€β”΄β”€β”β”Œβ”€β”€β”€β”β”Œβ”€β”΄β”€β”β”Œβ”€β”€β”€β”€β”€β”β”Œβ”€β”΄β”€β”β”œβ”€β”€β”€β”€β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β””β”€β”€β”€β”˜
qb_97: ─ H β”œβ”€ T β”œβ”€ X β”œβ”€ Tdg β”œβ”€ X β”œβ”€ T β”œβ”€ X β”œβ”€ Tdg β”œβ”€ X β”œβ”€ H β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
       β””β”€β”€β”€β”˜β””β”€β”€β”€β”˜β””β”€β”€β”€β”˜β””β”€β”€β”€β”€β”€β”˜β””β”€β”€β”€β”˜β””β”€β”€β”€β”˜β””β”€β”€β”€β”˜β””β”€β”€β”€β”€β”€β”˜β””β”€β”€β”€β”˜β””β”€β”€β”€β”˜

This implementation has T-depth 5 but the first 4 CX gates can be implemented swap-free on a linear chain connectivity. After this, a single SWAP (that can be fused with one of the CX) is suffificient to execute the remaining CX.