scientific-skills/qiskit/references/transpilation.md
Transpilation is the process of rewriting a quantum circuit to match the topology and gate set of a specific quantum device, while optimizing for execution on noisy quantum computers.
Problem: Abstract quantum circuits may use gates not available on hardware and assume all-to-all qubit connectivity.
Solution: Transpilation transforms circuits to:
from qiskit import QuantumCircuit, transpile
qc = QuantumCircuit(3)
qc.h(0)
qc.cx(0, 1)
qc.cx(1, 2)
# Transpile for a specific backend
transpiled_qc = transpile(qc, backend=backend)
Choose optimization level 0-3:
# Level 0: No optimization (fastest)
qc_0 = transpile(qc, backend=backend, optimization_level=0)
# Level 1: Light optimization
qc_1 = transpile(qc, backend=backend, optimization_level=1)
# Level 2: Moderate optimization (default)
qc_2 = transpile(qc, backend=backend, optimization_level=2)
# Level 3: Heavy optimization (slowest, best results)
qc_3 = transpile(qc, backend=backend, optimization_level=3)
Qiskit SDK v2.2 provides 83x faster transpilation compared to competitors.
The transpiler pipeline consists of six stages:
from qiskit.transpiler import CouplingMap
# Define custom coupling
coupling = CouplingMap([(0, 1), (1, 2), (2, 3)])
qc_transpiled = transpile(qc, coupling_map=coupling)
# Specify basis gates
basis_gates = ['cx', 'id', 'rz', 'sx', 'x']
qc_transpiled = transpile(qc, basis_gates=basis_gates)
At optimization levels 2-3, Qiskit analyzes commutation structure to eliminate unnecessary SWAP gates by tracking virtual qubit permutations.
Identifies and removes pairs of gates that cancel:
Splits two-qubit gates that can be expressed as separable one-qubit operations.
Specify which physical qubits to use:
# Use specific physical qubits
initial_layout = [0, 2, 4] # Maps circuit qubits 0,1,2 to physical qubits 0,2,4
qc_transpiled = transpile(qc, backend=backend, initial_layout=initial_layout)
Trade accuracy for fewer gates (0.0 = max approximation, 1.0 = no approximation):
# Allow 5% approximation error for fewer gates
qc_transpiled = transpile(qc, backend=backend, approximation_degree=0.95)
qc_transpiled = transpile(qc, backend=backend, seed_transpiler=42)
# Add timing constraints
qc_transpiled = transpile(
qc,
backend=backend,
scheduling_method='alap' # As Late As Possible
)
Even for simulators, transpilation can optimize circuits:
from qiskit_aer import AerSimulator
simulator = AerSimulator()
qc_optimized = transpile(qc, backend=simulator, optimization_level=3)
# Compare gate counts
print(f"Original: {qc.size()} gates")
print(f"Optimized: {qc_optimized.size()} gates")
Use Target objects for detailed backend specifications:
from qiskit.transpiler import Target
# Transpile with target specification
qc_transpiled = transpile(qc, target=backend.target)
qc_transpiled = transpile(qc, backend=backend, optimization_level=3)
# Analyze results
print(f"Depth: {qc_transpiled.depth()}")
print(f"Gate count: {qc_transpiled.size()}")
print(f"Operations: {qc_transpiled.count_ops()}")
# Check two-qubit gate count (major error source)
two_qubit_gates = qc_transpiled.count_ops().get('cx', 0)
print(f"Two-qubit gates: {two_qubit_gates}")
Qiskit produces circuits with 29% fewer two-qubit gates than leading alternatives, significantly reducing errors.
Transpile multiple circuits efficiently:
circuits = [qc1, qc2, qc3]
transpiled_circuits = transpile(
circuits,
backend=backend,
optimization_level=3
)
Consider backend coupling map when designing circuits:
# Check backend coupling
print(backend.coupling_map)
# Design circuits that align with coupling
Some backends support gates beyond {CX, RZ, SX, X}:
# Check available basis gates
print(backend.configuration().basis_gates)
Two-qubit gates have significantly higher error rates:
from qiskit_aer import AerSimulator
# Test transpilation locally
sim_backend = AerSimulator.from_backend(backend)
qc_test = transpile(qc, backend=sim_backend, optimization_level=3)
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
backend = service.backend("ibm_brisbane")
qc_transpiled = transpile(qc, backend=backend)
# IonQ has all-to-all connectivity, different basis gates
basis_gates = ['gpi', 'gpi2', 'ms']
qc_transpiled = transpile(qc, basis_gates=basis_gates)
Transpilation depends on specific device (Rigetti, IonQ, etc.)
Solution: Use higher optimization level or redesign circuit with fewer layers
Solution: Adjust initial_layout to better match qubit topology
Solution: Reduce optimization level or update to Qiskit v2.2+ for speed improvements
Solution: Check basis_gates and consider specifying custom decomposition rules