Modules
QuantumDebugger - Interactive Quantum Circuit Debugger and Simulator
A comprehensive Python library for quantum circuit debugging, profiling, and simulation with realistic noise models and error mitigation.
Features: - Step-through circuit debugging - State inspection and visualization - Realistic noise simulation (v0.3.0) - Zero-noise extrapolation (v0.4.0) - Qiskit integration - Hardware profile support
- class quantum_debugger.AmplitudeDamping(gamma: float)[source]
Bases:
NoiseModelAmplitude damping: Energy loss (T1 decay)
|1>can decay to|0>with rate gamma. Models spontaneous emission and energy relaxation.
- class quantum_debugger.BlochSphere[source]
Bases:
objectBloch sphere visualization for single qubits
- class quantum_debugger.Breakpoint(gate_index: int | None = None, condition: Callable[[QuantumState], bool] | None = None, description: str = '')[source]
Bases:
objectRepresents a breakpoint in circuit execution
- class quantum_debugger.BreakpointManager[source]
Bases:
objectManages breakpoints for debugging
- add(gate_index: int | None = None, condition: Callable[[QuantumState], bool] | None = None, description: str = '') Breakpoint[source]
Add a breakpoint
- Parameters:
gate_index – Gate index to break at
condition – Condition function
description – Breakpoint description
- Returns:
Created breakpoint
- check(gate_index: int, state: QuantumState) Breakpoint | None[source]
Check if any breakpoint should trigger
- Parameters:
gate_index – Current gate index
state – Current quantum state
- Returns:
Triggered breakpoint or None
- clear()[source]
Remove all breakpoints
- disable_all()[source]
Disable all breakpoints
- enable_all()[source]
Enable all breakpoints
- remove(breakpoint: Breakpoint)[source]
Remove a breakpoint
- class quantum_debugger.CircuitMetrics(circuit: QuantumCircuit)[source]
Bases:
objectContainer for circuit analysis metrics
- estimate_error_rate(single_error: float = 0.001, cnot_error: float = 0.01) float[source]
Estimate cumulative error rate
- Parameters:
single_error – Error rate for single-qubit gates
cnot_error – Error rate for CNOT gates
- Returns:
Estimated cumulative error rate
- class quantum_debugger.CircuitProfiler(circuit: QuantumCircuit)[source]
Bases:
objectProfiler for analyzing quantum circuit performance
- analyze() CircuitMetrics[source]
Analyze the circuit and return metrics
- Returns:
CircuitMetrics object with analysis results
- compare_with_ideal() Dict[source]
Compare circuit with theoretical ideal
- Returns:
Comparison metrics
- get_optimization_suggestions() List[str][source]
Get suggestions for circuit optimization
- Returns:
List of optimization suggestions
- print_report()[source]
Print comprehensive profiling report
- class quantum_debugger.CompositeNoise(noise_models: List[NoiseModel])[source]
Bases:
NoiseModelComposite noise model that applies multiple noise sources sequentially
Allows realistic simulation by combining different noise types: - Thermal relaxation (T1/T2) - Depolarizing errors - Readout errors - etc.
Example
>>> thermal = ThermalRelaxation(t1=100e-6, t2=80e-6, gate_time=50e-9) >>> depol = DepolarizingNoise(0.001) >>> composite = CompositeNoise([thermal, depol])
- class quantum_debugger.DepolarizingNoise(probability: float)[source]
Bases:
NoiseModelDepolarizing channel: random Pauli errors
With probability p, apply random Pauli (X, Y, or Z) error. Simulates random bit/phase flips.
- get_kraus_operators()[source]
Get Kraus operators for stochastic sampling
These describe the same channel as apply(), which implements the Pauli-error convention this class documents:
rho -> (1 - p) rho + (p/3) (X rho X + Y rho Y + Z rho Z)
so K0 = sqrt(1 - p) I and K1..K3 = sqrt(p/3) {X, Y, Z}.
The previous sqrt(p/4) form implemented a different convention, rho -> (1 - p) rho + p I/2, which coincides with the above only at 4p/3. StochasticNoiseSampler consumes this method, so the mismatch made sampled noise 4/3 stronger than apply() produced for the same p.
- Returns:
List of Kraus operators [K0, K1, K2, K3] for depolarizing channel
- class quantum_debugger.GateLibrary[source]
Bases:
objectLibrary of standard quantum gates
- CNOT = array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j], [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j]])
- CZ = array([[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [ 0.+0.j, 0.+0.j, 0.+0.j, -1.+0.j]])
- H = array([[ 0.70710678+0.j, 0.70710678+0.j], [ 0.70710678+0.j, -0.70710678+0.j]])
- S = array([[1.+0.j, 0.+0.j], [0.+0.j, 0.+1.j]])
- SWAP = array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]])
- T = array([[1. +0.j , 0. +0.j ], [0. +0.j , 0.70710678+0.70710678j]])
- TOFFOLI = array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])
- X = array([[0.+0.j, 1.+0.j], [1.+0.j, 0.+0.j]])
- Y = array([[ 0.+0.j, -0.-1.j], [ 0.+1.j, 0.+0.j]])
- Z = array([[ 1.+0.j, 0.+0.j], [ 0.+0.j, -1.+0.j]])
- class quantum_debugger.MPS(tensors, max_bond=None)[source]
Bases:
objectMatrix product state on
nqubits with maximum bond dimensionmax_bond.- add(other: MPS, normalize: bool = True) MPS[source]
Sum of two MPS by the direct-sum-of-bonds construction: the result represents
|self> + |other>(normalized by default). Bond dimensions add.
- amplitude(bits) complex[source]
The amplitude
<bits|psi>for a computational-basis string (qubiti=bits[i]), by contracting the fixed-bit tensor slices –O(n·chi^2), no dense state.
- apply_mpo(mpo, max_bond: int = None) MPS[source]
Apply a matrix product operator
mpo(list of rank-4Wtensors) to this MPS, returningH|psi>as a new MPS whose bond dimension is multiplied by the MPO bond dimension (optionally recompressed tomax_bond).
- apply_single(gate, qubit: int) MPS[source]
Apply a single-qubit gate to
qubit(exact, local contraction).
- apply_two(gate, qubit: int) MPS[source]
Apply a two-qubit
gate(4x4) to the neighbouring pair(qubit, qubit+1), then re-split by SVD and truncate the bond tomax_bond. The gate is indexed as acting on|q, q+1>with qubit the lower (little-endian) index.
- apply_two_long_range(gate, qubit_a: int, qubit_b: int) MPS[source]
Apply a two-qubit
gateto any pair(qubit_a, qubit_b), not just neighbours: SWAP the qubits together with a ladder of nearest-neighbour SWAPs, apply the gate, then SWAP back. The gate is indexed on|qubit_a, qubit_b>withqubit_athe lower index (as forapply_two()).
- bloch_vector(qubit: int) ndarray[source]
Bloch vector
(<X>, <Y>, <Z>)of onequbit(contraction, no dense state).
- bond_entropies() list[source]
Entanglement entropy (bits) across each of the
n-1bonds, from the Schmidt spectrum obtained by canonicalizing the MPS (a right-to-left SVD sweep to right-canonical form, then a left-to-right SVD sweep reading off the singular values). Scales to largen– no dense state. The maximum over bonds is the state’s peak bipartite entanglement.
- compress(max_bond: int) MPS[source]
Recompress the MPS to bond dimension
max_bondby an SVD roundtrip (canonicalize, truncate). Returns a new MPS; the truncation fidelity to the original is|<compressed|self>|^2.
- concurrence(qubit_a: int, qubit_b: int) float[source]
Wootters concurrence between two qubits (from their reduced density matrix) – the pairwise entanglement, 0 for a product pair and 1 for a Bell pair.
- correlation(obs_a, qubit_a: int, obs_b, qubit_b: int) float[source]
Two-point correlation
<psi| O_a O_b |psi>for single-qubit operators onqubit_aandqubit_b(contraction, no dense state).
- correlation_profile(obs_a, obs_b, ref: int = 0) list[source]
<O_a(ref) O_b(j)>versus sitej– a spatial correlation function.
- energy(terms) float[source]
Expectation
<psi|H|psi>of a Hamiltonian given as(coefficient, pauli_string)terms (the format ofpauli_decompose/ the VQE solver), summed by contraction. Lets any Hamiltonian – molecular, Fermi-Hubbard, spin – be evaluated on a large MPS.
- entanglement_entropy(bond: int) float[source]
Entanglement entropy (bits) across
bond(the cut between sites0..bondandbond+1..n-1).
- entanglement_spectrum(bond: int) ndarray[source]
The Schmidt coefficients (singular values, descending) across
bond– the full entanglement spectrum, of whichentanglement_entropy()is a summary.
- expectation(observable, qubit: int) float[source]
Expectation
<psi|O|psi>of a single-qubit observable onqubit, viaO(n * chi^3)tensor contraction – works for hundreds of qubits without ever building the dense state. Normalized by<psi|psi>.
- expectation_mpo(mpo) float[source]
<psi|H|psi>for an MPO, delegating toquantum_debugger.mpo.mpo_expectation().
- expectation_pauli(pauli_string: str) float[source]
Expectation
<psi|P|psi>of a full Pauli stringP(pauli_string[q]inI/X/Y/Zacts on qubitq), byO(n * chi^3)contraction – so any multi-qubit observable is measurable on a large MPS with no dense state.
- fidelity(other: MPS) float[source]
State fidelity
|<other|self>|^2 / (||self||^2 ||other||^2)to another MPS.
- classmethod from_bitstring(bits, max_bond: int = None) MPS[source]
Computational-basis-state MPS
|bits>from a bit sequence (qubiti=bits[i], little-endian). All bond dimensions 1.
- classmethod from_circuit(circuit, max_bond: int = None) MPS[source]
Run a
QuantumCircuiton the MPS engine, starting from|0...0>. Single-qubit gates are applied exactly; two-qubit gates use the long-range SWAP path (any connectivity), truncating the bond tomax_bond. Three-or-more qubit gates must be decomposed first (e.g. viatoffoli_gates/mcx_gates).For low-entanglement circuits this runs at scales the dense simulator cannot.
- classmethod from_product(single_qubit_states, max_bond: int = None) MPS[source]
Product-state MPS from a list of single-qubit amplitude pairs
[a, b]per qubit (each normalized). All bond dimensions are 1.
- classmethod from_statevector(state_vector, max_bond: int = None, tol: float = 1e-12) MPS[source]
Exact MPS for a dense
state_vectorvia sequential SVD (truncated tomax_bondif given). Qubitibecomes sitei(little-endian).
- magnetization_profile(observable) list[source]
<O_i>on every qubit for a single-qubitobservable(e.g. Z).
- most_probable(shots: int = 2000, seed: int = 0)[source]
The most probable computational-basis outcome, estimated from
shotssamples (returns the bitstring and its exact Born probability).
- mutual_information(qubit_a: int, qubit_b: int) float[source]
Quantum mutual information
I(a:b) = S(a) + S(b) - S(ab)between two qubits (bits), from their reduced density matrices – total correlation across the pair.
- normalize() MPS[source]
Rescale the MPS to unit norm in place (folding the scale into the first tensor). Returns
self.
- overlap(other: MPS) complex[source]
Inner product
<other|self>of two MPS on the same number of qubits, by sweeping the double-layer contraction inO(n * chi^3)– no dense state.
- purity_profile() list[source]
Single-qubit purity
Tr(rho_i^2)on every site (1 = pure, 0.5 = maximally mixed) – a local measure of how entangled each qubit is with the rest.
- classmethod random(n: int, bond: int = 4, seed: int = 0, max_bond: int = None) MPS[source]
A random MPS on
nqubits with bond dimensionbond(bonds taper to 1 at the ends). Normalized. Useful for testing and benchmarking.
- renyi_entropy(bond: int, alpha: float = 2.0) float[source]
Renyi-
alphaentanglement entropy acrossbond(bits).alpha -> 1is the von Neumann entropy (entanglement_entropy());alpha = 2is the collision entropy-log2 sum lambda^4.
- sample(shots: int, seed: int = 0) dict[source]
Draw
shotscomputational-basis measurement outcomes from the MPS by exact sequential conditional sampling –O(shots * n * chi^2), with no dense state. Returns a dict mapping bitstring (characteri= qubiti) to its count; the distribution is the exact Born rule.
- schmidt_gap(bond: int) float[source]
Gap between the two largest squared Schmidt values across
bond– an order parameter that closes at a quantum phase transition. 1 for a product cut.
- single_qubit_rdm(qubit: int) ndarray[source]
Reduced density matrix of one
qubit– built from its Pauli expectationsrho = (I + <X>X + <Y>Y + <Z>Z)/2by contraction, so it scales to large systems with no dense state.
- structure_factor(observable, momentum: float) float[source]
Static structure factor
S(k) = (1/n) sum_{i,j} e^{i k (i-j)} <O_i O_j>at wavevectormomentum– the Fourier transform of the spatial correlations, peaking at the ordering wavevector.
- total_magnetization(observable) float[source]
Sum of
<O_i>over all qubits for a single-qubitobservable.
- truncation_error(max_bond: int) float[source]
Weight lost when the MPS is compressed to bond dimension
max_bond:1 - |<compressed|self>|^2. Zero when the state already fits (a GHZ atmax_bond >= 2); grows as more of the entanglement spectrum is discarded.
- two_qubit_rdm(qubit_a: int, qubit_b: int) ndarray[source]
Reduced density matrix of two qubits, assembled from their 16 two-qubit Pauli expectations
(1/4) sum_{P,Q} <P_a Q_b> P (x) Q– scalable, matching the dense partial trace. The pair is returned in sorted (little-endian) order.
- two_site_expectation(operator, qubit_a: int, qubit_b: int) float[source]
Expectation of a two-qubit
operator(4x4, indexed on|a, b>little-endian) via the two-qubit reduced density matrix:Tr(O rho_ab)– for bond energies and general two-site observables.
- class quantum_debugger.PhaseDamping(gamma: float)[source]
Bases:
NoiseModelPhase damping: Phase coherence loss (T2 dephasing)
Random Z rotations causing phase errors. Preserves populations but destroys coherence.
- class quantum_debugger.QiskitAdapter[source]
Bases:
objectAdapter for converting between Qiskit and QuantumDebugger circuits
- GATE_MAP = {'ccx': 'toffoli', 'cp': 'cp', 'cx': 'cnot', 'cz': 'cz', 'h': 'h', 'p': 'phase', 'rx': 'rx', 'ry': 'ry', 'rz': 'rz', 's': 's', 'swap': 'swap', 't': 't', 'x': 'x', 'y': 'y', 'z': 'z'}
- static check_qiskit_available()[source]
Check if Qiskit is installed
- classmethod compare_circuits(qiskit_circuit: None, qd_circuit: QuantumCircuit) dict[source]
Compare a Qiskit circuit with a QuantumDebugger circuit
- Returns:
Dictionary with comparison results
- classmethod from_qiskit(qiskit_circuit: None) QuantumCircuit[source]
Convert a Qiskit QuantumCircuit to QuantumDebugger circuit
- Parameters:
qiskit_circuit – Qiskit QuantumCircuit to convert
- Returns:
QuantumDebugger QuantumCircuit
Example
>>> from qiskit import QuantumCircuit >>> qc_qiskit = QuantumCircuit(2) >>> qc_qiskit.h(0) >>> qc_qiskit.cx(0, 1) >>> qc_qd = QiskitAdapter.from_qiskit(qc_qiskit)
- classmethod to_qiskit(qd_circuit: QuantumCircuit) None[source]
Convert a QuantumDebugger circuit to Qiskit QuantumCircuit
- Parameters:
qd_circuit – QuantumDebugger circuit to convert
- Returns:
Qiskit QuantumCircuit
Example
>>> from quantum_debugger import QuantumCircuit >>> qc_qd = QuantumCircuit(2) >>> qc_qd.h(0) >>> qc_qd.cnot(0, 1) >>> qc_qiskit = QiskitAdapter.to_qiskit(qc_qd)
- class quantum_debugger.QuantumCircuit(num_qubits: int, num_classical: int = 0, noise_model: Any | None = None, noise_simulation_method: str = 'density_matrix', backend: str = 'auto')[source]
Bases:
objectQuantum circuit with gate operations
- count_gates(gate_name: str = None) int[source]
Count gates of specific type
- Parameters:
gate_name – Name of gate to count (None for all gates)
- draw(output: str = 'text') str[source]
Draw the circuit
- Parameters:
output – Output format (‘text’ for ASCII art)
- Returns:
String representation of circuit
- get_statevector(initial_state: QuantumState | None = None, use_gpu: bool = False, precision: str = 'double') QuantumState[source]
Get final state vector without measurements.
- Parameters:
initial_state – Optional initial state
use_gpu – Run the whole circuit on the GPU (CuPy). The state lives on the GPU for every gate and is transferred back to the CPU once at the end. Falls back to CPU if CuPy is unavailable.
precision – ‘double’ (complex128, default, exact) or ‘single’ (complex64 – much faster on consumer GPUs, at reduced precision).
- Returns:
Final quantum state (always CPU/NumPy-backed)
- measure(qubit: int, classical_bit: int = None)[source]
Measure a qubit
- Parameters:
qubit – Qubit index to measure
classical_bit – Classical bit to store result (defaults to same as qubit)
- measure_all()[source]
Measure all qubits
- run(shots: int = 1, initial_state: QuantumState | None = None, use_gpu: bool = False, precision: str = 'double') dict[source]
Execute the circuit.
The statevector is computed once and all shots are sampled from the resulting distribution. This is equivalent, for independent projective Z-measurements, to collapsing the state per shot, but costs O(gates + shots) instead of the previous O(shots x gates) (which re-simulated the whole circuit for every shot).
- Parameters:
shots – Number of measurement samples
initial_state – Optional initial state (defaults to
|0...0>)use_gpu – Simulate the circuit on the GPU (see get_statevector)
precision – ‘double’ (complex128) or ‘single’ (complex64) for the GPU path
- Returns:
Dictionary with measurement results and statistics
- class quantum_debugger.QuantumDebugger(circuit: QuantumCircuit, initial_state: QuantumState | None = None)[source]
Bases:
objectInteractive debugger for quantum circuits
- clear_breakpoints()[source]
Remove all breakpoints
- compare_with_expected(expected_state: QuantumState) Dict[source]
Compare current state with expected state
- Parameters:
expected_state – Expected quantum state
- Returns:
Comparison metrics
- continue_execution()[source]
Continue execution until end (alias for run_to_end)
- get_current_state()[source]
Get current quantum state (alias for get_state)
- get_execution_trace() List[Dict][source]
Get full execution trace
- Returns:
List of execution states with information
- get_state() QuantumState[source]
Get current quantum state
- inspect_state() Dict[source]
Get detailed information about current state
- Returns:
Dictionary with state information
- print_status()[source]
Print current debugging status
- reset()[source]
Reset debugger to initial state
- run_to_end()[source]
Execute all remaining gates
- run_until_breakpoint()[source]
Execute until a breakpoint is hit or circuit ends
- set_breakpoint(gate: int | None = None, condition=None, description: str = '') Breakpoint[source]
Set a breakpoint
- Parameters:
gate – Gate index to break at
condition – Conditional function
description – Breakpoint description
- Returns:
Created breakpoint
- step(steps: int = 1) bool[source]
Execute one or more gates
- Parameters:
steps – Number of gates to execute
- Returns:
True if stepped successfully, False if at end
- step_back(steps: int = 1) bool[source]
Step backwards in execution history
- Parameters:
steps – Number of steps to go back
- Returns:
True if stepped back successfully
- visualize()[source]
Print visualization of current state
- class quantum_debugger.QuantumState(num_qubits: int, state_vector: ndarray | None = None, backend='auto')[source]
Bases:
objectRepresents a quantum state vector
- apply_gate(gate_matrix: ndarray, target_qubits: List[int])[source]
Apply a quantum gate to specific qubits.
Uses tensor contraction, applying the k-qubit gate directly to the relevant axes of the state tensor. This is O(2**n) per gate instead of the O(4**n) cost of materializing the full 2**n x 2**n operator, so it is dramatically faster and more memory efficient for multi-qubit circuits.
- Parameters:
gate_matrix – Unitary matrix of the gate (2**k x 2**k for k qubits)
target_qubits – List of qubit indices to apply gate to. Gate qubit j acts on
target_qubits[j](matches the previous convention).
- bloch_vector(qubit: int = 0) Tuple[float, float, float][source]
Get Bloch sphere coordinates for a single qubit
- Parameters:
qubit – Index of qubit (for multi-qubit systems, traces out other qubits)
- Returns:
(x, y, z) coordinates on Bloch sphere
- copy()[source]
Create a deep copy of this state
- fidelity(other: QuantumState) float[source]
Calculate fidelity with another quantum state
- Parameters:
other – Another quantum state
- Returns:
Fidelity value between 0 and 1
- get_measurement_probability(qubit: int, outcome: int) float[source]
Get probability of measuring a specific outcome for a qubit
- is_entangled() bool[source]
Check if state is entangled (simple check for 2-qubit systems)
For 2 qubits: state is entangled if it cannot be written as tensor product
- class quantum_debugger.StateInspector[source]
Bases:
objectUtilities for inspecting quantum states during debugging
- static check_superposition(state: QuantumState, qubit: int, threshold: float = 0.1) bool[source]
Check if a qubit is in superposition
- Parameters:
state – Quantum state
qubit – Qubit index
threshold – Threshold for considering a state in superposition
- Returns:
True if qubit is in superposition
- static compare_states(state1: QuantumState, state2: QuantumState) Dict[source]
Compare two quantum states
- Parameters:
state1 – First quantum state
state2 – Second quantum state
- Returns:
Dictionary with comparison metrics
- static format_state_string(state: QuantumState, max_terms: int = 10) str[source]
Format quantum state as readable string
- Parameters:
state – Quantum state
max_terms – Maximum number of terms to show
- Returns:
Formatted string representation
- static get_amplitude_info(state: QuantumState) List[Dict][source]
Get detailed amplitude information for all basis states
- Parameters:
state – Quantum state
- Returns:
List of dictionaries with amplitude information
- static get_measurement_stats(state: QuantumState) Dict[str, float][source]
Get measurement statistics for all computational basis states
- Parameters:
state – Quantum state
- Returns:
Dictionary mapping basis states to probabilities
- static get_qubit_probabilities(state: QuantumState, qubit: int) Tuple[float, float][source]
Get measurement probabilities for a specific qubit
- Parameters:
state – Quantum state
qubit – Qubit index
- Returns:
(probability of 0, probability of 1)
- static get_state_summary(state: QuantumState) Dict[source]
Get a comprehensive summary of a quantum state
- Parameters:
state – Quantum state to inspect
- Returns:
Dictionary with state information
- static print_state_info(state: QuantumState)[source]
Print comprehensive state information to console
- Parameters:
state – Quantum state to inspect
- class quantum_debugger.StateVisualizer[source]
Bases:
objectVisualize quantum states
- static plot_density_matrix(state: QuantumState, figsize: tuple = (10, 8))[source]
Plot density matrix representation
- Parameters:
state – Quantum state
figsize – Figure size
- static plot_probabilities(state: QuantumState, figsize: tuple = (10, 6))[source]
Plot measurement probabilities
- Parameters:
state – Quantum state
figsize – Figure size
- static plot_qubit_probabilities(state: QuantumState, figsize: tuple = (10, 6))[source]
Plot per-qubit measurement probabilities
- Parameters:
state – Quantum state
figsize – Figure size
- class quantum_debugger.ThermalRelaxation(t1: float, t2: float, gate_time: float)[source]
Bases:
NoiseModelThermal relaxation: Combined T1 and T2 effects
Models realistic decoherence with both amplitude and phase damping. Based on T1 (energy relaxation) and T2 (phase coherence) times.
- quantum_debugger.adaptive_fold(circuit, scale_factor: float, gate_error_rates: Dict[str, float] | None = None)[source]
Adaptive folding: fold gates proportional to their error rates.
Gates with higher error rates are folded more aggressively.
- Parameters:
circuit – QuantumCircuit to fold
scale_factor – Target noise scaling
gate_error_rates – Dict mapping gate names to error rates If None, uses default hardware error rates
- Returns:
Adaptively folded circuit
Example
>>> error_rates = {'cnot': 0.01, 'h': 0.0003, 'rx': 0.0005} >>> folded = adaptive_fold(circuit, 2.0, error_rates)
- quantum_debugger.global_fold(circuit, scale_factor: float)[source]
Global circuit folding: C → C + C† + C
Amplifies noise by factor approximately equal to scale_factor.
- Parameters:
circuit – QuantumCircuit to fold
scale_factor – Target noise scaling (>= 1.0) scale=1.0: original circuit scale=3.0: C + C† + C (2 folds) scale=5.0: C + (C† + C) * 2
- Returns:
Folded circuit with amplified noise
Example
>>> circuit = QuantumCircuit(2) >>> circuit.h(0).cnot(0, 1) >>> folded = global_fold(circuit, scale_factor=3.0) >>> # folded has 3x the gates and ~3x the noise
- quantum_debugger.local_fold(circuit, scale_factor: float, gate_indices: List[int] | None = None)[source]
Local circuit folding: fold only specific gates.
Better for targeted error mitigation of high-error gates (e.g., CNOT).
- Parameters:
circuit – QuantumCircuit to fold
scale_factor – Target noise scaling
gate_indices – Indices of gates to fold. If None, fold two-qubit gates
- Returns:
Locally folded circuit
Example
>>> circuit = create_vqe_circuit() >>> # Fold only CNOT gates (highest error rate) >>> folded = local_fold(circuit, scale_factor=2.0)
- quantum_debugger.zero_noise_extrapolation(circuit, scale_factors: List[float] | None = None, extrapolation_method: str = 'richardson', folding_method: str = 'global', shots: int = 1000, **kwargs) Dict[source]
Zero-Noise Extrapolation: run circuit at multiple noise levels and extrapolate to zero.
- Parameters:
circuit – QuantumCircuit to mitigate
scale_factors – Noise scaling factors (e.g., [1.0, 2.0, 3.0]) Default: [1.0, 1.5, 2.0, 2.5, 3.0]
extrapolation_method – ‘richardson’, ‘linear’, ‘exponential’, ‘adaptive’
folding_method – ‘global’, ‘local’, or ‘adaptive’
shots – Number of measurement shots per noise level
**kwargs – Additional arguments for folding/extrapolation
- Returns:
mitigated_value: Extrapolated zero-noise expectation
unmitigated_value: Original noisy result
improvement_factor: Ratio of improvement
noise_levels: Scale factors used
expectation_values: Measured at each scale
method: Extrapolation method used
fidelity_unmitigated: Original fidelity (if available)
fidelity_mitigated: Estimated mitigated fidelity
- Return type:
Dictionary with
Example
>>> from quantum_debugger import QuantumCircuit >>> from quantum_debugger.noise import IBM_PERTH_2025 >>> from quantum_debugger.mitigation import zero_noise_extrapolation >>> >>> circuit = QuantumCircuit(2, noise_model=IBM_PERTH_2025.noise_model) >>> circuit.h(0).cnot(0, 1) >>> >>> result = zero_noise_extrapolation(circuit, shots=1000) >>> print(f"Mitigated fidelity: {result['fidelity_mitigated']:.4f}") >>> print(f"Improvement: {result['improvement_factor']:.2f}x")
Submodules
Core quantum computing components
- class quantum_debugger.core.GateLibrary[source]
Bases:
objectLibrary of standard quantum gates
- CNOT = array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j], [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j]])
- CZ = array([[ 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [ 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [ 0.+0.j, 0.+0.j, 0.+0.j, -1.+0.j]])
- H = array([[ 0.70710678+0.j, 0.70710678+0.j], [ 0.70710678+0.j, -0.70710678+0.j]])
- S = array([[1.+0.j, 0.+0.j], [0.+0.j, 0.+1.j]])
- SWAP = array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]])
- T = array([[1. +0.j , 0. +0.j ], [0. +0.j , 0.70710678+0.70710678j]])
- TOFFOLI = array([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j], [0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])
- X = array([[0.+0.j, 1.+0.j], [1.+0.j, 0.+0.j]])
- Y = array([[ 0.+0.j, -0.-1.j], [ 0.+1.j, 0.+0.j]])
- Z = array([[ 1.+0.j, 0.+0.j], [ 0.+0.j, -1.+0.j]])
- class quantum_debugger.core.QuantumCircuit(num_qubits: int, num_classical: int = 0, noise_model: Any | None = None, noise_simulation_method: str = 'density_matrix', backend: str = 'auto')[source]
Bases:
objectQuantum circuit with gate operations
- count_gates(gate_name: str = None) int[source]
Count gates of specific type
- Parameters:
gate_name – Name of gate to count (None for all gates)
- draw(output: str = 'text') str[source]
Draw the circuit
- Parameters:
output – Output format (‘text’ for ASCII art)
- Returns:
String representation of circuit
- get_statevector(initial_state: QuantumState | None = None, use_gpu: bool = False, precision: str = 'double') QuantumState[source]
Get final state vector without measurements.
- Parameters:
initial_state – Optional initial state
use_gpu – Run the whole circuit on the GPU (CuPy). The state lives on the GPU for every gate and is transferred back to the CPU once at the end. Falls back to CPU if CuPy is unavailable.
precision – ‘double’ (complex128, default, exact) or ‘single’ (complex64 – much faster on consumer GPUs, at reduced precision).
- Returns:
Final quantum state (always CPU/NumPy-backed)
- measure(qubit: int, classical_bit: int = None)[source]
Measure a qubit
- Parameters:
qubit – Qubit index to measure
classical_bit – Classical bit to store result (defaults to same as qubit)
- measure_all()[source]
Measure all qubits
- run(shots: int = 1, initial_state: QuantumState | None = None, use_gpu: bool = False, precision: str = 'double') dict[source]
Execute the circuit.
The statevector is computed once and all shots are sampled from the resulting distribution. This is equivalent, for independent projective Z-measurements, to collapsing the state per shot, but costs O(gates + shots) instead of the previous O(shots x gates) (which re-simulated the whole circuit for every shot).
- Parameters:
shots – Number of measurement samples
initial_state – Optional initial state (defaults to
|0...0>)use_gpu – Simulate the circuit on the GPU (see get_statevector)
precision – ‘double’ (complex128) or ‘single’ (complex64) for the GPU path
- Returns:
Dictionary with measurement results and statistics
- class quantum_debugger.core.QuantumState(num_qubits: int, state_vector: ndarray | None = None, backend='auto')[source]
Bases:
objectRepresents a quantum state vector
- apply_gate(gate_matrix: ndarray, target_qubits: List[int])[source]
Apply a quantum gate to specific qubits.
Uses tensor contraction, applying the k-qubit gate directly to the relevant axes of the state tensor. This is O(2**n) per gate instead of the O(4**n) cost of materializing the full 2**n x 2**n operator, so it is dramatically faster and more memory efficient for multi-qubit circuits.
- Parameters:
gate_matrix – Unitary matrix of the gate (2**k x 2**k for k qubits)
target_qubits – List of qubit indices to apply gate to. Gate qubit j acts on
target_qubits[j](matches the previous convention).
- bloch_vector(qubit: int = 0) Tuple[float, float, float][source]
Get Bloch sphere coordinates for a single qubit
- Parameters:
qubit – Index of qubit (for multi-qubit systems, traces out other qubits)
- Returns:
(x, y, z) coordinates on Bloch sphere
- copy()[source]
Create a deep copy of this state
- fidelity(other: QuantumState) float[source]
Calculate fidelity with another quantum state
- Parameters:
other – Another quantum state
- Returns:
Fidelity value between 0 and 1
- get_measurement_probability(qubit: int, outcome: int) float[source]
Get probability of measuring a specific outcome for a qubit
- is_entangled() bool[source]
Check if state is entangled (simple check for 2-qubit systems)
For 2 qubits: state is entangled if it cannot be written as tensor product
Debugger module for step-through quantum circuit execution
- class quantum_debugger.debugger.BreakpointManager[source]
Bases:
objectManages breakpoints for debugging
- add(gate_index: int | None = None, condition: Callable[[QuantumState], bool] | None = None, description: str = '') Breakpoint[source]
Add a breakpoint
- Parameters:
gate_index – Gate index to break at
condition – Condition function
description – Breakpoint description
- Returns:
Created breakpoint
- check(gate_index: int, state: QuantumState) Breakpoint | None[source]
Check if any breakpoint should trigger
- Parameters:
gate_index – Current gate index
state – Current quantum state
- Returns:
Triggered breakpoint or None
- clear()[source]
Remove all breakpoints
- disable_all()[source]
Disable all breakpoints
- enable_all()[source]
Enable all breakpoints
- remove(breakpoint: Breakpoint)[source]
Remove a breakpoint
- class quantum_debugger.debugger.QuantumDebugger(circuit: QuantumCircuit, initial_state: QuantumState | None = None)[source]
Bases:
objectInteractive debugger for quantum circuits
- clear_breakpoints()[source]
Remove all breakpoints
- compare_with_expected(expected_state: QuantumState) Dict[source]
Compare current state with expected state
- Parameters:
expected_state – Expected quantum state
- Returns:
Comparison metrics
- continue_execution()[source]
Continue execution until end (alias for run_to_end)
- get_current_state()[source]
Get current quantum state (alias for get_state)
- get_execution_trace() List[Dict][source]
Get full execution trace
- Returns:
List of execution states with information
- get_state() QuantumState[source]
Get current quantum state
- inspect_state() Dict[source]
Get detailed information about current state
- Returns:
Dictionary with state information
- print_status()[source]
Print current debugging status
- reset()[source]
Reset debugger to initial state
- run_to_end()[source]
Execute all remaining gates
- run_until_breakpoint()[source]
Execute until a breakpoint is hit or circuit ends
- set_breakpoint(gate: int | None = None, condition=None, description: str = '') Breakpoint[source]
Set a breakpoint
- Parameters:
gate – Gate index to break at
condition – Conditional function
description – Breakpoint description
- Returns:
Created breakpoint
- step(steps: int = 1) bool[source]
Execute one or more gates
- Parameters:
steps – Number of gates to execute
- Returns:
True if stepped successfully, False if at end
- step_back(steps: int = 1) bool[source]
Step backwards in execution history
- Parameters:
steps – Number of steps to go back
- Returns:
True if stepped back successfully
- visualize()[source]
Print visualization of current state
- class quantum_debugger.debugger.StateInspector[source]
Bases:
objectUtilities for inspecting quantum states during debugging
- static check_superposition(state: QuantumState, qubit: int, threshold: float = 0.1) bool[source]
Check if a qubit is in superposition
- Parameters:
state – Quantum state
qubit – Qubit index
threshold – Threshold for considering a state in superposition
- Returns:
True if qubit is in superposition
- static compare_states(state1: QuantumState, state2: QuantumState) Dict[source]
Compare two quantum states
- Parameters:
state1 – First quantum state
state2 – Second quantum state
- Returns:
Dictionary with comparison metrics
- static format_state_string(state: QuantumState, max_terms: int = 10) str[source]
Format quantum state as readable string
- Parameters:
state – Quantum state
max_terms – Maximum number of terms to show
- Returns:
Formatted string representation
- static get_amplitude_info(state: QuantumState) List[Dict][source]
Get detailed amplitude information for all basis states
- Parameters:
state – Quantum state
- Returns:
List of dictionaries with amplitude information
- static get_measurement_stats(state: QuantumState) Dict[str, float][source]
Get measurement statistics for all computational basis states
- Parameters:
state – Quantum state
- Returns:
Dictionary mapping basis states to probabilities
- static get_qubit_probabilities(state: QuantumState, qubit: int) Tuple[float, float][source]
Get measurement probabilities for a specific qubit
- Parameters:
state – Quantum state
qubit – Qubit index
- Returns:
(probability of 0, probability of 1)
- static get_state_summary(state: QuantumState) Dict[source]
Get a comprehensive summary of a quantum state
- Parameters:
state – Quantum state to inspect
- Returns:
Dictionary with state information
- static print_state_info(state: QuantumState)[source]
Print comprehensive state information to console
- Parameters:
state – Quantum state to inspect
Profiler module for quantum circuit analysis
- class quantum_debugger.profiler.CircuitMetrics(circuit: QuantumCircuit)[source]
Bases:
objectContainer for circuit analysis metrics
- estimate_error_rate(single_error: float = 0.001, cnot_error: float = 0.01) float[source]
Estimate cumulative error rate
- Parameters:
single_error – Error rate for single-qubit gates
cnot_error – Error rate for CNOT gates
- Returns:
Estimated cumulative error rate
- class quantum_debugger.profiler.CircuitProfiler(circuit: QuantumCircuit)[source]
Bases:
objectProfiler for analyzing quantum circuit performance
- analyze() CircuitMetrics[source]
Analyze the circuit and return metrics
- Returns:
CircuitMetrics object with analysis results
- compare_with_ideal() Dict[source]
Compare circuit with theoretical ideal
- Returns:
Comparison metrics
- get_optimization_suggestions() List[str][source]
Get suggestions for circuit optimization
- Returns:
List of optimization suggestions
- print_report()[source]
Print comprehensive profiling report
Visualization module for quantum states and circuits
- class quantum_debugger.visualization.BlochSphere[source]
Bases:
objectBloch sphere visualization for single qubits
- class quantum_debugger.visualization.StateVisualizer[source]
Bases:
objectVisualize quantum states
- static plot_density_matrix(state: QuantumState, figsize: tuple = (10, 8))[source]
Plot density matrix representation
- Parameters:
state – Quantum state
figsize – Figure size
- static plot_probabilities(state: QuantumState, figsize: tuple = (10, 6))[source]
Plot measurement probabilities
- Parameters:
state – Quantum state
figsize – Figure size
- static plot_qubit_probabilities(state: QuantumState, figsize: tuple = (10, 6))[source]
Plot per-qubit measurement probabilities
- Parameters:
state – Quantum state
figsize – Figure size
Framework Integrations
Universal compatibility layer for quantum frameworks: - Qiskit (IBM) - PennyLane (Xanadu) - Cirq (Google)
All integrations are optional - quantum-debugger works standalone.
- class quantum_debugger.integrations.CirqAdapter[source]
Bases:
objectAdapter for converting between Cirq and QuantumDebugger circuits
- GATE_MAP = {'CCX': 'toffoli', 'CNOT': 'cnot', 'CX': 'cnot', 'CZ': 'cz', 'H': 'h', 'Rx': 'rx', 'Ry': 'ry', 'Rz': 'rz', 'S': 's', 'SWAP': 'swap', 'T': 't', 'TOFFOLI': 'toffoli', 'X': 'x', 'Y': 'y', 'Z': 'z'}
- static check_cirq_available()[source]
Check if Cirq is installed
- classmethod compare_circuits(cirq_circuit: cirq.Circuit, qd_circuit: QuantumCircuit) dict[source]
Compare a Cirq circuit with a QuantumDebugger circuit
- Returns:
Dictionary with comparison results
- classmethod from_cirq(cirq_circuit: cirq.Circuit) QuantumCircuit[source]
Convert a Cirq Circuit to QuantumDebugger circuit
- Parameters:
cirq_circuit – Cirq Circuit to convert
- Returns:
QuantumDebugger QuantumCircuit
Example
>>> import cirq >>> q0, q1 = cirq.LineQubit.range(2) >>> cirq_circuit = cirq.Circuit() >>> cirq_circuit.append([cirq.H(q0), cirq.CNOT(q0, q1)]) >>> qd_circuit = CirqAdapter.from_cirq(cirq_circuit)
- classmethod simulate_cirq(qd_circuit: QuantumCircuit) dict[source]
Simulate a QuantumDebugger circuit using Cirq’s simulator
- Parameters:
qd_circuit – QuantumDebugger circuit to simulate
- Returns:
Dictionary with simulation results
- classmethod to_cirq(qd_circuit: QuantumCircuit, qubits: List[cirq.Qubit] | None = None) cirq.Circuit[source]
Convert a QuantumDebugger circuit to Cirq Circuit
- Parameters:
qd_circuit – QuantumDebugger circuit to convert
qubits – Optional list of Cirq qubits to use. If None, LineQubits are created.
- Returns:
Cirq Circuit
Example
>>> from quantum_debugger import QuantumCircuit >>> qd_circuit = QuantumCircuit(2) >>> qd_circuit.h(0) >>> qd_circuit.cnot(0, 1) >>> cirq_circuit = CirqAdapter.to_cirq(qd_circuit)
- class quantum_debugger.integrations.QiskitAdapter[source]
Bases:
objectAdapter for converting between Qiskit and QuantumDebugger circuits
- GATE_MAP = {'ccx': 'toffoli', 'cp': 'cp', 'cx': 'cnot', 'cz': 'cz', 'h': 'h', 'p': 'phase', 'rx': 'rx', 'ry': 'ry', 'rz': 'rz', 's': 's', 'swap': 'swap', 't': 't', 'x': 'x', 'y': 'y', 'z': 'z'}
- static check_qiskit_available()[source]
Check if Qiskit is installed
- classmethod compare_circuits(qiskit_circuit: None, qd_circuit: QuantumCircuit) dict[source]
Compare a Qiskit circuit with a QuantumDebugger circuit
- Returns:
Dictionary with comparison results
- classmethod from_qiskit(qiskit_circuit: None) QuantumCircuit[source]
Convert a Qiskit QuantumCircuit to QuantumDebugger circuit
- Parameters:
qiskit_circuit – Qiskit QuantumCircuit to convert
- Returns:
QuantumDebugger QuantumCircuit
Example
>>> from qiskit import QuantumCircuit >>> qc_qiskit = QuantumCircuit(2) >>> qc_qiskit.h(0) >>> qc_qiskit.cx(0, 1) >>> qc_qd = QiskitAdapter.from_qiskit(qc_qiskit)
- classmethod to_qiskit(qd_circuit: QuantumCircuit) None[source]
Convert a QuantumDebugger circuit to Qiskit QuantumCircuit
- Parameters:
qd_circuit – QuantumDebugger circuit to convert
- Returns:
Qiskit QuantumCircuit
Example
>>> from quantum_debugger import QuantumCircuit >>> qc_qd = QuantumCircuit(2) >>> qc_qd.h(0) >>> qc_qd.cnot(0, 1) >>> qc_qiskit = QiskitAdapter.to_qiskit(qc_qd)
- quantum_debugger.integrations.from_cirq(cirq_circuit) List[Tuple][source]
Convert Cirq circuit to quantum-debugger format.
- Parameters:
cirq_circuit – Cirq Circuit
- Returns:
List of gate tuples
Examples
>>> import cirq >>> qubits = cirq.LineQubit.range(2) >>> circuit = cirq.Circuit() >>> circuit.append(cirq.H(qubits[0])) >>> circuit.append(cirq.CNOT(qubits[0], qubits[1])) >>> gates = from_cirq(circuit)
- quantum_debugger.integrations.from_pennylane(pennylane_tape) List[Tuple][source]
Convert PennyLane tape/circuit to quantum-debugger format.
- Parameters:
pennylane_tape – PennyLane QuantumTape or operations list
- Returns:
List of gate tuples
Examples
>>> import pennylane as qml >>> dev = qml.device('default.qubit', wires=2) >>> @qml.qnode(dev) >>> def circuit(): ... qml.Hadamard(wires=0) ... qml.CNOT(wires=[0, 1]) ... return qml.expval(qml.PauliZ(0)) >>> gates = from_pennylane(circuit.tape)
- quantum_debugger.integrations.from_qiskit(qiskit_circuit) List[Tuple][source]
Convert Qiskit circuit to quantum-debugger format.
- Parameters:
qiskit_circuit – Qiskit QuantumCircuit
- Returns:
List of gate tuples in quantum-debugger format
Examples
>>> from qiskit import QuantumCircuit >>> qc = QuantumCircuit(2) >>> qc.h(0) >>> qc.cx(0, 1) >>> gates = from_qiskit(qc) >>> print(gates) # [('h', 0), ('cnot', (0, 1))]
- quantum_debugger.integrations.to_cirq(gates: List[Tuple]) cirq.Circuit[source]
Convert quantum-debugger format to Cirq circuit.
- Parameters:
gates – List of gate tuples
- Returns:
Cirq Circuit
Examples
>>> gates = [('h', 0), ('cnot', (0, 1))] >>> circuit = to_cirq(gates) >>> print(circuit)
- quantum_debugger.integrations.to_pennylane(gates: List[Tuple], device_name: str = 'default.qubit') qml.QNode[source]
Convert quantum-debugger format to PennyLane QNode.
- Parameters:
gates – List of gate tuples
device_name – PennyLane device name
- Returns:
PennyLane QNode function
Examples
>>> gates = [('h', 0), ('cnot', (0, 1))] >>> qnode = to_pennylane(gates) >>> result = qnode()
- quantum_debugger.integrations.to_qiskit(gates: List[Tuple], n_qubits: int | None = None) QuantumCircuit[source]
Convert quantum-debugger format to Qiskit circuit.
- Parameters:
gates – List of gate tuples
n_qubits – Number of qubits (auto-detected if None)
- Returns:
Qiskit QuantumCircuit
Examples
>>> gates = [('h', 0), ('cnot', (0, 1))] >>> qc = to_qiskit(gates) >>> print(qc)