Skip to content

Circuits API Reference

SuperQuantX provides comprehensive quantum circuit construction, manipulation, and execution capabilities. This API reference covers quantum circuits, gates, measurements, and noise modeling.

Quantum Circuits

Quantum Circuit

superquantx.circuits.QuantumCircuit

QuantumCircuit(num_qubits: int, num_classical_bits: int | None = None, name: str | None = None)

Quantum circuit representation with gate operations and measurements

This class provides a high-level interface for building and manipulating quantum circuits compatible with multiple quantum computing frameworks.

Initialize a quantum circuit

Parameters:

Name Type Description Default
num_qubits int

Number of qubits in the circuit

required
num_classical_bits int | None

Number of classical bits (defaults to num_qubits)

None
name str | None

Optional circuit name

None
Source code in src/superquantx/circuits.py
def __init__(
    self,
    num_qubits: int,
    num_classical_bits: int | None = None,
    name: str | None = None
):
    """Initialize a quantum circuit

    Args:
        num_qubits: Number of qubits in the circuit
        num_classical_bits: Number of classical bits (defaults to num_qubits)
        name: Optional circuit name

    """
    self.num_qubits = num_qubits
    self.num_classical_bits = num_classical_bits or num_qubits
    self.name = name or f"circuit_{id(self)}"

    self.quantum_registers: list[QuantumRegister] = [
        QuantumRegister(name="q", size=num_qubits)
    ]
    self.classical_registers: list[ClassicalRegister] = [
        ClassicalRegister(name="c", size=self.num_classical_bits)
    ]

    self.gates: list[QuantumGate] = []
    self.measurements: list[tuple[int, int]] = []  # (qubit_index, classical_bit_index)
    self.barriers: list[list[int]] = []  # Barrier positions

Functions

copy

copy() -> QuantumCircuit

Create a deep copy of the circuit

Source code in src/superquantx/circuits.py
def copy(self) -> "QuantumCircuit":
    """Create a deep copy of the circuit"""
    return deepcopy(self)

add_register

add_register(register: QuantumRegister | ClassicalRegister) -> None

Add a quantum or classical register to the circuit

Source code in src/superquantx/circuits.py
def add_register(self, register: QuantumRegister | ClassicalRegister) -> None:
    """Add a quantum or classical register to the circuit"""
    if isinstance(register, QuantumRegister):
        self.quantum_registers.append(register)
        self.num_qubits += register.size
    elif isinstance(register, ClassicalRegister):
        self.classical_registers.append(register)
        self.num_classical_bits += register.size

h

h(qubit: int) -> QuantumCircuit

Apply Hadamard gate

Source code in src/superquantx/circuits.py
def h(self, qubit: int) -> "QuantumCircuit":
    """Apply Hadamard gate"""
    self.gates.append(QuantumGate(name="H", qubits=[qubit]))
    return self

x

x(qubit: int) -> QuantumCircuit

Apply Pauli-X gate

Source code in src/superquantx/circuits.py
def x(self, qubit: int) -> "QuantumCircuit":
    """Apply Pauli-X gate"""
    self.gates.append(QuantumGate(name="X", qubits=[qubit]))
    return self

y

y(qubit: int) -> QuantumCircuit

Apply Pauli-Y gate

Source code in src/superquantx/circuits.py
def y(self, qubit: int) -> "QuantumCircuit":
    """Apply Pauli-Y gate"""
    self.gates.append(QuantumGate(name="Y", qubits=[qubit]))
    return self

z

z(qubit: int) -> QuantumCircuit

Apply Pauli-Z gate

Source code in src/superquantx/circuits.py
def z(self, qubit: int) -> "QuantumCircuit":
    """Apply Pauli-Z gate"""
    self.gates.append(QuantumGate(name="Z", qubits=[qubit]))
    return self

s

s(qubit: int) -> QuantumCircuit

Apply S gate (phase gate)

Source code in src/superquantx/circuits.py
def s(self, qubit: int) -> "QuantumCircuit":
    """Apply S gate (phase gate)"""
    self.gates.append(QuantumGate(name="S", qubits=[qubit]))
    return self

sdg

sdg(qubit: int) -> QuantumCircuit

Apply S† gate (inverse phase gate)

Source code in src/superquantx/circuits.py
def sdg(self, qubit: int) -> "QuantumCircuit":
    """Apply S† gate (inverse phase gate)"""
    self.gates.append(QuantumGate(name="SDG", qubits=[qubit]))
    return self

t

t(qubit: int) -> QuantumCircuit

Apply T gate

Source code in src/superquantx/circuits.py
def t(self, qubit: int) -> "QuantumCircuit":
    """Apply T gate"""
    self.gates.append(QuantumGate(name="T", qubits=[qubit]))
    return self

tdg

tdg(qubit: int) -> QuantumCircuit

Apply T† gate

Source code in src/superquantx/circuits.py
def tdg(self, qubit: int) -> "QuantumCircuit":
    """Apply T† gate"""
    self.gates.append(QuantumGate(name="TDG", qubits=[qubit]))
    return self

rx

rx(theta: float, qubit: int) -> QuantumCircuit

Apply rotation around X-axis

Source code in src/superquantx/circuits.py
def rx(self, theta: float, qubit: int) -> "QuantumCircuit":
    """Apply rotation around X-axis"""
    self.gates.append(QuantumGate(name="RX", qubits=[qubit], parameters=[theta]))
    return self

ry

ry(theta: float, qubit: int) -> QuantumCircuit

Apply rotation around Y-axis

Source code in src/superquantx/circuits.py
def ry(self, theta: float, qubit: int) -> "QuantumCircuit":
    """Apply rotation around Y-axis"""
    self.gates.append(QuantumGate(name="RY", qubits=[qubit], parameters=[theta]))
    return self

rz

rz(theta: float, qubit: int) -> QuantumCircuit

Apply rotation around Z-axis

Source code in src/superquantx/circuits.py
def rz(self, theta: float, qubit: int) -> "QuantumCircuit":
    """Apply rotation around Z-axis"""
    self.gates.append(QuantumGate(name="RZ", qubits=[qubit], parameters=[theta]))
    return self

u

u(theta: float, phi: float, lam: float, qubit: int) -> QuantumCircuit

Apply general unitary gate U(θ,φ,λ)

Source code in src/superquantx/circuits.py
def u(self, theta: float, phi: float, lam: float, qubit: int) -> "QuantumCircuit":
    """Apply general unitary gate U(θ,φ,λ)"""
    self.gates.append(
        QuantumGate(name="U", qubits=[qubit], parameters=[theta, phi, lam])
    )
    return self

cx

cx(control: int, target: int) -> QuantumCircuit

Apply CNOT gate

Source code in src/superquantx/circuits.py
def cx(self, control: int, target: int) -> "QuantumCircuit":
    """Apply CNOT gate"""
    self.gates.append(QuantumGate(name="CNOT", qubits=[control, target]))
    return self

cnot

cnot(control: int, target: int) -> QuantumCircuit

Apply CNOT gate (alias for cx)

Source code in src/superquantx/circuits.py
def cnot(self, control: int, target: int) -> "QuantumCircuit":
    """Apply CNOT gate (alias for cx)"""
    return self.cx(control, target)

cy

cy(control: int, target: int) -> QuantumCircuit

Apply controlled-Y gate

Source code in src/superquantx/circuits.py
def cy(self, control: int, target: int) -> "QuantumCircuit":
    """Apply controlled-Y gate"""
    self.gates.append(QuantumGate(name="CY", qubits=[control, target]))
    return self

cz

cz(control: int, target: int) -> QuantumCircuit

Apply controlled-Z gate

Source code in src/superquantx/circuits.py
def cz(self, control: int, target: int) -> "QuantumCircuit":
    """Apply controlled-Z gate"""
    self.gates.append(QuantumGate(name="CZ", qubits=[control, target]))
    return self

swap

swap(qubit1: int, qubit2: int) -> QuantumCircuit

Apply SWAP gate

Source code in src/superquantx/circuits.py
def swap(self, qubit1: int, qubit2: int) -> "QuantumCircuit":
    """Apply SWAP gate"""
    self.gates.append(QuantumGate(name="SWAP", qubits=[qubit1, qubit2]))
    return self

crx

crx(theta: float, control: int, target: int) -> QuantumCircuit

Apply controlled rotation around X-axis

Source code in src/superquantx/circuits.py
def crx(self, theta: float, control: int, target: int) -> "QuantumCircuit":
    """Apply controlled rotation around X-axis"""
    self.gates.append(
        QuantumGate(name="CRX", qubits=[control, target], parameters=[theta])
    )
    return self

cry

cry(theta: float, control: int, target: int) -> QuantumCircuit

Apply controlled rotation around Y-axis

Source code in src/superquantx/circuits.py
def cry(self, theta: float, control: int, target: int) -> "QuantumCircuit":
    """Apply controlled rotation around Y-axis"""
    self.gates.append(
        QuantumGate(name="CRY", qubits=[control, target], parameters=[theta])
    )
    return self

crz

crz(theta: float, control: int, target: int) -> QuantumCircuit

Apply controlled rotation around Z-axis

Source code in src/superquantx/circuits.py
def crz(self, theta: float, control: int, target: int) -> "QuantumCircuit":
    """Apply controlled rotation around Z-axis"""
    self.gates.append(
        QuantumGate(name="CRZ", qubits=[control, target], parameters=[theta])
    )
    return self

ccx

ccx(control1: int, control2: int, target: int) -> QuantumCircuit

Apply Toffoli (CCNOT) gate

Source code in src/superquantx/circuits.py
def ccx(self, control1: int, control2: int, target: int) -> "QuantumCircuit":
    """Apply Toffoli (CCNOT) gate"""
    self.gates.append(
        QuantumGate(name="TOFFOLI", qubits=[control1, control2, target])
    )
    return self

toffoli

toffoli(control1: int, control2: int, target: int) -> QuantumCircuit

Apply Toffoli gate (alias for ccx)

Source code in src/superquantx/circuits.py
def toffoli(self, control1: int, control2: int, target: int) -> "QuantumCircuit":
    """Apply Toffoli gate (alias for ccx)"""
    return self.ccx(control1, control2, target)

cswap

cswap(control: int, target1: int, target2: int) -> QuantumCircuit

Apply controlled SWAP (Fredkin) gate

Source code in src/superquantx/circuits.py
def cswap(self, control: int, target1: int, target2: int) -> "QuantumCircuit":
    """Apply controlled SWAP (Fredkin) gate"""
    self.gates.append(
        QuantumGate(name="FREDKIN", qubits=[control, target1, target2])
    )
    return self

fredkin

fredkin(control: int, target1: int, target2: int) -> QuantumCircuit

Apply Fredkin gate (alias for cswap)

Source code in src/superquantx/circuits.py
def fredkin(self, control: int, target1: int, target2: int) -> "QuantumCircuit":
    """Apply Fredkin gate (alias for cswap)"""
    return self.cswap(control, target1, target2)

measure

measure(qubit: int, classical_bit: int) -> QuantumCircuit

Measure a qubit into a classical bit

Source code in src/superquantx/circuits.py
def measure(self, qubit: int, classical_bit: int) -> "QuantumCircuit":
    """Measure a qubit into a classical bit"""
    self.measurements.append((qubit, classical_bit))
    return self

measure_all

measure_all() -> QuantumCircuit

Measure all qubits into classical bits

Source code in src/superquantx/circuits.py
def measure_all(self) -> "QuantumCircuit":
    """Measure all qubits into classical bits"""
    for i in range(min(self.num_qubits, self.num_classical_bits)):
        self.measure(i, i)
    return self

barrier

barrier(qubits: list[int] | None = None) -> QuantumCircuit

Add a barrier (prevents gate reordering across barrier)

Source code in src/superquantx/circuits.py
def barrier(self, qubits: list[int] | None = None) -> "QuantumCircuit":
    """Add a barrier (prevents gate reordering across barrier)"""
    if qubits is None:
        qubits = list(range(self.num_qubits))
    self.barriers.append(qubits)
    return self

compose

compose(other: QuantumCircuit, qubits: list[int] | None = None) -> QuantumCircuit

Compose this circuit with another circuit

Parameters:

Name Type Description Default
other QuantumCircuit

Circuit to compose with

required
qubits list[int] | None

Qubit mapping for the other circuit

None

Returns:

Type Description
QuantumCircuit

New composed circuit

Source code in src/superquantx/circuits.py
def compose(self, other: "QuantumCircuit", qubits: list[int] | None = None) -> "QuantumCircuit":
    """Compose this circuit with another circuit

    Args:
        other: Circuit to compose with
        qubits: Qubit mapping for the other circuit

    Returns:
        New composed circuit

    """
    if qubits is None:
        qubits = list(range(other.num_qubits))

    if len(qubits) != other.num_qubits:
        raise ValueError("Qubit mapping must match other circuit size")

    new_circuit = self.copy()

    # Map gates from other circuit
    for gate in other.gates:
        mapped_qubits = [qubits[q] for q in gate.qubits]
        new_gate = QuantumGate(
            name=gate.name,
            qubits=mapped_qubits,
            parameters=gate.parameters,
            classical_condition=gate.classical_condition
        )
        new_circuit.gates.append(new_gate)

    # Map measurements
    for qubit, cbit in other.measurements:
        new_circuit.measurements.append((qubits[qubit], cbit))

    return new_circuit

inverse

inverse() -> QuantumCircuit

Return the inverse (adjoint) of the circuit

Source code in src/superquantx/circuits.py
def inverse(self) -> "QuantumCircuit":
    """Return the inverse (adjoint) of the circuit"""
    inv_circuit = QuantumCircuit(self.num_qubits, self.num_classical_bits)

    # Reverse gates and apply inverse
    for gate in reversed(self.gates):
        inv_gate = self._inverse_gate(gate)
        inv_circuit.gates.append(inv_gate)

    return inv_circuit

to_dict

to_dict() -> dict[str, Any]

Convert circuit to dictionary representation

Source code in src/superquantx/circuits.py
def to_dict(self) -> dict[str, Any]:
    """Convert circuit to dictionary representation"""
    return {
        "name": self.name,
        "num_qubits": self.num_qubits,
        "num_classical_bits": self.num_classical_bits,
        "quantum_registers": [reg.dict() for reg in self.quantum_registers],
        "classical_registers": [reg.dict() for reg in self.classical_registers],
        "gates": [gate.to_dict() for gate in self.gates],
        "measurements": self.measurements,
        "barriers": self.barriers
    }

to_json

to_json(indent: int = 2) -> str

Convert circuit to JSON string

Source code in src/superquantx/circuits.py
def to_json(self, indent: int = 2) -> str:
    """Convert circuit to JSON string"""
    return json.dumps(self.to_dict(), indent=indent)

from_dict classmethod

from_dict(data: dict[str, Any]) -> QuantumCircuit

Create circuit from dictionary representation

Source code in src/superquantx/circuits.py
@classmethod
def from_dict(cls, data: dict[str, Any]) -> "QuantumCircuit":
    """Create circuit from dictionary representation"""
    circuit = cls(
        num_qubits=data["num_qubits"],
        num_classical_bits=data["num_classical_bits"],
        name=data.get("name")
    )

    circuit.quantum_registers = [
        QuantumRegister(**reg) for reg in data.get("quantum_registers", [])
    ]
    circuit.classical_registers = [
        ClassicalRegister(**reg) for reg in data.get("classical_registers", [])
    ]
    circuit.gates = [QuantumGate.from_dict(gate) for gate in data.get("gates", [])]
    circuit.measurements = data.get("measurements", [])
    circuit.barriers = data.get("barriers", [])

    return circuit

from_json classmethod

from_json(json_str: str) -> QuantumCircuit

Create circuit from JSON string

Source code in src/superquantx/circuits.py
@classmethod
def from_json(cls, json_str: str) -> "QuantumCircuit":
    """Create circuit from JSON string"""
    data = json.loads(json_str)
    return cls.from_dict(data)

draw

draw(output: str = 'text') -> str

Draw the circuit in text format

Parameters:

Name Type Description Default
output str

Output format ("text" only for now)

'text'

Returns:

Type Description
str

String representation of the circuit

Source code in src/superquantx/circuits.py
def draw(self, output: str = "text") -> str:
    """Draw the circuit in text format

    Args:
        output: Output format ("text" only for now)

    Returns:
        String representation of the circuit

    """
    if output != "text":
        raise NotImplementedError("Only text output is currently supported")

    lines = []
    for i in range(self.num_qubits):
        line = f"q{i} |0⟩─"
        lines.append(line)

    for gate in self.gates:
        max(gate.qubits)
        gate_repr = gate.name

        if len(gate.qubits) == 1:
            # Single-qubit gate
            qubit = gate.qubits[0]
            lines[qubit] += f"─{gate_repr}─"
            for i in range(self.num_qubits):
                if i != qubit:
                    lines[i] += "─" * (len(gate_repr) + 2)
        elif len(gate.qubits) == 2:
            # Two-qubit gate
            control, target = gate.qubits
            for i in range(self.num_qubits):
                if i == control:
                    lines[i] += "─●─"
                elif i == target:
                    lines[i] += "─⊕─"
                elif min(control, target) < i < max(control, target):
                    lines[i] += "─│─"
                else:
                    lines[i] += "───"

    # Add measurements
    for qubit, cbit in self.measurements:
        lines[qubit] += f"─M{cbit}"

    return "\n".join(lines)

Quantum Gate

superquantx.circuits.QuantumGate

Bases: BaseModel

Represents a quantum gate operation

Functions

to_dict

to_dict() -> dict[str, Any]

Convert gate to dictionary representation

Source code in src/superquantx/circuits.py
def to_dict(self) -> dict[str, Any]:
    """Convert gate to dictionary representation"""
    return {
        "name": self.name,
        "qubits": self.qubits,
        "parameters": self.parameters,
        "classical_condition": self.classical_condition
    }

from_dict classmethod

from_dict(data: dict[str, Any]) -> QuantumGate

Create gate from dictionary representation

Source code in src/superquantx/circuits.py
@classmethod
def from_dict(cls, data: dict[str, Any]) -> "QuantumGate":
    """Create gate from dictionary representation"""
    return cls(**data)

Classical Register

superquantx.circuits.ClassicalRegister

Bases: BaseModel

Represents a classical register for measurements

Quantum Gates

Gate Matrix Library

superquantx.gates.GateMatrix

Quantum gate matrix representations and operations

Functions

rx staticmethod

rx(theta: float) -> np.ndarray

Rotation around X-axis

Source code in src/superquantx/gates.py
@staticmethod
def rx(theta: float) -> np.ndarray:
    """Rotation around X-axis"""
    c = math.cos(theta / 2)
    s = math.sin(theta / 2)
    return np.array([[c, -1j * s], [-1j * s, c]], dtype=complex)

ry staticmethod

ry(theta: float) -> np.ndarray

Rotation around Y-axis

Source code in src/superquantx/gates.py
@staticmethod
def ry(theta: float) -> np.ndarray:
    """Rotation around Y-axis"""
    c = math.cos(theta / 2)
    s = math.sin(theta / 2)
    return np.array([[c, -s], [s, c]], dtype=complex)

rz staticmethod

rz(theta: float) -> np.ndarray

Rotation around Z-axis

Source code in src/superquantx/gates.py
@staticmethod
def rz(theta: float) -> np.ndarray:
    """Rotation around Z-axis"""
    return np.array([
        [np.exp(-1j * theta / 2), 0],
        [0, np.exp(1j * theta / 2)]
    ], dtype=complex)

u staticmethod

u(theta: float, phi: float, lam: float) -> np.ndarray

General single-qubit unitary gate U(θ,φ,λ)

Source code in src/superquantx/gates.py
@staticmethod
def u(theta: float, phi: float, lam: float) -> np.ndarray:
    """General single-qubit unitary gate U(θ,φ,λ)"""
    return np.array([
        [math.cos(theta / 2), -np.exp(1j * lam) * math.sin(theta / 2)],
        [np.exp(1j * phi) * math.sin(theta / 2),
         np.exp(1j * (phi + lam)) * math.cos(theta / 2)]
    ], dtype=complex)

phase staticmethod

phase(phi: float) -> np.ndarray

Phase gate

Source code in src/superquantx/gates.py
@staticmethod
def phase(phi: float) -> np.ndarray:
    """Phase gate"""
    return np.array([[1, 0], [0, np.exp(1j * phi)]], dtype=complex)

cnot staticmethod

cnot() -> np.ndarray

CNOT gate matrix

Source code in src/superquantx/gates.py
@staticmethod
def cnot() -> np.ndarray:
    """CNOT gate matrix"""
    return np.array([
        [1, 0, 0, 0],
        [0, 1, 0, 0],
        [0, 0, 0, 1],
        [0, 0, 1, 0]
    ], dtype=complex)

cz staticmethod

cz() -> np.ndarray

Controlled-Z gate matrix

Source code in src/superquantx/gates.py
@staticmethod
def cz() -> np.ndarray:
    """Controlled-Z gate matrix"""
    return np.array([
        [1, 0, 0, 0],
        [0, 1, 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, -1]
    ], dtype=complex)

swap staticmethod

swap() -> np.ndarray

SWAP gate matrix

Source code in src/superquantx/gates.py
@staticmethod
def swap() -> np.ndarray:
    """SWAP gate matrix"""
    return np.array([
        [1, 0, 0, 0],
        [0, 0, 1, 0],
        [0, 1, 0, 0],
        [0, 0, 0, 1]
    ], dtype=complex)

iswap staticmethod

iswap() -> np.ndarray

ISWAP gate matrix

Source code in src/superquantx/gates.py
@staticmethod
def iswap() -> np.ndarray:
    """ISWAP gate matrix"""
    return np.array([
        [1, 0, 0, 0],
        [0, 0, 1j, 0],
        [0, 1j, 0, 0],
        [0, 0, 0, 1]
    ], dtype=complex)

crx staticmethod

crx(theta: float) -> np.ndarray

Controlled rotation around X-axis

Source code in src/superquantx/gates.py
@staticmethod
def crx(theta: float) -> np.ndarray:
    """Controlled rotation around X-axis"""
    c = math.cos(theta / 2)
    s = math.sin(theta / 2)
    return np.array([
        [1, 0, 0, 0],
        [0, 1, 0, 0],
        [0, 0, c, -1j * s],
        [0, 0, -1j * s, c]
    ], dtype=complex)

cry staticmethod

cry(theta: float) -> np.ndarray

Controlled rotation around Y-axis

Source code in src/superquantx/gates.py
@staticmethod
def cry(theta: float) -> np.ndarray:
    """Controlled rotation around Y-axis"""
    c = math.cos(theta / 2)
    s = math.sin(theta / 2)
    return np.array([
        [1, 0, 0, 0],
        [0, 1, 0, 0],
        [0, 0, c, -s],
        [0, 0, s, c]
    ], dtype=complex)

crz staticmethod

crz(theta: float) -> np.ndarray

Controlled rotation around Z-axis

Source code in src/superquantx/gates.py
@staticmethod
def crz(theta: float) -> np.ndarray:
    """Controlled rotation around Z-axis"""
    return np.array([
        [1, 0, 0, 0],
        [0, 1, 0, 0],
        [0, 0, np.exp(-1j * theta / 2), 0],
        [0, 0, 0, np.exp(1j * theta / 2)]
    ], dtype=complex)

xx staticmethod

xx(theta: float) -> np.ndarray

XX interaction gate

Source code in src/superquantx/gates.py
@staticmethod
def xx(theta: float) -> np.ndarray:
    """XX interaction gate"""
    c = math.cos(theta / 2)
    s = math.sin(theta / 2)
    return np.array([
        [c, 0, 0, -1j * s],
        [0, c, -1j * s, 0],
        [0, -1j * s, c, 0],
        [-1j * s, 0, 0, c]
    ], dtype=complex)

yy staticmethod

yy(theta: float) -> np.ndarray

YY interaction gate

Source code in src/superquantx/gates.py
@staticmethod
def yy(theta: float) -> np.ndarray:
    """YY interaction gate"""
    c = math.cos(theta / 2)
    s = math.sin(theta / 2)
    return np.array([
        [c, 0, 0, 1j * s],
        [0, c, -1j * s, 0],
        [0, -1j * s, c, 0],
        [1j * s, 0, 0, c]
    ], dtype=complex)

zz staticmethod

zz(theta: float) -> np.ndarray

ZZ interaction gate

Source code in src/superquantx/gates.py
@staticmethod
def zz(theta: float) -> np.ndarray:
    """ZZ interaction gate"""
    return np.array([
        [np.exp(-1j * theta / 2), 0, 0, 0],
        [0, np.exp(1j * theta / 2), 0, 0],
        [0, 0, np.exp(1j * theta / 2), 0],
        [0, 0, 0, np.exp(-1j * theta / 2)]
    ], dtype=complex)

toffoli staticmethod

toffoli() -> np.ndarray

Toffoli (CCNOT) gate matrix

Source code in src/superquantx/gates.py
@staticmethod
def toffoli() -> np.ndarray:
    """Toffoli (CCNOT) gate matrix"""
    matrix = np.eye(8, dtype=complex)
    matrix[6, 6] = 0
    matrix[7, 7] = 0
    matrix[6, 7] = 1
    matrix[7, 6] = 1
    return matrix

fredkin staticmethod

fredkin() -> np.ndarray

Fredkin (CSWAP) gate matrix

Source code in src/superquantx/gates.py
@staticmethod
def fredkin() -> np.ndarray:
    """Fredkin (CSWAP) gate matrix"""
    matrix = np.eye(8, dtype=complex)
    matrix[5, 5] = 0
    matrix[6, 6] = 0
    matrix[5, 6] = 1
    matrix[6, 5] = 1
    return matrix

Pauli String Operations

superquantx.gates.PauliString

PauliString(pauli_ops: str, coefficient: complex = 1.0)

Represents a Pauli string for Hamiltonian construction

Initialize Pauli string

Parameters:

Name Type Description Default
pauli_ops str

String of Pauli operators (e.g., "IXZY")

required
coefficient complex

Complex coefficient

1.0
Source code in src/superquantx/gates.py
def __init__(self, pauli_ops: str, coefficient: complex = 1.0):
    """Initialize Pauli string

    Args:
        pauli_ops: String of Pauli operators (e.g., "IXZY")
        coefficient: Complex coefficient

    """
    self.pauli_ops = pauli_ops.upper()
    self.coefficient = coefficient
    self.num_qubits = len(pauli_ops)

    # Validate Pauli string
    valid_ops = set("IXYZ")
    if not all(op in valid_ops for op in self.pauli_ops):
        raise ValueError("Pauli string must contain only I, X, Y, Z operators")

Functions

matrix

matrix() -> np.ndarray

Get the matrix representation of the Pauli string

Source code in src/superquantx/gates.py
def matrix(self) -> np.ndarray:
    """Get the matrix representation of the Pauli string"""
    matrices = {
        'I': GateMatrix.identity,
        'X': GateMatrix.X,
        'Y': GateMatrix.Y,
        'Z': GateMatrix.Z
    }

    result = np.array([[1]], dtype=complex)
    for op in self.pauli_ops:
        result = np.kron(result, matrices[op])

    return self.coefficient * result

commutes_with

commutes_with(other: PauliString) -> bool

Check if this Pauli string commutes with another

Source code in src/superquantx/gates.py
def commutes_with(self, other: "PauliString") -> bool:
    """Check if this Pauli string commutes with another"""
    if len(self.pauli_ops) != len(other.pauli_ops):
        return False

    anti_commuting_pairs = {('X', 'Y'), ('Y', 'X'), ('X', 'Z'), ('Z', 'X'), ('Y', 'Z'), ('Z', 'Y')}
    anti_commutations = 0

    for op1, op2 in zip(self.pauli_ops, other.pauli_ops, strict=False):
        if (op1, op2) in anti_commuting_pairs:
            anti_commutations += 1

    return anti_commutations % 2 == 0

Hamiltonian Operations

superquantx.gates.Hamiltonian

Hamiltonian(pauli_strings: list[PauliString])

Quantum Hamiltonian represented as sum of Pauli strings

Initialize Hamiltonian

Parameters:

Name Type Description Default
pauli_strings list[PauliString]

List of Pauli strings that sum to form the Hamiltonian

required
Source code in src/superquantx/gates.py
def __init__(self, pauli_strings: list[PauliString]):
    """Initialize Hamiltonian

    Args:
        pauli_strings: List of Pauli strings that sum to form the Hamiltonian

    """
    self.pauli_strings = pauli_strings
    if pauli_strings:
        self.num_qubits = pauli_strings[0].num_qubits
        # Validate all strings have same length
        if not all(p.num_qubits == self.num_qubits for p in pauli_strings):
            raise ValueError("All Pauli strings must have same length")
    else:
        self.num_qubits = 0

Functions

matrix

matrix() -> np.ndarray

Get matrix representation of the Hamiltonian

Source code in src/superquantx/gates.py
def matrix(self) -> np.ndarray:
    """Get matrix representation of the Hamiltonian"""
    if not self.pauli_strings:
        return np.zeros((1, 1), dtype=complex)

    dim = 2 ** self.num_qubits
    result = np.zeros((dim, dim), dtype=complex)

    for pauli_string in self.pauli_strings:
        result += pauli_string.matrix()

    return result

expectation_value

expectation_value(state: ndarray) -> complex

Calculate expectation value ⟨ψ|H|ψ⟩

Source code in src/superquantx/gates.py
def expectation_value(self, state: np.ndarray) -> complex:
    """Calculate expectation value ⟨ψ|H|ψ⟩"""
    H = self.matrix()
    return np.conj(state).T @ H @ state

ground_state_energy

ground_state_energy() -> float

Calculate ground state energy (lowest eigenvalue)

Source code in src/superquantx/gates.py
def ground_state_energy(self) -> float:
    """Calculate ground state energy (lowest eigenvalue)"""
    eigenvals = np.linalg.eigvals(self.matrix())
    return float(np.min(np.real(eigenvals)))

time_evolution

time_evolution(time: float) -> np.ndarray

Generate time evolution operator U(t) = exp(-iHt)

Source code in src/superquantx/gates.py
def time_evolution(self, time: float) -> np.ndarray:
    """Generate time evolution operator U(t) = exp(-iHt)"""
    H = self.matrix()
    return expm(-1j * H * time)

from_dict classmethod

from_dict(hamiltonian_dict: dict[str, complex]) -> Hamiltonian

Create Hamiltonian from dictionary

Parameters:

Name Type Description Default
hamiltonian_dict dict[str, complex]

Dictionary mapping Pauli strings to coefficients

required
Example

{"IXZI": 0.5, "YZII": -0.3, "ZXYX": 1.2j}

Source code in src/superquantx/gates.py
@classmethod
def from_dict(cls, hamiltonian_dict: dict[str, complex]) -> "Hamiltonian":
    """Create Hamiltonian from dictionary

    Args:
        hamiltonian_dict: Dictionary mapping Pauli strings to coefficients

    Example:
        {"IXZI": 0.5, "YZII": -0.3, "ZXYX": 1.2j}

    """
    pauli_strings = []
    for pauli_ops, coeff in hamiltonian_dict.items():
        pauli_strings.append(PauliString(pauli_ops, coeff))
    return cls(pauli_strings)

heisenberg_model staticmethod

heisenberg_model(num_qubits: int, Jx: float = 1.0, Jy: float = 1.0, Jz: float = 1.0, periodic: bool = False) -> Hamiltonian

Create Heisenberg model Hamiltonian

H = Σᵢ (Jₓ XᵢXᵢ₊₁ + Jᵧ YᵢYᵢ₊₁ + Jᵤ ZᵢZᵢ₊₁)

Source code in src/superquantx/gates.py
@staticmethod
def heisenberg_model(
    num_qubits: int,
    Jx: float = 1.0,
    Jy: float = 1.0,
    Jz: float = 1.0,
    periodic: bool = False
) -> "Hamiltonian":
    """Create Heisenberg model Hamiltonian

    H = Σᵢ (Jₓ XᵢXᵢ₊₁ + Jᵧ YᵢYᵢ₊₁ + Jᵤ ZᵢZᵢ₊₁)
    """
    pauli_strings = []

    max_i = num_qubits if periodic else num_qubits - 1

    for i in range(max_i):
        j = (i + 1) % num_qubits

        # XX term
        xx_ops = ['I'] * num_qubits
        xx_ops[i] = 'X'
        xx_ops[j] = 'X'
        pauli_strings.append(PauliString(''.join(xx_ops), Jx))

        # YY term
        yy_ops = ['I'] * num_qubits
        yy_ops[i] = 'Y'
        yy_ops[j] = 'Y'
        pauli_strings.append(PauliString(''.join(yy_ops), Jy))

        # ZZ term
        zz_ops = ['I'] * num_qubits
        zz_ops[i] = 'Z'
        zz_ops[j] = 'Z'
        pauli_strings.append(PauliString(''.join(zz_ops), Jz))

    return Hamiltonian(pauli_strings)

ising_model staticmethod

ising_model(num_qubits: int, J: float = 1.0, h: float = 0.0, periodic: bool = False) -> Hamiltonian

Create transverse field Ising model Hamiltonian

H = -J Σᵢ ZᵢZᵢ₊₁ - h Σᵢ Xᵢ

Source code in src/superquantx/gates.py
@staticmethod
def ising_model(
    num_qubits: int,
    J: float = 1.0,
    h: float = 0.0,
    periodic: bool = False
) -> "Hamiltonian":
    """Create transverse field Ising model Hamiltonian

    H = -J Σᵢ ZᵢZᵢ₊₁ - h Σᵢ Xᵢ
    """
    pauli_strings = []

    # ZZ interactions
    max_i = num_qubits if periodic else num_qubits - 1
    for i in range(max_i):
        j = (i + 1) % num_qubits
        zz_ops = ['I'] * num_qubits
        zz_ops[i] = 'Z'
        zz_ops[j] = 'Z'
        pauli_strings.append(PauliString(''.join(zz_ops), -J))

    # X fields
    for i in range(num_qubits):
        x_ops = ['I'] * num_qubits
        x_ops[i] = 'X'
        pauli_strings.append(PauliString(''.join(x_ops), -h))

    return Hamiltonian(pauli_strings)

Measurements

Measurement Result

superquantx.measurements.MeasurementResult

Bases: BaseModel

Represents the result of quantum measurements

Attributes

probabilities property

probabilities: dict[str, float]

Get measurement probabilities

most_frequent property

most_frequent: tuple[str, int]

Get most frequent measurement outcome

Functions

model_post_init

model_post_init(__context)

Validate measurement result

Source code in src/superquantx/measurements.py
def model_post_init(self, __context):
    """Validate measurement result"""
    if sum(self.counts.values()) != self.shots:
        raise ValueError("Sum of counts must equal total shots")

marginal_counts

marginal_counts(qubits: list[int]) -> dict[str, int]

Get marginal counts for specific qubits

Parameters:

Name Type Description Default
qubits list[int]

List of qubit indices to marginalize over

required

Returns:

Type Description
dict[str, int]

Marginal counts dictionary

Source code in src/superquantx/measurements.py
def marginal_counts(self, qubits: list[int]) -> dict[str, int]:
    """Get marginal counts for specific qubits

    Args:
        qubits: List of qubit indices to marginalize over

    Returns:
        Marginal counts dictionary

    """
    marginal = defaultdict(int)

    for outcome, count in self.counts.items():
        # Extract bits for specified qubits (reverse order due to endianness)
        marginal_outcome = ''.join(outcome[-(i+1)] for i in qubits)
        marginal[marginal_outcome] += count

    return dict(marginal)

expectation_value

expectation_value(observable: str) -> float

Calculate expectation value for Pauli observable

Parameters:

Name Type Description Default
observable str

Pauli string (e.g., "ZZI")

required

Returns:

Type Description
float

Expectation value

Source code in src/superquantx/measurements.py
def expectation_value(self, observable: str) -> float:
    """Calculate expectation value for Pauli observable

    Args:
        observable: Pauli string (e.g., "ZZI")

    Returns:
        Expectation value

    """
    if len(observable) == 0:
        return 1.0

    expectation = 0.0

    for outcome, count in self.counts.items():
        # Calculate parity for non-identity Pauli operators
        parity = 1
        for i, pauli_op in enumerate(observable):
            if pauli_op == 'Z' and i < len(outcome):
                bit = int(outcome[-(i+1)])  # Reverse order
                parity *= (-1) ** bit
            elif pauli_op in ['X', 'Y']:
                # X and Y measurements require basis rotation
                raise ValueError(f"Cannot compute expectation for {pauli_op} from Z-basis measurements")

        expectation += parity * count / self.shots

    return expectation

entropy

entropy() -> float

Calculate measurement entropy

Source code in src/superquantx/measurements.py
def entropy(self) -> float:
    """Calculate measurement entropy"""
    entropy = 0.0
    for prob in self.probabilities.values():
        if prob > 0:
            entropy -= prob * np.log2(prob)
    return entropy

plot_histogram

plot_histogram(title: str = 'Measurement Results', figsize: tuple[int, int] = (10, 6), max_outcomes: int = 20) -> plt.Figure

Plot measurement histogram

Parameters:

Name Type Description Default
title str

Plot title

'Measurement Results'
figsize tuple[int, int]

Figure size

(10, 6)
max_outcomes int

Maximum number of outcomes to show

20

Returns:

Type Description
Figure

Matplotlib figure

Source code in src/superquantx/measurements.py
def plot_histogram(
    self,
    title: str = "Measurement Results",
    figsize: tuple[int, int] = (10, 6),
    max_outcomes: int = 20
) -> plt.Figure:
    """Plot measurement histogram

    Args:
        title: Plot title
        figsize: Figure size
        max_outcomes: Maximum number of outcomes to show

    Returns:
        Matplotlib figure

    """
    fig, ax = plt.subplots(figsize=figsize)

    # Sort outcomes by count (descending)
    sorted_outcomes = sorted(self.counts.items(), key=lambda x: x[1], reverse=True)

    # Take top outcomes
    if len(sorted_outcomes) > max_outcomes:
        sorted_outcomes = sorted_outcomes[:max_outcomes]

    outcomes, counts = zip(*sorted_outcomes, strict=False) if sorted_outcomes else ([], [])

    ax.bar(range(len(outcomes)), counts)
    ax.set_xlabel('Measurement Outcome')
    ax.set_ylabel('Count')
    ax.set_title(title)
    ax.set_xticks(range(len(outcomes)))
    ax.set_xticklabels(outcomes, rotation=45, ha='right')

    plt.tight_layout()
    return fig

to_dict

to_dict() -> dict[str, Any]

Convert to dictionary

Source code in src/superquantx/measurements.py
def to_dict(self) -> dict[str, Any]:
    """Convert to dictionary"""
    return {
        "counts": self.counts,
        "shots": self.shots,
        "memory": self.memory,
        "metadata": self.metadata
    }

to_json

to_json(indent: int = 2) -> str

Convert to JSON string

Source code in src/superquantx/measurements.py
def to_json(self, indent: int = 2) -> str:
    """Convert to JSON string"""
    return json.dumps(self.to_dict(), indent=indent)

from_dict classmethod

from_dict(data: dict[str, Any]) -> MeasurementResult

Create from dictionary

Source code in src/superquantx/measurements.py
@classmethod
def from_dict(cls, data: dict[str, Any]) -> "MeasurementResult":
    """Create from dictionary"""
    return cls(**data)

from_json classmethod

from_json(json_str: str) -> MeasurementResult

Create from JSON string

Source code in src/superquantx/measurements.py
@classmethod
def from_json(cls, json_str: str) -> "MeasurementResult":
    """Create from JSON string"""
    data = json.loads(json_str)
    return cls.from_dict(data)

Quantum Measurement

superquantx.measurements.QuantumMeasurement

QuantumMeasurement(backend: str | None = 'simulator')

Quantum measurement operations and analysis

Initialize measurement system

Parameters:

Name Type Description Default
backend str | None

Quantum backend for measurements

'simulator'
Source code in src/superquantx/measurements.py
def __init__(self, backend: str | None = "simulator"):
    """Initialize measurement system

    Args:
        backend: Quantum backend for measurements

    """
    self.backend = backend
    self.measurement_history: list[MeasurementResult] = []

Functions

measure_circuit

measure_circuit(circuit: QuantumCircuit, shots: int = 1024, memory: bool = False) -> MeasurementResult

Measure quantum circuit

Parameters:

Name Type Description Default
circuit QuantumCircuit

Quantum circuit to measure

required
shots int

Number of measurement shots

1024
memory bool

Whether to store individual shot outcomes

False

Returns:

Type Description
MeasurementResult

Measurement result

Source code in src/superquantx/measurements.py
def measure_circuit(
    self,
    circuit: "QuantumCircuit",
    shots: int = 1024,
    memory: bool = False
) -> MeasurementResult:
    """Measure quantum circuit

    Args:
        circuit: Quantum circuit to measure
        shots: Number of measurement shots
        memory: Whether to store individual shot outcomes

    Returns:
        Measurement result

    """
    # This would interface with actual quantum hardware/simulator
    # For now, create simulated results


    # Simulate measurement outcomes
    if self.backend == "simulator":
        counts = self._simulate_measurements(circuit, shots)
    else:
        counts = self._execute_measurements(circuit, shots)

    # Generate memory if requested
    shot_memory = None
    if memory:
        shot_memory = []
        for outcome, count in counts.items():
            shot_memory.extend([outcome] * count)
        np.random.shuffle(shot_memory)  # Randomize order

    result = MeasurementResult(
        counts=counts,
        shots=shots,
        memory=shot_memory,
        metadata={"backend": self.backend, "circuit_name": circuit.name}
    )

    self.measurement_history.append(result)
    return result

measure_observable

measure_observable(circuit: QuantumCircuit, observable: str, shots: int = 1024) -> float

Measure expectation value of Pauli observable

Parameters:

Name Type Description Default
circuit QuantumCircuit

Quantum circuit (without measurements)

required
observable str

Pauli string observable

required
shots int

Number of shots

1024

Returns:

Type Description
float

Expectation value

Source code in src/superquantx/measurements.py
def measure_observable(
    self,
    circuit: "QuantumCircuit",
    observable: str,
    shots: int = 1024
) -> float:
    """Measure expectation value of Pauli observable

    Args:
        circuit: Quantum circuit (without measurements)
        observable: Pauli string observable
        shots: Number of shots

    Returns:
        Expectation value

    """
    # Create measurement circuit with basis rotations
    measurement_circuit = self._prepare_observable_measurement(circuit, observable)

    # Measure circuit
    result = self.measure_circuit(measurement_circuit, shots)

    # Calculate expectation value
    return result.expectation_value('Z' * len(observable))

tomography_measurements

tomography_measurements(circuit: QuantumCircuit, qubits: list[int] | None = None, shots_per_measurement: int = 1024) -> dict[str, MeasurementResult]

Perform quantum state tomography measurements

Parameters:

Name Type Description Default
circuit QuantumCircuit

Quantum circuit to tomographically reconstruct

required
qubits list[int] | None

Qubits to perform tomography on (default: all)

None
shots_per_measurement int

Shots per Pauli measurement

1024

Returns:

Type Description
dict[str, MeasurementResult]

Dictionary of measurement results for each Pauli basis

Source code in src/superquantx/measurements.py
def tomography_measurements(
    self,
    circuit: "QuantumCircuit",
    qubits: list[int] | None = None,
    shots_per_measurement: int = 1024
) -> dict[str, MeasurementResult]:
    """Perform quantum state tomography measurements

    Args:
        circuit: Quantum circuit to tomographically reconstruct
        qubits: Qubits to perform tomography on (default: all)
        shots_per_measurement: Shots per Pauli measurement

    Returns:
        Dictionary of measurement results for each Pauli basis

    """
    if qubits is None:
        qubits = list(range(circuit.num_qubits))

    num_qubits = len(qubits)
    pauli_bases = ['I', 'X', 'Y', 'Z']

    # Generate all Pauli measurement settings
    measurements = {}

    def generate_pauli_strings(n):
        if n == 0:
            yield ''
        else:
            for base in pauli_bases:
                for rest in generate_pauli_strings(n - 1):
                    yield base + rest

    for pauli_string in generate_pauli_strings(num_qubits):
        if 'I' in pauli_string:
            continue  # Skip identity measurements

        measurement_circuit = self._prepare_tomography_measurement(
            circuit, pauli_string, qubits
        )

        result = self.measure_circuit(measurement_circuit, shots_per_measurement)
        measurements[pauli_string] = result

    return measurements

reconstruct_state

reconstruct_state(tomography_results: dict[str, MeasurementResult]) -> np.ndarray

Reconstruct quantum state from tomography measurements

Parameters:

Name Type Description Default
tomography_results dict[str, MeasurementResult]

Results from tomography_measurements

required

Returns:

Type Description
ndarray

Reconstructed density matrix

Source code in src/superquantx/measurements.py
def reconstruct_state(
    self,
    tomography_results: dict[str, MeasurementResult]
) -> np.ndarray:
    """Reconstruct quantum state from tomography measurements

    Args:
        tomography_results: Results from tomography_measurements

    Returns:
        Reconstructed density matrix

    """
    # This is a simplified implementation
    # Full tomography would use maximum likelihood estimation

    num_qubits = len(next(iter(tomography_results.keys())))
    dim = 2 ** num_qubits

    # Initialize density matrix
    rho = np.eye(dim, dtype=complex) / dim

    # This is a placeholder implementation
    # Real tomography would involve solving a constrained optimization problem

    return rho

fidelity

fidelity(state1: ndarray, state2: ndarray) -> float

Calculate quantum state fidelity

Parameters:

Name Type Description Default
state1 ndarray

First quantum state (vector or density matrix)

required
state2 ndarray

Second quantum state (vector or density matrix)

required

Returns:

Type Description
float

Fidelity between states

Source code in src/superquantx/measurements.py
def fidelity(
    self,
    state1: np.ndarray,
    state2: np.ndarray
) -> float:
    """Calculate quantum state fidelity

    Args:
        state1: First quantum state (vector or density matrix)
        state2: Second quantum state (vector or density matrix)

    Returns:
        Fidelity between states

    """
    # Convert to density matrices if needed
    if state1.ndim == 1:
        rho1 = np.outer(state1, np.conj(state1))
    else:
        rho1 = state1

    if state2.ndim == 1:
        rho2 = np.outer(state2, np.conj(state2))
    else:
        rho2 = state2

    # Calculate fidelity using proper matrix square root
    eigenvals_rho1, eigenvecs_rho1 = np.linalg.eigh(rho1)
    eigenvals_rho1 = np.maximum(eigenvals_rho1, 0)  # Ensure non-negative
    sqrt_rho1 = eigenvecs_rho1 @ np.diag(np.sqrt(eigenvals_rho1)) @ eigenvecs_rho1.conj().T

    product = sqrt_rho1 @ rho2 @ sqrt_rho1
    eigenvals = np.linalg.eigvals(product)
    eigenvals = np.maximum(eigenvals.real, 0)  # Take real part and ensure non-negative

    return float(np.sum(np.sqrt(eigenvals)))

trace_distance

trace_distance(state1: ndarray, state2: ndarray) -> float

Calculate trace distance between quantum states

Parameters:

Name Type Description Default
state1 ndarray

First quantum state

required
state2 ndarray

Second quantum state

required

Returns:

Type Description
float

Trace distance

Source code in src/superquantx/measurements.py
def trace_distance(
    self,
    state1: np.ndarray,
    state2: np.ndarray
) -> float:
    """Calculate trace distance between quantum states

    Args:
        state1: First quantum state
        state2: Second quantum state

    Returns:
        Trace distance

    """
    # Convert to density matrices if needed
    if state1.ndim == 1:
        rho1 = np.outer(state1, np.conj(state1))
    else:
        rho1 = state1

    if state2.ndim == 1:
        rho2 = np.outer(state2, np.conj(state2))
    else:
        rho2 = state2

    diff = rho1 - rho2
    eigenvals = np.linalg.eigvals(diff)

    return 0.5 * np.sum(np.abs(eigenvals))

quantum_volume

quantum_volume(num_qubits: int, depth: int, trials: int = 100, shots_per_trial: int = 1024) -> dict[str, Any]

Perform quantum volume benchmark

Parameters:

Name Type Description Default
num_qubits int

Number of qubits

required
depth int

Circuit depth

required
trials int

Number of random circuits to test

100
shots_per_trial int

Shots per circuit

1024

Returns:

Type Description
dict[str, Any]

Quantum volume benchmark results

Source code in src/superquantx/measurements.py
def quantum_volume(
    self,
    num_qubits: int,
    depth: int,
    trials: int = 100,
    shots_per_trial: int = 1024
) -> dict[str, Any]:
    """Perform quantum volume benchmark

    Args:
        num_qubits: Number of qubits
        depth: Circuit depth
        trials: Number of random circuits to test
        shots_per_trial: Shots per circuit

    Returns:
        Quantum volume benchmark results

    """
    import random

    from .circuits import QuantumCircuit

    successes = 0

    for trial in range(trials):
        # Generate random quantum volume circuit
        circuit = QuantumCircuit(num_qubits)

        for layer in range(depth):
            # Random SU(4) gates on random qubit pairs
            available_qubits = list(range(num_qubits))
            random.shuffle(available_qubits)

            for i in range(0, num_qubits - 1, 2):
                q1, q2 = available_qubits[i], available_qubits[i + 1]

                # Random single-qubit gates
                circuit.u(
                    random.uniform(0, 2*np.pi),
                    random.uniform(0, 2*np.pi),
                    random.uniform(0, 2*np.pi),
                    q1
                )
                circuit.u(
                    random.uniform(0, 2*np.pi),
                    random.uniform(0, 2*np.pi),
                    random.uniform(0, 2*np.pi),
                    q2
                )

                # CNOT gate
                circuit.cnot(q1, q2)

        # Measure circuit
        circuit.measure_all()
        result = self.measure_circuit(circuit, shots_per_trial)

        # Check if heavy output (simplified check)
        # Real quantum volume would compute ideal probabilities
        most_frequent = result.most_frequent
        if most_frequent[1] > shots_per_trial // 4:  # Simplified threshold
            successes += 1

    success_rate = successes / trials

    return {
        "num_qubits": num_qubits,
        "depth": depth,
        "trials": trials,
        "successes": successes,
        "success_rate": success_rate,
        "passed": success_rate > 2/3,  # Standard QV threshold
        "quantum_volume": 2 ** num_qubits if success_rate > 2/3 else 0
    }

Result Analyzer

superquantx.measurements.ResultAnalyzer

Advanced analysis of quantum measurement results

Functions

compare_results staticmethod

compare_results(results1: MeasurementResult, results2: MeasurementResult) -> dict[str, float]

Compare two measurement results

Parameters:

Name Type Description Default
results1 MeasurementResult

First measurement result

required
results2 MeasurementResult

Second measurement result

required

Returns:

Type Description
dict[str, float]

Comparison metrics

Source code in src/superquantx/measurements.py
@staticmethod
def compare_results(
    results1: MeasurementResult,
    results2: MeasurementResult
) -> dict[str, float]:
    """Compare two measurement results

    Args:
        results1: First measurement result
        results2: Second measurement result

    Returns:
        Comparison metrics

    """
    # Hellinger distance between probability distributions
    prob1 = results1.probabilities
    prob2 = results2.probabilities

    all_outcomes = set(prob1.keys()) | set(prob2.keys())

    hellinger = 0.0
    kl_divergence = 0.0

    for outcome in all_outcomes:
        p1 = prob1.get(outcome, 0)
        p2 = prob2.get(outcome, 0)

        # Hellinger distance
        hellinger += (np.sqrt(p1) - np.sqrt(p2)) ** 2

        # KL divergence (with smoothing to avoid log(0))
        p1_smooth = p1 + 1e-10
        p2_smooth = p2 + 1e-10
        kl_divergence += p1_smooth * np.log(p1_smooth / p2_smooth)

    hellinger = np.sqrt(hellinger / 2)

    # Total variation distance
    tv_distance = 0.5 * sum(abs(prob1.get(outcome, 0) - prob2.get(outcome, 0))
                          for outcome in all_outcomes)

    return {
        "hellinger_distance": hellinger,
        "kl_divergence": kl_divergence,
        "total_variation_distance": tv_distance
    }

error_mitigation_zero_noise_extrapolation staticmethod

error_mitigation_zero_noise_extrapolation(noise_levels: list[float], measurement_results: list[MeasurementResult], observable: str = 'Z') -> tuple[float, dict[str, Any]]

Perform zero-noise extrapolation error mitigation

Parameters:

Name Type Description Default
noise_levels list[float]

List of noise levels (e.g., [1, 2, 3])

required
measurement_results list[MeasurementResult]

Results for each noise level

required
observable str

Observable to extrapolate

'Z'

Returns:

Type Description
tuple[float, dict[str, Any]]

Zero-noise extrapolated value and fitting info

Source code in src/superquantx/measurements.py
@staticmethod
def error_mitigation_zero_noise_extrapolation(
    noise_levels: list[float],
    measurement_results: list[MeasurementResult],
    observable: str = "Z"
) -> tuple[float, dict[str, Any]]:
    """Perform zero-noise extrapolation error mitigation

    Args:
        noise_levels: List of noise levels (e.g., [1, 2, 3])
        measurement_results: Results for each noise level
        observable: Observable to extrapolate

    Returns:
        Zero-noise extrapolated value and fitting info

    """
    if len(noise_levels) != len(measurement_results):
        raise ValueError("Noise levels and results must have same length")

    # Extract expectation values
    expectation_values = []
    for result in measurement_results:
        exp_val = result.expectation_value(observable)
        expectation_values.append(exp_val)

    # Fit exponential decay model: f(x) = a * exp(-b * x) + c
    from scipy.optimize import curve_fit

    def exponential_model(x, a, b, c):
        return a * np.exp(-b * x) + c

    try:
        popt, pcov = curve_fit(
            exponential_model,
            noise_levels,
            expectation_values,
            p0=[expectation_values[0], 0.1, 0]
        )

        # Extrapolate to zero noise
        zero_noise_value = exponential_model(0, *popt)

        # Calculate fit quality
        fitted_values = [exponential_model(x, *popt) for x in noise_levels]
        r_squared = 1 - np.sum((np.array(expectation_values) - fitted_values)**2) / \
                       np.sum((np.array(expectation_values) - np.mean(expectation_values))**2)

        return zero_noise_value, {
            "fit_parameters": popt,
            "fit_covariance": pcov,
            "r_squared": r_squared,
            "fitted_values": fitted_values,
            "raw_values": expectation_values
        }

    except Exception as e:
        # Fallback to linear extrapolation
        coeffs = np.polyfit(noise_levels, expectation_values, 1)
        zero_noise_value = coeffs[1]  # y-intercept

        return zero_noise_value, {
            "method": "linear_fallback",
            "coefficients": coeffs,
            "error": str(e)
        }

readout_error_mitigation staticmethod

readout_error_mitigation(calibration_results: dict[str, MeasurementResult], measurement_result: MeasurementResult) -> MeasurementResult

Apply readout error mitigation

Parameters:

Name Type Description Default
calibration_results dict[str, MeasurementResult]

Results from measuring |0⟩ and |1⟩ states

required
measurement_result MeasurementResult

Result to correct

required

Returns:

Type Description
MeasurementResult

Error-mitigated result

Source code in src/superquantx/measurements.py
@staticmethod
def readout_error_mitigation(
    calibration_results: dict[str, MeasurementResult],
    measurement_result: MeasurementResult
) -> MeasurementResult:
    """Apply readout error mitigation

    Args:
        calibration_results: Results from measuring |0⟩ and |1⟩ states
        measurement_result: Result to correct

    Returns:
        Error-mitigated result

    """
    # Build calibration matrix
    len(next(iter(calibration_results.keys())))

    # This is a simplified implementation
    # Full readout error mitigation would build complete confusion matrix

    corrected_counts = dict(measurement_result.counts)

    # Apply simple correction (placeholder)
    # Real implementation would invert the calibration matrix

    return MeasurementResult(
        counts=corrected_counts,
        shots=measurement_result.shots,
        memory=measurement_result.memory,
        metadata={**measurement_result.metadata, "error_mitigated": True}
    )

Noise Models

Noise Channel Base

superquantx.noise.NoiseChannel

NoiseChannel(probability: float)

Bases: ABC

Abstract base class for quantum noise channels

Initialize noise channel

Parameters:

Name Type Description Default
probability float

Noise probability (0 <= p <= 1)

required
Source code in src/superquantx/noise.py
def __init__(self, probability: float):
    """Initialize noise channel

    Args:
        probability: Noise probability (0 <= p <= 1)

    """
    if not 0 <= probability <= 1:
        raise ValueError("Probability must be between 0 and 1")
    self.probability = probability

Functions

kraus_operators abstractmethod

kraus_operators() -> list[np.ndarray]

Return Kraus operators for the noise channel

Source code in src/superquantx/noise.py
@abstractmethod
def kraus_operators(self) -> list[np.ndarray]:
    """Return Kraus operators for the noise channel"""
    pass

apply_to_density_matrix abstractmethod

apply_to_density_matrix(rho: ndarray) -> np.ndarray

Apply noise channel to density matrix

Source code in src/superquantx/noise.py
@abstractmethod
def apply_to_density_matrix(self, rho: np.ndarray) -> np.ndarray:
    """Apply noise channel to density matrix"""
    pass

is_unital

is_unital() -> bool

Check if channel is unital (maps identity to identity)

Source code in src/superquantx/noise.py
def is_unital(self) -> bool:
    """Check if channel is unital (maps identity to identity)"""
    identity = np.eye(2, dtype=complex)
    noisy_identity = self.apply_to_density_matrix(identity)
    return np.allclose(noisy_identity, identity)

Specific Noise Channels

superquantx.noise.BitFlipChannel

BitFlipChannel(probability: float)

Bases: NoiseChannel

Bit flip (X) noise channel

Source code in src/superquantx/noise.py
def __init__(self, probability: float):
    """Initialize noise channel

    Args:
        probability: Noise probability (0 <= p <= 1)

    """
    if not 0 <= probability <= 1:
        raise ValueError("Probability must be between 0 and 1")
    self.probability = probability

Functions

kraus_operators

kraus_operators() -> list[np.ndarray]

Kraus operators for bit flip channel

Source code in src/superquantx/noise.py
def kraus_operators(self) -> list[np.ndarray]:
    """Kraus operators for bit flip channel"""
    sqrt_p = np.sqrt(self.probability)
    sqrt_1_p = np.sqrt(1 - self.probability)

    return [
        sqrt_1_p * GateMatrix.I,  # No error
        sqrt_p * GateMatrix.X     # Bit flip
    ]

apply_to_density_matrix

apply_to_density_matrix(rho: ndarray) -> np.ndarray

Apply bit flip noise to density matrix

Source code in src/superquantx/noise.py
def apply_to_density_matrix(self, rho: np.ndarray) -> np.ndarray:
    """Apply bit flip noise to density matrix"""
    kraus_ops = self.kraus_operators()
    result = np.zeros_like(rho, dtype=complex)

    for kraus in kraus_ops:
        result += kraus @ rho @ kraus.conj().T

    return result

superquantx.noise.PhaseFlipChannel

PhaseFlipChannel(probability: float)

Bases: NoiseChannel

Phase flip (Z) noise channel

Source code in src/superquantx/noise.py
def __init__(self, probability: float):
    """Initialize noise channel

    Args:
        probability: Noise probability (0 <= p <= 1)

    """
    if not 0 <= probability <= 1:
        raise ValueError("Probability must be between 0 and 1")
    self.probability = probability

Functions

kraus_operators

kraus_operators() -> list[np.ndarray]

Kraus operators for phase flip channel

Source code in src/superquantx/noise.py
def kraus_operators(self) -> list[np.ndarray]:
    """Kraus operators for phase flip channel"""
    sqrt_p = np.sqrt(self.probability)
    sqrt_1_p = np.sqrt(1 - self.probability)

    return [
        sqrt_1_p * GateMatrix.I,  # No error
        sqrt_p * GateMatrix.Z     # Phase flip
    ]

apply_to_density_matrix

apply_to_density_matrix(rho: ndarray) -> np.ndarray

Apply phase flip noise to density matrix

Source code in src/superquantx/noise.py
def apply_to_density_matrix(self, rho: np.ndarray) -> np.ndarray:
    """Apply phase flip noise to density matrix"""
    kraus_ops = self.kraus_operators()
    result = np.zeros_like(rho, dtype=complex)

    for kraus in kraus_ops:
        result += kraus @ rho @ kraus.conj().T

    return result

superquantx.noise.DepolarizingChannel

DepolarizingChannel(probability: float)

Bases: NoiseChannel

Depolarizing noise channel

Source code in src/superquantx/noise.py
def __init__(self, probability: float):
    """Initialize noise channel

    Args:
        probability: Noise probability (0 <= p <= 1)

    """
    if not 0 <= probability <= 1:
        raise ValueError("Probability must be between 0 and 1")
    self.probability = probability

Functions

kraus_operators

kraus_operators() -> list[np.ndarray]

Kraus operators for depolarizing channel

Source code in src/superquantx/noise.py
def kraus_operators(self) -> list[np.ndarray]:
    """Kraus operators for depolarizing channel"""
    p = self.probability

    return [
        np.sqrt(1 - 3*p/4) * GateMatrix.I,  # No error
        np.sqrt(p/4) * GateMatrix.X,        # X error
        np.sqrt(p/4) * GateMatrix.Y,        # Y error
        np.sqrt(p/4) * GateMatrix.Z         # Z error
    ]

apply_to_density_matrix

apply_to_density_matrix(rho: ndarray) -> np.ndarray

Apply depolarizing noise to density matrix

Source code in src/superquantx/noise.py
def apply_to_density_matrix(self, rho: np.ndarray) -> np.ndarray:
    """Apply depolarizing noise to density matrix"""
    p = self.probability

    # Direct formula: ρ → (1-p)ρ + p*I/2
    identity = np.eye(rho.shape[0], dtype=complex)
    return (1 - p) * rho + (p / rho.shape[0]) * identity

superquantx.noise.AmplitudeDampingChannel

AmplitudeDampingChannel(probability: float)

Bases: NoiseChannel

Amplitude damping noise channel (T1 decay)

Source code in src/superquantx/noise.py
def __init__(self, probability: float):
    """Initialize noise channel

    Args:
        probability: Noise probability (0 <= p <= 1)

    """
    if not 0 <= probability <= 1:
        raise ValueError("Probability must be between 0 and 1")
    self.probability = probability

Functions

kraus_operators

kraus_operators() -> list[np.ndarray]

Kraus operators for amplitude damping channel

Source code in src/superquantx/noise.py
def kraus_operators(self) -> list[np.ndarray]:
    """Kraus operators for amplitude damping channel"""
    gamma = self.probability

    E0 = np.array([
        [1, 0],
        [0, np.sqrt(1 - gamma)]
    ], dtype=complex)

    E1 = np.array([
        [0, np.sqrt(gamma)],
        [0, 0]
    ], dtype=complex)

    return [E0, E1]

apply_to_density_matrix

apply_to_density_matrix(rho: ndarray) -> np.ndarray

Apply amplitude damping noise to density matrix

Source code in src/superquantx/noise.py
def apply_to_density_matrix(self, rho: np.ndarray) -> np.ndarray:
    """Apply amplitude damping noise to density matrix"""
    kraus_ops = self.kraus_operators()
    result = np.zeros_like(rho, dtype=complex)

    for kraus in kraus_ops:
        result += kraus @ rho @ kraus.conj().T

    return result

Noise Model

superquantx.noise.NoiseModel

Bases: BaseModel

Comprehensive noise model for quantum circuits

Functions

add_single_qubit_error

add_single_qubit_error(gate_name: str, error_rate: float) -> None

Add single-qubit gate error rate

Source code in src/superquantx/noise.py
def add_single_qubit_error(self, gate_name: str, error_rate: float) -> None:
    """Add single-qubit gate error rate"""
    self.single_qubit_error_rates[gate_name] = error_rate

add_two_qubit_error

add_two_qubit_error(gate_name: str, error_rate: float) -> None

Add two-qubit gate error rate

Source code in src/superquantx/noise.py
def add_two_qubit_error(self, gate_name: str, error_rate: float) -> None:
    """Add two-qubit gate error rate"""
    self.two_qubit_error_rates[gate_name] = error_rate

add_readout_error

add_readout_error(qubit: int, error_rate: float) -> None

Add readout error rate for qubit

Source code in src/superquantx/noise.py
def add_readout_error(self, qubit: int, error_rate: float) -> None:
    """Add readout error rate for qubit"""
    self.readout_error_rates[qubit] = error_rate

set_coherence_time

set_coherence_time(qubit: int, t1: float, t2: float) -> None

Set T1 and T2 coherence times for qubit

Source code in src/superquantx/noise.py
def set_coherence_time(self, qubit: int, t1: float, t2: float) -> None:
    """Set T1 and T2 coherence times for qubit"""
    if "T1" not in self.coherence_times:
        self.coherence_times["T1"] = {}
    if "T2" not in self.coherence_times:
        self.coherence_times["T2"] = {}

    self.coherence_times["T1"][qubit] = t1
    self.coherence_times["T2"][qubit] = t2

apply_to_circuit

apply_to_circuit(circuit: QuantumCircuit) -> QuantumCircuit

Apply noise model to quantum circuit

Parameters:

Name Type Description Default
circuit QuantumCircuit

Original circuit

required

Returns:

Type Description
QuantumCircuit

Noisy circuit with error channels

Source code in src/superquantx/noise.py
def apply_to_circuit(self, circuit: QuantumCircuit) -> QuantumCircuit:
    """Apply noise model to quantum circuit

    Args:
        circuit: Original circuit

    Returns:
        Noisy circuit with error channels

    """
    noisy_circuit = QuantumCircuit(circuit.num_qubits, circuit.num_classical_bits)

    for gate in circuit.gates:
        # Add original gate
        noisy_circuit.gates.append(gate)

        # Add noise after gate
        self._add_gate_noise(noisy_circuit, gate)

    # Add measurements with readout errors
    for qubit, cbit in circuit.measurements:
        self._add_readout_noise(noisy_circuit, qubit, cbit)

    return noisy_circuit

from_device_properties classmethod

from_device_properties(device_props: dict[str, Any]) -> NoiseModel

Create noise model from device properties

Parameters:

Name Type Description Default
device_props dict[str, Any]

Device property dictionary

required

Returns:

Type Description
NoiseModel

Noise model based on device properties

Source code in src/superquantx/noise.py
@classmethod
def from_device_properties(
    cls,
    device_props: dict[str, Any]
) -> "NoiseModel":
    """Create noise model from device properties

    Args:
        device_props: Device property dictionary

    Returns:
        Noise model based on device properties

    """
    noise_model = cls()

    # Extract gate error rates
    if "gates" in device_props:
        for gate_info in device_props["gates"]:
            gate_name = gate_info.get("gate")
            error_rate = gate_info.get("error_rate", 0.0)
            qubits = gate_info.get("qubits", [])

            if len(qubits) == 1:
                noise_model.add_single_qubit_error(gate_name, error_rate)
            elif len(qubits) == 2:
                noise_model.add_two_qubit_error(gate_name, error_rate)

    # Extract readout errors
    if "readout_errors" in device_props:
        for qubit, error_rate in enumerate(device_props["readout_errors"]):
            noise_model.add_readout_error(qubit, error_rate)

    # Extract coherence times
    if "coherence_times" in device_props:
        t1_times = device_props["coherence_times"].get("T1", [])
        t2_times = device_props["coherence_times"].get("T2", [])

        for qubit, (t1, t2) in enumerate(zip(t1_times, t2_times, strict=False)):
            noise_model.set_coherence_time(qubit, t1, t2)

    return noise_model

ideal classmethod

ideal() -> NoiseModel

Create ideal (noiseless) noise model

Source code in src/superquantx/noise.py
@classmethod
def ideal(cls) -> "NoiseModel":
    """Create ideal (noiseless) noise model"""
    return cls()

basic_device_noise classmethod

basic_device_noise(single_qubit_error: float = 0.001, two_qubit_error: float = 0.01, readout_error: float = 0.01) -> NoiseModel

Create basic device noise model

Parameters:

Name Type Description Default
single_qubit_error float

Single-qubit gate error rate

0.001
two_qubit_error float

Two-qubit gate error rate

0.01
readout_error float

Readout error rate

0.01

Returns:

Type Description
NoiseModel

Basic noise model

Source code in src/superquantx/noise.py
@classmethod
def basic_device_noise(
    cls,
    single_qubit_error: float = 1e-3,
    two_qubit_error: float = 1e-2,
    readout_error: float = 1e-2
) -> "NoiseModel":
    """Create basic device noise model

    Args:
        single_qubit_error: Single-qubit gate error rate
        two_qubit_error: Two-qubit gate error rate
        readout_error: Readout error rate

    Returns:
        Basic noise model

    """
    noise_model = cls()

    # Common single-qubit gates
    for gate in ["H", "X", "Y", "Z", "RX", "RY", "RZ", "U"]:
        noise_model.add_single_qubit_error(gate, single_qubit_error)

    # Common two-qubit gates
    for gate in ["CNOT", "CZ", "SWAP"]:
        noise_model.add_two_qubit_error(gate, two_qubit_error)

    return noise_model

Usage Examples

Basic Circuit Construction

import superquantx as sqx
import numpy as np

# Create quantum circuit
circuit = sqx.QuantumCircuit(n_qubits=3, n_classical=3)

# Add quantum gates
circuit.h(0)                    # Hadamard gate
circuit.cx(0, 1)               # CNOT gate
circuit.ry(np.pi/4, 2)         # Y-rotation

# Add measurements
circuit.measure(0, 0)          # Measure qubit 0 to classical bit 0
circuit.measure_all()          # Measure all qubits

print(circuit)

Advanced Gate Operations

from superquantx.gates import GateMatrix, PauliString

# Custom rotation gates
theta = np.pi/3
rx_gate = GateMatrix.rx(theta)
ry_gate = GateMatrix.ry(theta) 
rz_gate = GateMatrix.rz(theta)

# Pauli string operations
pauli_str = PauliString('XYZX')  # X⊗Y⊗Z⊗X
print(f"Pauli string: {pauli_str}")
print(f"Matrix shape: {pauli_str.to_matrix().shape}")

# Hamiltonian construction
from superquantx.gates import Hamiltonian, PauliString

# Create Heisenberg model Hamiltonian
hamiltonian = Hamiltonian.heisenberg_model(num_qubits=4, Jx=1.0, Jy=1.0, Jz=1.0)
print(f"Hamiltonian: {hamiltonian}")

# Time evolution
time_evolution_op = hamiltonian.time_evolution(time=0.1)
circuit.unitary(time_evolution_op, range(4))

Measurement Analysis

# Execute circuit and analyze results
backend = sqx.get_backend('simulator')
result = backend.execute_circuit(circuit, shots=1000)

# Create measurement result object
measurement = sqx.MeasurementResult(
    counts=result['counts'],
    shots=result['shots'],
    metadata=result.get('metadata', {})
)

# Analyze measurements
print(f"Most frequent outcome: {measurement.most_frequent}")
print(f"Measurement probabilities: {measurement.probabilities}")

# Marginal analysis
marginal = measurement.marginal_counts([0, 1])  # Marginalize over qubits 0,1
print(f"Marginal counts: {marginal}")

# Statistical analysis
entropy = measurement.measurement_entropy()
print(f"Measurement entropy: {entropy:.4f}")

Expectation Value Calculations

from superquantx.measurements import QuantumMeasurement
from superquantx.gates import PauliString

# Create measurement system
measurement = QuantumMeasurement(backend="simulator")

# Define observable
observable = 'ZZ'  # Z⊗Z measurement

# Calculate expectation value
exp_value = measurement.measure_observable(
    circuit=circuit,
    observable=observable,
    shots=5000
)

print(f"⟨ZZ⟩ = {exp_value:.4f}")

# Multiple observables
observables = ['XX', 'YY', 'ZZ']

exp_values = []
for obs in observables:
    val = measurement.measure_observable(circuit, obs, shots=5000)
    exp_values.append(val)
    print(f"⟨{obs}⟩ = {val:.4f}")

Quantum State Tomography

from superquantx.measurements import QuantumMeasurement

# Create measurement system
measurement = QuantumMeasurement(backend="simulator")

# Perform tomography measurements
tomography_results = measurement.tomography_measurements(
    circuit=circuit,
    qubits=[0, 1],  # Reconstruct 2-qubit state
    shots_per_measurement=1000
)

# Reconstruct density matrix
density_matrix = measurement.reconstruct_state(tomography_results)
print(f"Reconstructed density matrix:\n{density_matrix}")

# Calculate fidelity with target state
bell_state = np.array([1, 0, 0, 1]) / np.sqrt(2)  # |Φ⁺⟩
fidelity = measurement.fidelity(density_matrix, bell_state)

print(f"Fidelity with |Φ⁺⟩: {fidelity:.4f}")
print(f"State purity: {np.trace(density_matrix @ density_matrix).real:.4f}")

Noise Modeling

from superquantx.noise import (
    NoiseModel, BitFlipChannel, PhaseFlipChannel, 
    DepolarizingChannel, AmplitudeDampingChannel
)

# Create noise channels
bit_flip = BitFlipChannel(probability=0.01)
phase_flip = PhaseFlipChannel(probability=0.01)
depolarizing = DepolarizingChannel(probability=0.02)
amplitude_damping = AmplitudeDampingChannel(probability=0.05)

# Combine into noise model
noise_model = NoiseModel()

# Add gate-specific noise
noise_model.add_gate_noise('X', bit_flip)
noise_model.add_gate_noise('H', depolarizing)
noise_model.add_gate_noise('CNOT', phase_flip)

# Add readout noise
noise_model.add_readout_noise(
    p0_given_1=0.02,  # Probability of measuring 0 given |1⟩
    p1_given_0=0.03   # Probability of measuring 1 given |0⟩
)

# Apply noise model to backend
noisy_backend = sqx.get_backend('simulator', noise_model=noise_model)

# Execute noisy simulation
noisy_result = noisy_backend.execute_circuit(circuit, shots=1000)
print("Noisy simulation results:", noisy_result['counts'])

Error Mitigation

from superquantx.measurements import ResultAnalyzer

# Zero-noise extrapolation
noise_levels = [1, 2, 3]
measurement_results = []

# Collect measurements at different noise levels
for noise_level in noise_levels:
    # Create noisy backend (implementation dependent)
    result = measurement.measure_circuit(circuit, shots=1000)
    measurement_results.append(result)

# Perform extrapolation
zero_noise_value, fit_info = ResultAnalyzer.error_mitigation_zero_noise_extrapolation(
    noise_levels=noise_levels,
    measurement_results=measurement_results,
    observable='Z'
)

print(f"Zero-noise extrapolated value: {zero_noise_value:.4f}")
print(f"Fit R²: {fit_info.get('r_squared', 'N/A'):.4f}")

# Readout error mitigation
calibration_results = {"0": result, "1": result}  # Calibration measurements
corrected_result = ResultAnalyzer.readout_error_mitigation(
    calibration_results=calibration_results,
    measurement_result=result
)
print(f"Corrected counts: {corrected_result.counts}")

Circuit Optimization

from superquantx.circuits import CircuitOptimizer

# Create optimizer
optimizer = CircuitOptimizer(
    optimization_level=2,
    target_backend=backend
)

# Optimize circuit
optimized_circuit = optimizer.optimize(circuit)

print(f"Original circuit: {circuit.depth()} depth, {circuit.count_ops()} gates")
print(f"Optimized circuit: {optimized_circuit.depth()} depth, {optimized_circuit.count_ops()} gates")

# Specific optimizations
optimized_circuit = optimizer.apply_passes([
    'RemoveRedundantGates',
    'CombineRotations',
    'CancelInverses',
    'CommuteThroughClifford'
])

Parameterized Circuits

from superquantx.circuits import Parameter, ParameterVector

# Create parameters
theta = Parameter('theta')
phi_vec = ParameterVector('phi', 3)

# Build parameterized circuit
param_circuit = sqx.QuantumCircuit(3)

param_circuit.ry(theta, 0)
param_circuit.rx(phi_vec[0], 1)
param_circuit.rz(phi_vec[1], 2)
param_circuit.cx(0, 1)
param_circuit.cry(phi_vec[2], 1, 2)

# Bind parameters
bound_circuit = param_circuit.bind_parameters({
    theta: np.pi/4,
    phi_vec: [np.pi/3, np.pi/6, np.pi/2]
})

# Execute bound circuit
result = backend.execute_circuit(bound_circuit)

Quantum Circuit Libraries

from superquantx.circuits.library import (
    EfficientSU2,
    RealAmplitudes,
    ZZFeatureMap,
    PauliFeatureMap
)

# Variational ansatz circuits
ansatz1 = EfficientSU2(num_qubits=4, reps=3)
ansatz2 = RealAmplitudes(num_qubits=4, reps=2)

# Feature map circuits for quantum machine learning
feature_map1 = ZZFeatureMap(feature_dimension=4, reps=2)
feature_map2 = PauliFeatureMap(feature_dimension=4, reps=1)

# Combine feature map and ansatz
ml_circuit = feature_map1.compose(ansatz1)

# Bind training data
training_data = [0.1, 0.5, -0.3, 0.8]
bound_ml_circuit = ml_circuit.bind_parameters({
    **feature_map1.parameter_dict(training_data),
    **ansatz1.random_parameters()
})

Circuit Simulation and Debugging

from superquantx.circuits import CircuitSimulator

# Create detailed simulator
sim = CircuitSimulator(backend='statevector')

# Step-by-step execution
sim.initialize_circuit(circuit)

for step, gate in enumerate(circuit.data):
    print(f"Step {step}: Applying {gate}")

    # Apply gate
    sim.apply_gate(gate)

    # Get current state
    current_state = sim.get_statevector()
    print(f"  Statevector norm: {np.linalg.norm(current_state):.6f}")

    # Check entanglement
    entanglement = sim.calculate_entanglement()
    print(f"  Entanglement entropy: {entanglement:.4f}")

# Final state analysis
final_state = sim.get_statevector()
final_density_matrix = sim.get_density_matrix()

print("Final state analysis:")
print(f"  Purity: {np.trace(final_density_matrix @ final_density_matrix).real:.4f}")
print(f"  Von Neumann entropy: {sim.von_neumann_entropy():.4f}")

Performance Optimization

Circuit Compilation

from superquantx.circuits import QuantumCompiler

# Create compiler for specific backend
compiler = QuantumCompiler(target_backend=backend)

# Compile circuit
compiled_circuit = compiler.compile(
    circuit=circuit,
    optimization_level=3,
    scheduling='as_late_as_possible',
    layout='dense'
)

# Analysis compilation results
print(f"Compilation report:")
print(f"  Original gates: {circuit.count_ops()}")
print(f"  Compiled gates: {compiled_circuit.count_ops()}")
print(f"  Gate reduction: {(1 - compiled_circuit.count_ops()/circuit.count_ops())*100:.1f}%")

Batch Circuit Execution

# Execute multiple circuits efficiently
circuits = [create_random_circuit(n_qubits=4) for _ in range(10)]

# Parallel execution
results = backend.execute_circuits_parallel(
    circuits=circuits,
    shots=1000,
    max_workers=4
)

# Batch analysis
success_rate = sum(1 for r in results if r['success']) / len(results)
avg_execution_time = np.mean([r.get('execution_time', 0) for r in results])

print(f"Batch execution: {success_rate*100:.1f}% success rate")
print(f"Average execution time: {avg_execution_time:.3f}s")

Best Practices

Circuit Construction

  1. Use Native Gates: Prefer gates supported by target backend
  2. Minimize Depth: Reduce circuit depth for better fidelity
  3. Optimize Layout: Consider qubit connectivity constraints
  4. Parameter Management: Use symbolic parameters for flexibility

Measurement Strategy

  1. Statistical Significance: Use sufficient shots for reliable statistics
  2. Marginal Analysis: Focus on relevant qubit subsets
  3. Error Bars: Always include measurement uncertainties
  4. Baseline Comparison: Compare with theoretical expectations

Noise Handling

  1. Realistic Models: Use device-specific noise parameters
  2. Error Mitigation: Apply appropriate mitigation techniques
  3. Validation: Compare noisy vs. noiseless simulations
  4. Calibration: Regularly update noise models from hardware data

For more detailed examples and tutorials, see: - Circuit Construction Tutorial - Noise Modeling Guide - Backend Integration