Source code for qrisp.circuit.pass_management.passes.resolve_swaps

"""********************************************************************************
* Copyright (c) 2026 the Qrisp authors
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is
* available at https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************
"""

from __future__ import annotations

from qrisp.circuit.pass_management.circuit_pass import CircuitPass
from qrisp.circuit.quantum_circuit import QuantumCircuit


[docs] @CircuitPass def resolve_swaps(qc: QuantumCircuit) -> QuantumCircuit: """Remove SWAP gates by folding them into qubit index remapping. Every SWAP encountered updates an internal permutation table. All subsequent instructions have their qubit operands remapped through this table, so the logical effect of the SWAP is preserved without any physical gates. This pass should be applied **before** routing. Instead of decomposing each SWAP into three CX gates, it tracks a running qubit permutation and remaps all subsequent gate operands accordingly. After processing, the circuit contains no SWAP gates and produces the same unitary up to a final qubit permutation. This especially means that the circuit statistics remain unchanged as the measurement instructions get permuted as well. Parameters ---------- qc : QuantumCircuit Input circuit, potentially containing ``swap`` instructions. Returns ------- QuantumCircuit A new circuit with all SWAP gates removed and operands remapped. Examples -------- Resolve a SWAP by remapping subsequent gate operands:: >>> from qrisp import QuantumCircuit, PassManager >>> from qrisp import resolve_swaps >>> qc = QuantumCircuit(2) >>> qc.h(0) >>> qc.swap(0, 1) >>> qc.cx(0, 1) >>> print(qc) ┌───┐ qb_126: ┤ H ├─X───■── └───┘ │ ┌─┴─┐ qb_127: ──────X─┤ X ├ └───┘ >>> pm = PassManager() >>> pm += resolve_swaps >>> routable_qc = pm.run(qc) >>> print(routable_qc) ┌───┐┌───┐ qb_126: ┤ H ├┤ X ├ └───┘└─┬─┘ qb_127: ───────■── """ n = qc.num_qubits() qubits = qc.qubits # perm[i] = current physical qubit index that logical qubit i maps to. # Starts as the identity. perm = list(range(n)) qc_new = qc.clearcopy() qubit_index = {qb: i for i, qb in enumerate(qubits)} for instr in qc.data: if instr.op.name == "swap": # Update the permutation: swap the two entries. a = qubit_index[instr.qubits[0]] b = qubit_index[instr.qubits[1]] perm[a], perm[b] = perm[b], perm[a] else: # Remap qubit operands through the current permutation. mapped_qubits = [qc_new.qubits[perm[qubits.index(q)]] for q in instr.qubits] qc_new.append(instr.op, mapped_qubits, instr.clbits) return qc_new