Skip to content

Backends API Reference

Unverified examples

This page predates the current release and parts of it describe planned or older API. Only 4 of 13 code snippets on this page run as-is today. For verified, runnable code see the Quick Start, the Showcase and the Backends guide.

SuperQuantX provides a unified interface to multiple quantum computing backends, enabling seamless switching between simulators and real quantum hardware from different providers.

Base Classes

Base Backend

superquantx.backends.BaseBackend

BaseBackend(device: str | None = None, shots: int = 1024, **kwargs)

Bases: ABC

Abstract base class for quantum computing backends.

This class defines the interface that all quantum backends must implement to provide quantum circuit execution, measurement, and algorithm-specific operations for SuperQuantX.

Parameters:

Name Type Description Default
device str | None

Device or simulator to use

None
shots int

Default number of measurement shots

1024
**kwargs

Backend-specific configuration

{}
Source code in src/superquantx/backends/base_backend.py
def __init__(self, device: str | None = None, shots: int = 1024, **kwargs):
    self.device = device
    self.shots = shots
    self.config = kwargs
    self.capabilities = {}

    self._initialize_backend()

Functions

create_circuit abstractmethod

create_circuit(n_qubits: int) -> Any

Create a quantum circuit with n qubits.

Source code in src/superquantx/backends/base_backend.py
@abstractmethod
def create_circuit(self, n_qubits: int) -> Any:
    """Create a quantum circuit with n qubits."""
    pass

add_gate abstractmethod

add_gate(circuit: Any, gate: str, qubits: int | list[int], params: list[float] | None = None) -> Any

Add a quantum gate to the circuit.

Source code in src/superquantx/backends/base_backend.py
@abstractmethod
def add_gate(self, circuit: Any, gate: str, qubits: int | list[int],
             params: list[float] | None = None) -> Any:
    """Add a quantum gate to the circuit."""
    pass

add_measurement abstractmethod

add_measurement(circuit: Any, qubits: list[int] | None = None) -> Any

Add measurement operations to the circuit.

Source code in src/superquantx/backends/base_backend.py
@abstractmethod
def add_measurement(self, circuit: Any, qubits: list[int] | None = None) -> Any:
    """Add measurement operations to the circuit."""
    pass

execute_circuit abstractmethod

execute_circuit(circuit: Any, shots: int | None = None) -> dict[str, Any]

Execute quantum circuit and return results.

Source code in src/superquantx/backends/base_backend.py
@abstractmethod
def execute_circuit(self, circuit: Any, shots: int | None = None) -> dict[str, Any]:
    """Execute quantum circuit and return results."""
    pass

get_statevector abstractmethod

get_statevector(circuit: Any) -> np.ndarray

Get the statevector from a quantum circuit.

Source code in src/superquantx/backends/base_backend.py
@abstractmethod
def get_statevector(self, circuit: Any) -> np.ndarray:
    """Get the statevector from a quantum circuit."""
    pass

counts_big_endian

counts_big_endian(counts: dict[str, int]) -> dict[str, int]

Return counts re-keyed so that character i is the value of qubit i.

Source code in src/superquantx/backends/base_backend.py
def counts_big_endian(self, counts: dict[str, int]) -> dict[str, int]:
    """Return counts re-keyed so that character i is the value of qubit i."""
    if self._bit_order('counts') == 'big':
        return {str(k).replace(' ', ''): int(v) for k, v in counts.items()}
    return {str(k).replace(' ', '')[::-1]: int(v) for k, v in counts.items()}

statevector_big_endian

statevector_big_endian(circuit: Any) -> np.ndarray

Statevector of circuit with qubit 0 as the most significant bit.

Source code in src/superquantx/backends/base_backend.py
def statevector_big_endian(self, circuit: Any) -> np.ndarray:
    """Statevector of ``circuit`` with qubit 0 as the most significant bit."""
    sv = np.asarray(self.get_statevector(circuit), dtype=complex).ravel()
    n = int(round(np.log2(len(sv))))
    if 2 ** n != len(sv):
        raise RuntimeError(f"Statevector length {len(sv)} is not a power of two")
    if self._bit_order('statevector') == 'little' and n > 1:
        sv = sv.reshape([2] * n).transpose(list(range(n))[::-1]).reshape(-1)
    return sv

create_feature_map

create_feature_map(n_features: int, feature_map: str = 'ZZFeatureMap', reps: int = 2) -> FeatureMapSpec

Return a feature-map specification used by :meth:compute_kernel_matrix.

Supported maps: ZZFeatureMap (Havlicek et al. 2019, linear entanglement), ZFeatureMap (the same without entanglement), PauliFeatureMap (RX/RY/RZ plus CNOT chain) and AngleEncoding (one RY per feature).

Source code in src/superquantx/backends/base_backend.py
def create_feature_map(self, n_features: int, feature_map: str = 'ZZFeatureMap',
                       reps: int = 2) -> 'FeatureMapSpec':
    """Return a feature-map specification used by :meth:`compute_kernel_matrix`.

    Supported maps: ``ZZFeatureMap`` (Havlicek et al. 2019, linear
    entanglement), ``ZFeatureMap`` (the same without entanglement),
    ``PauliFeatureMap`` (RX/RY/RZ plus CNOT chain) and
    ``AngleEncoding`` (one RY per feature).
    """
    if feature_map not in FEATURE_MAPS:
        raise ValueError(
            f"Unknown feature map '{feature_map}'. Supported: {sorted(FEATURE_MAPS)}"
        )
    return FeatureMapSpec(name=feature_map, n_features=n_features, reps=reps)

build_feature_map_circuit

build_feature_map_circuit(x: ndarray, spec: FeatureMapSpec) -> Any

Build the backend-native circuit that encodes x with spec.

Source code in src/superquantx/backends/base_backend.py
def build_feature_map_circuit(self, x: np.ndarray, spec: 'FeatureMapSpec') -> Any:
    """Build the backend-native circuit that encodes ``x`` with ``spec``."""
    n = spec.n_features
    x = np.asarray(x, dtype=float).ravel()
    if len(x) != n:
        raise ValueError(f"Feature map expects {n} features, got {len(x)}")
    circuit = self.create_circuit(n)
    for _ in range(spec.reps):
        if spec.name == 'ZZFeatureMap':
            for i in range(n):
                circuit = self.add_gate(circuit, 'H', i)
                circuit = self.add_gate(circuit, 'RZ', i, [2.0 * x[i]])
            for i in range(n - 1):
                phi = 2.0 * (np.pi - x[i]) * (np.pi - x[i + 1])
                circuit = self.add_gate(circuit, 'CNOT', [i, i + 1])
                circuit = self.add_gate(circuit, 'RZ', i + 1, [phi])
                circuit = self.add_gate(circuit, 'CNOT', [i, i + 1])
        elif spec.name == 'ZFeatureMap':
            for i in range(n):
                circuit = self.add_gate(circuit, 'H', i)
                circuit = self.add_gate(circuit, 'RZ', i, [2.0 * x[i]])
        elif spec.name == 'PauliFeatureMap':
            for i in range(n):
                circuit = self.add_gate(circuit, 'RX', i, [x[i]])
                circuit = self.add_gate(circuit, 'RY', i, [x[i]])
                circuit = self.add_gate(circuit, 'RZ', i, [x[i]])
            for i in range(n - 1):
                circuit = self.add_gate(circuit, 'CNOT', [i, i + 1])
        else:  # AngleEncoding
            for i in range(n):
                circuit = self.add_gate(circuit, 'RY', i, [x[i]])
    return circuit

compute_kernel_matrix

compute_kernel_matrix(X1: ndarray, X2: ndarray, feature_map: Any = None, shots: int | None = None) -> np.ndarray

Fidelity quantum kernel K[i, j] = ||^2.

Each data point is encoded with the feature map and simulated on this backend; the kernel is computed exactly from the resulting statevectors (shots is accepted for API compatibility and ignored). This is a real quantum-circuit kernel, but it is classically simulated, so it says nothing about quantum advantage.

Source code in src/superquantx/backends/base_backend.py
def compute_kernel_matrix(self, X1: np.ndarray, X2: np.ndarray,
                          feature_map: Any = None, shots: int | None = None) -> np.ndarray:
    """Fidelity quantum kernel K[i, j] = |<phi(x1_i)|phi(x2_j)>|^2.

    Each data point is encoded with the feature map and simulated on this
    backend; the kernel is computed exactly from the resulting statevectors
    (``shots`` is accepted for API compatibility and ignored). This is a
    real quantum-circuit kernel, but it is classically simulated, so it says
    nothing about quantum advantage.
    """
    X1 = np.atleast_2d(np.asarray(X1, dtype=float))
    X2 = np.atleast_2d(np.asarray(X2, dtype=float))
    if feature_map is None:
        spec = self.create_feature_map(X1.shape[1])
    elif isinstance(feature_map, str):
        spec = self.create_feature_map(X1.shape[1], feature_map)
    elif isinstance(feature_map, FeatureMapSpec):
        spec = feature_map
    else:
        raise TypeError(
            "feature_map must be a FeatureMapSpec, a feature map name, or None; "
            f"got {type(feature_map).__name__}"
        )

    def states(X: np.ndarray) -> np.ndarray:
        return np.array([
            self.statevector_big_endian(self.build_feature_map_circuit(x, spec))
            for x in X
        ])

    S1 = states(X1)
    S2 = S1 if X2 is X1 or (X2.shape == X1.shape and np.array_equal(X1, X2)) else states(X2)
    return np.abs(S1.conj() @ S2.T) ** 2

ansatz_param_count

ansatz_param_count(ansatz_type: str, n_qubits: int, reps: int = 1) -> int

Number of parameters used by :meth:create_ansatz.

Source code in src/superquantx/backends/base_backend.py
def ansatz_param_count(self, ansatz_type: str, n_qubits: int, reps: int = 1) -> int:
    """Number of parameters used by :meth:`create_ansatz`."""
    if ansatz_type == 'EfficientSU2':
        return 2 * n_qubits * (reps + 1)
    if ansatz_type in ('RealAmplitudes', 'TwoLocal'):
        return n_qubits * (reps + 1)
    raise ValueError(
        f"Ansatz '{ansatz_type}' is not implemented. Use 'RealAmplitudes', "
        "'EfficientSU2' or 'TwoLocal', or pass a callable ansatz."
    )

create_ansatz

create_ansatz(ansatz_type: str, n_qubits: int, params: ndarray, include_custom_gates: bool = False, reps: int | None = None) -> Any

Build a hardware-efficient ansatz with this backend's own gates.

RealAmplitudes/TwoLocal: reps layers of RY on every qubit followed by a linear CNOT chain, plus a final RY layer. EfficientSU2: the same structure with RY and RZ rotations.

Source code in src/superquantx/backends/base_backend.py
def create_ansatz(self, ansatz_type: str, n_qubits: int, params: np.ndarray,
                  include_custom_gates: bool = False, reps: int | None = None) -> Any:
    """Build a hardware-efficient ansatz with this backend's own gates.

    ``RealAmplitudes``/``TwoLocal``: ``reps`` layers of RY on every qubit
    followed by a linear CNOT chain, plus a final RY layer.
    ``EfficientSU2``: the same structure with RY and RZ rotations.
    """
    params = np.asarray(params, dtype=float).ravel()
    per_layer = 2 * n_qubits if ansatz_type == 'EfficientSU2' else n_qubits
    if reps is None:
        reps = max(len(params) // per_layer - 1, 0)
    expected = self.ansatz_param_count(ansatz_type, n_qubits, reps)
    if len(params) != expected:
        raise ValueError(
            f"{ansatz_type} with {n_qubits} qubits and reps={reps} needs "
            f"{expected} parameters, got {len(params)}"
        )

    circuit = self.create_circuit(n_qubits)
    idx = 0
    for layer in range(reps + 1):
        for q in range(n_qubits):
            circuit = self.add_gate(circuit, 'RY', q, [params[idx]])
            idx += 1
            if ansatz_type == 'EfficientSU2':
                circuit = self.add_gate(circuit, 'RZ', q, [params[idx]])
                idx += 1
        if layer < reps:
            for q in range(n_qubits - 1):
                circuit = self.add_gate(circuit, 'CNOT', [q, q + 1])
    return circuit

compute_expectation

compute_expectation(circuit: Any, hamiltonian: Any, shots: int | None = None) -> float

Exact expectation value from this backend's statevector.

hamiltonian may be a dense matrix (qubit 0 most significant), a superquantx.gates.Hamiltonian, a dict like {"ZI": -0.4}, a list of (coeff, "ZI") pairs, or a PennyLane / Qiskit operator. shots is accepted for API compatibility and ignored.

Source code in src/superquantx/backends/base_backend.py
def compute_expectation(self, circuit: Any, hamiltonian: Any,
                        shots: int | None = None) -> float:
    """Exact expectation value <psi|H|psi> from this backend's statevector.

    ``hamiltonian`` may be a dense matrix (qubit 0 most significant), a
    ``superquantx.gates.Hamiltonian``, a dict like ``{"ZI": -0.4}``, a list
    of ``(coeff, "ZI")`` pairs, or a PennyLane / Qiskit operator.
    ``shots`` is accepted for API compatibility and ignored.
    """
    sv = self.statevector_big_endian(circuit)
    n = int(round(np.log2(len(sv))))
    H = hamiltonian_to_matrix(hamiltonian, n)
    return float(np.real(np.vdot(sv, H @ sv)))

create_qaoa_circuit

create_qaoa_circuit(n_qubits: int, gammas: ndarray, betas: ndarray, problem_hamiltonian: Any, mixer_hamiltonian: Any, initial_state: Any, problem_instance: Any) -> Any

QAOA circuit for weighted MaxCut given an adjacency matrix.

Cost layer: exp(-i gamma w_ij Z_i Z_j / 2) per edge (CNOT, RZ, CNOT); mixer layer: RX(2 beta) on every qubit; initial state |+>^n.

Source code in src/superquantx/backends/base_backend.py
def create_qaoa_circuit(self, n_qubits: int, gammas: np.ndarray, betas: np.ndarray,
                        problem_hamiltonian: Any, mixer_hamiltonian: Any,
                        initial_state: Any, problem_instance: Any) -> Any:
    """QAOA circuit for weighted MaxCut given an adjacency matrix.

    Cost layer: exp(-i gamma w_ij Z_i Z_j / 2) per edge (CNOT, RZ, CNOT);
    mixer layer: RX(2 beta) on every qubit; initial state |+>^n.
    """
    W = _as_weight_matrix(problem_instance, n_qubits)
    circuit = self.create_circuit(n_qubits)
    for q in range(n_qubits):
        circuit = self.add_gate(circuit, 'H', q)
    for gamma, beta in zip(gammas, betas, strict=True):
        for i in range(n_qubits):
            for j in range(i + 1, n_qubits):
                if W[i, j] != 0:
                    circuit = self.add_gate(circuit, 'CNOT', [i, j])
                    circuit = self.add_gate(circuit, 'RZ', j, [float(gamma * W[i, j])])
                    circuit = self.add_gate(circuit, 'CNOT', [i, j])
        for q in range(n_qubits):
            circuit = self.add_gate(circuit, 'RX', q, [float(2 * beta)])
    return circuit

execute_qaoa

execute_qaoa(circuit: Any, problem_hamiltonian: Any, problem_instance: Any, shots: int | None = None) -> float

Expected MaxCut value of the QAOA state (exact, from the statevector).

Source code in src/superquantx/backends/base_backend.py
def execute_qaoa(self, circuit: Any, problem_hamiltonian: Any, problem_instance: Any,
                 shots: int | None = None) -> float:
    """Expected MaxCut value of the QAOA state (exact, from the statevector)."""
    probs = np.abs(self.statevector_big_endian(circuit)) ** 2
    n = int(round(np.log2(len(probs))))
    W = _as_weight_matrix(problem_instance, n)
    return float(probs @ maxcut_values(W))

sample_circuit

sample_circuit(circuit: Any, shots: int | None = None) -> np.ndarray

Sample bitstrings; row k column i is the measured value of qubit i.

Source code in src/superquantx/backends/base_backend.py
def sample_circuit(self, circuit: Any, shots: int | None = None) -> np.ndarray:
    """Sample bitstrings; row k column i is the measured value of qubit i."""
    circuit = self.add_measurement(circuit)
    result = self.execute_circuit(circuit, shots)
    if not result.get('counts'):
        raise RuntimeError(f"{self.__class__.__name__} returned no counts: {result}")
    counts = self.counts_big_endian(result['counts'])
    rows = []
    for bitstring, count in counts.items():
        rows.extend([[int(b) for b in bitstring]] * int(count))
    return np.array(rows, dtype=int)

encode_data_point

encode_data_point(data: ndarray, encoding: str, n_qubits: int) -> Any

Encode classical data into quantum state.

Source code in src/superquantx/backends/base_backend.py
def encode_data_point(self, data: np.ndarray, encoding: str, n_qubits: int) -> Any:
    """Encode classical data into quantum state."""
    circuit = self.create_circuit(n_qubits)

    if encoding == 'amplitude':
        return self._amplitude_encoding(circuit, data)
    elif encoding == 'angle':
        return self._angle_encoding(circuit, data)
    elif encoding == 'basis':
        return self._basis_encoding(circuit, data)
    else:
        logger.warning(f"Encoding '{encoding}' not implemented, using angle encoding")
        return self._angle_encoding(circuit, data)

compute_quantum_distance

compute_quantum_distance(x1: ndarray, x2: ndarray, metric: str, encoding: str, n_qubits: int, shots: int) -> float

Distance between two data points.

Only metric='fidelity' uses quantum states: it angle-encodes both points and returns sqrt(1 - ||^2) computed from statevectors. 'euclidean' and 'manhattan' are plain classical distances.

Source code in src/superquantx/backends/base_backend.py
def compute_quantum_distance(self, x1: np.ndarray, x2: np.ndarray, metric: str,
                            encoding: str, n_qubits: int, shots: int) -> float:
    """Distance between two data points.

    Only ``metric='fidelity'`` uses quantum states: it angle-encodes both
    points and returns sqrt(1 - |<x1|x2>|^2) computed from statevectors.
    ``'euclidean'`` and ``'manhattan'`` are plain classical distances.
    """
    if metric == 'fidelity':
        spec = FeatureMapSpec(name='AngleEncoding', n_features=len(x1), reps=1)
        s1 = self.statevector_big_endian(self.build_feature_map_circuit(x1, spec))
        s2 = self.statevector_big_endian(self.build_feature_map_circuit(x2, spec))
        return float(np.sqrt(max(0.0, 1.0 - abs(np.vdot(s1, s2)) ** 2)))
    if metric == 'euclidean':
        return np.linalg.norm(x1 - x2)
    elif metric == 'manhattan':
        return np.sum(np.abs(x1 - x2))
    else:
        return np.linalg.norm(x1 - x2)

execute_qnn

execute_qnn(input_data: ndarray, weights: ndarray, quantum_layers: list[dict], classical_layers: list[dict], encoding: str, measurement: str, shots: int) -> np.ndarray

Execute quantum neural network.

Source code in src/superquantx/backends/base_backend.py
def execute_qnn(self, input_data: np.ndarray, weights: np.ndarray,
               quantum_layers: list[dict], classical_layers: list[dict],
               encoding: str, measurement: str, shots: int) -> np.ndarray:
    """Execute quantum neural network."""
    # Each variational layer holds an RY and an RZ angle per qubit.
    n_qubits = len(weights) // (2 * len(quantum_layers)) if quantum_layers else input_data.shape[1]

    # Get expected output size from classical layers
    expected_output_size = None
    if classical_layers:
        for layer in classical_layers:
            if 'units' in layer:
                expected_output_size = layer['units']
                break


    outputs = []
    for sample in input_data:
        # Encode input data into a fresh circuit
        circuit = self.encode_data_point(sample, encoding, n_qubits)

        # Add variational layers
        param_idx = 0
        for layer in quantum_layers:
            layer_params = weights[param_idx:param_idx + n_qubits * 2]
            circuit = self._add_variational_layer(circuit, layer_params)
            param_idx += n_qubits * 2

        # Measure
        if measurement == 'expectation':
            # Compute expectation values
            result = self._compute_pauli_expectation(circuit, ['Z'] * n_qubits)
        else:
            # Sample and get probabilities
            result = self.execute_circuit(circuit, shots)
            result = self._result_to_probabilities(result)

        # Apply classical layers if present
        if classical_layers and expected_output_size:
            # Simple linear transformation to get desired output size
            if len(result) != expected_output_size:
                # Reshape/transform the quantum output to match expected size
                if len(result) > expected_output_size:
                    # Take first n elements or average
                    result = result[:expected_output_size]
                else:
                    # Pad with zeros or repeat
                    result = np.pad(result, (0, expected_output_size - len(result)), mode='constant')

        outputs.append(result)

    return np.array(outputs)

get_version_info

get_version_info() -> dict[str, Any]

Get backend version information.

Source code in src/superquantx/backends/base_backend.py
def get_version_info(self) -> dict[str, Any]:
    """Get backend version information."""
    return {
        'backend_name': self.__class__.__name__,
        'device': self.device,
        'capabilities': self.capabilities,
        'backend_version': '1.0.0',  # Default backend version
    }

get_device_info

get_device_info() -> dict[str, Any]

Get information about the quantum device.

Source code in src/superquantx/backends/base_backend.py
def get_device_info(self) -> dict[str, Any]:
    """Get information about the quantum device."""
    return {
        'device': self.device,
        'n_qubits': getattr(self, 'n_qubits', 'Unknown'),
        'topology': getattr(self, 'topology', 'Unknown'),
    }

Simulator Backends

Python Simulator Backend

superquantx.backends.SimulatorBackend

SimulatorBackend(device: str = 'simulator', max_qubits: int = 10, shots: int = 1024, **kwargs)

Bases: BaseBackend

Pure Python quantum simulator backend.

This backend provides a simple quantum simulator implementation that doesn't require external libraries. Useful for testing, development, and as a fallback when other backends are unavailable.

Parameters:

Name Type Description Default
device str

Device name (always 'simulator')

'simulator'
max_qubits int

Maximum number of qubits to simulate

10
shots int

Default number of measurement shots

1024
**kwargs

Additional parameters

{}
Source code in src/superquantx/backends/simulator_backend.py
def __init__(self, device: str = 'simulator', max_qubits: int = 10,
             shots: int = 1024, **kwargs):
    self.max_qubits = max_qubits
    super().__init__(device=device, shots=shots, **kwargs)
    self.capabilities = {
        'supports_gradient': True,  # Can compute numerical gradients
        'supports_parameter_shift': True,
        'supports_finite_diff': True,
        'supports_backprop': False,
        'supports_hardware': False,
        'supports_noise_models': False,
        'supports_measurements': True,  # Can perform measurements
        'supports_parameterized_circuits': True,  # Can handle parameterized circuits
    }

    # Gate matrices
    self.gates = self._define_gates()

Functions

create_circuit

create_circuit(n_qubits: int) -> QuantumState

Create a quantum circuit with n qubits.

Source code in src/superquantx/backends/simulator_backend.py
def create_circuit(self, n_qubits: int) -> QuantumState:
    """Create a quantum circuit with n qubits."""
    if n_qubits > self.max_qubits:
        raise ValueError(
            f"Requested {n_qubits} qubits, but this simulator is limited to "
            f"{self.max_qubits} (pass max_qubits=... to raise the limit)"
        )
    return QuantumState(n_qubits)

add_gate

add_gate(circuit: QuantumState, gate: str, qubits: int | list[int], params: list[float] | None = None) -> QuantumState

Apply a quantum gate to the circuit state.

Raises:

Type Description
ValueError

for unknown gates or invalid qubits.

Source code in src/superquantx/backends/simulator_backend.py
def add_gate(self, circuit: QuantumState, gate: str, qubits: int | list[int],
             params: list[float] | None = None) -> QuantumState:
    """Apply a quantum gate to the circuit state.

    Raises:
        ValueError: for unknown gates or invalid qubits.

    """
    if isinstance(qubits, int):
        qubits = [qubits]
    qubits = [int(q) for q in qubits]
    params = list(params) if params is not None else []
    name = gate.upper()

    if name in ('RX', 'RY', 'RZ'):
        matrix = self._rotation_gate(name[1], float(params[0]))
    elif name in ('P', 'PHASE', 'U1'):
        matrix = np.diag([1, np.exp(1j * float(params[0]))]).astype(complex)
    elif name in ('CRX', 'CRY', 'CRZ'):
        matrix = self._controlled(self._rotation_gate(name[2], float(params[0])))
    elif name in ('CCX', 'TOFFOLI'):
        matrix = self._controlled(self.gates['CNOT'])
    elif name in self.gates:
        matrix = self.gates[name]
    else:
        raise ValueError(f"Unsupported gate for SimulatorBackend: {gate}")

    circuit.apply_gate(matrix, qubits)
    return circuit

add_measurement

add_measurement(circuit: QuantumState, qubits: list[int] | None = None) -> QuantumState

Add measurement operations (no-op in this implementation).

Source code in src/superquantx/backends/simulator_backend.py
def add_measurement(self, circuit: QuantumState, qubits: list[int] | None = None) -> QuantumState:
    """Add measurement operations (no-op in this implementation)."""
    # Measurements are handled in execute_circuit
    return circuit

execute_circuit

execute_circuit(circuit: QuantumState, shots: int | None = None) -> dict[str, Any]

Sample all qubits. Bitstrings are little-endian (qubit 0 rightmost), like Qiskit.

Source code in src/superquantx/backends/simulator_backend.py
def execute_circuit(self, circuit: QuantumState, shots: int | None = None) -> dict[str, Any]:
    """Sample all qubits. Bitstrings are little-endian (qubit 0 rightmost), like Qiskit."""
    shots = shots or self.shots
    probabilities = np.abs(circuit.state) ** 2
    probabilities = probabilities / probabilities.sum()
    outcomes = np.random.choice(len(circuit.state), size=shots, p=probabilities)
    values, freq = np.unique(outcomes, return_counts=True)
    counts = {format(int(v), f'0{circuit.n_qubits}b'): int(c) for v, c in zip(values, freq, strict=True)}
    return {
        'counts': counts,
        'shots': shots,
        'backend': 'python_simulator',
    }

get_statevector

get_statevector(circuit: QuantumState) -> np.ndarray

Get the statevector from a quantum circuit.

Source code in src/superquantx/backends/simulator_backend.py
def get_statevector(self, circuit: QuantumState) -> np.ndarray:
    """Get the statevector from a quantum circuit."""
    return circuit.get_statevector()

get_version_info

get_version_info() -> dict[str, Any]

Get simulator version information.

Source code in src/superquantx/backends/simulator_backend.py
def get_version_info(self) -> dict[str, Any]:
    """Get simulator version information."""
    info = super().get_version_info()
    info.update({
        'simulator_type': 'pure_python',
        'max_qubits': self.max_qubits,
        'available_gates': list(self.gates.keys()),
    })
    return info

get_backend_info

get_backend_info() -> dict[str, Any]

Get backend information.

Source code in src/superquantx/backends/simulator_backend.py
def get_backend_info(self) -> dict[str, Any]:
    """Get backend information."""
    return {
        'backend_name': self.__class__.__name__,
        'device': self.device,
        'capabilities': self.capabilities,
        'simulator_type': 'pure_python',
        'max_qubits': self.max_qubits,
        'available_gates': list(self.gates.keys()),
    }

run

run(circuit: QuantumState, shots: int | None = None) -> QuantumResult

Run a quantum circuit and return results.

Source code in src/superquantx/backends/simulator_backend.py
def run(self, circuit: QuantumState, shots: int | None = None) -> "QuantumResult":
    """Run a quantum circuit and return results."""
    result_dict = self.execute_circuit(circuit, shots)
    return QuantumResult(result_dict)

is_available

is_available() -> bool

Check if the backend is available.

Source code in src/superquantx/backends/simulator_backend.py
def is_available(self) -> bool:
    """Check if the backend is available."""
    return True

Hardware Backends

IBM Qiskit Backend

superquantx.backends.QiskitBackend

QiskitBackend(device: str = 'aer_simulator', provider: dict | None = None, shots: int = 1024, **kwargs)

Bases: BaseBackend

Qiskit backend (Aer simulator locally, IBM Quantum via qiskit-ibm-runtime).

Parameters:

Name Type Description Default
device str

'aer_simulator' (default), an Aer method name such as 'statevector', or an IBM backend name such as 'ibm_brisbane'.

'aer_simulator'
provider dict | None

Optional dict of QiskitRuntimeService keyword arguments (channel, token, instance) for IBM hardware.

None
shots int

Number of measurement shots.

1024
Source code in src/superquantx/backends/qiskit_backend.py
def __init__(self, device: str = 'aer_simulator', provider: dict | None = None,
             shots: int = 1024, **kwargs):
    if not QISKIT_AVAILABLE:
        raise ImportError(
            "Qiskit is required for QiskitBackend. Install with: pip install 'superquantx[qiskit]'"
        )
    self.provider = provider
    self.backend = None
    self.service = None
    self.is_hardware = False
    super().__init__(device=device, shots=shots, **kwargs)
    self.capabilities = {
        'supports_gradient': False,
        'supports_parameter_shift': True,
        'supports_finite_diff': True,
        'supports_hardware': IBM_RUNTIME_AVAILABLE,
        'supports_noise_models': True,
    }

Functions

execute_circuit

execute_circuit(circuit: Any, shots: int | None = None) -> dict[str, Any]

Run the circuit and return counts (little-endian: qubit 0 is the rightmost bit).

If the circuit has no measurements, all qubits are measured on a copy.

Source code in src/superquantx/backends/qiskit_backend.py
def execute_circuit(self, circuit: Any, shots: int | None = None) -> dict[str, Any]:
    """Run the circuit and return counts (little-endian: qubit 0 is the rightmost bit).

    If the circuit has no measurements, all qubits are measured on a copy.
    """
    shots = shots or self.shots
    if not self._has_measurements(circuit):
        circuit = self.add_measurement(circuit.copy())

    if self.is_hardware:
        from qiskit.transpiler import generate_preset_pass_manager
        pm = generate_preset_pass_manager(backend=self.backend, optimization_level=1)
        isa = pm.run(circuit)
        job = RuntimeSampler(mode=self.backend).run([isa], shots=shots)
        pub = job.result()[0]
        counts: dict[str, int] = {}
        for reg in isa.cregs:
            data = getattr(pub.data, reg.name)
            for k, v in data.get_counts().items():
                counts[k] = counts.get(k, 0) + v
            break
        return {'counts': counts, 'shots': shots, 'backend': self.device,
                'job_id': job.job_id()}

    job = self.backend.run(transpile(circuit, self.backend), shots=shots)
    counts = job.result().get_counts()
    return {'counts': dict(counts), 'shots': shots, 'backend': self.device,
            'job_id': job.job_id()}

get_statevector

get_statevector(circuit: Any) -> np.ndarray

Exact statevector (little-endian), computed with qiskit.quantum_info.

Source code in src/superquantx/backends/qiskit_backend.py
def get_statevector(self, circuit: Any) -> np.ndarray:
    """Exact statevector (little-endian), computed with qiskit.quantum_info."""
    clean = circuit.remove_final_measurements(inplace=False)
    return np.asarray(Statevector.from_instruction(clean).data)

PennyLane Backend

superquantx.backends.PennyLaneBackend

PennyLaneBackend(device: str = 'default.qubit', wires: int = 16, shots: int = 1024, **kwargs)

Bases: BaseBackend

PennyLane backend.

Parameters:

Name Type Description Default
device str

PennyLane device name ('default.qubit', 'lightning.qubit', ...).

'default.qubit'
wires int

Maximum number of wires a circuit may use.

16
shots int

Default number of shots for sampled execution.

1024
**kwargs

Extra keyword arguments passed to qml.device.

{}
Source code in src/superquantx/backends/pennylane_backend.py
def __init__(self, device: str = 'default.qubit', wires: int = 16, shots: int = 1024, **kwargs):
    if not PENNYLANE_AVAILABLE:
        raise ImportError(
            "PennyLane is required for PennyLaneBackend. Install with: pip install 'superquantx[pennylane]'"
        )
    self.wires = wires
    self._devices: dict[int, Any] = {}
    super().__init__(device=device, shots=shots, **kwargs)
    self.capabilities = {
        'supports_gradient': True,
        'supports_parameter_shift': True,
        'supports_finite_diff': True,
        'supports_backprop': device == 'default.qubit',
        'supports_adjoint': device in ('default.qubit', 'lightning.qubit'),
    }

Functions

execute_circuit

execute_circuit(circuit: PennyLaneCircuit | Callable, shots: int | None = None) -> dict[str, Any]

Sample the circuit and return counts (big-endian: wire 0 is the leftmost bit).

A plain quantum function (legacy API) is also accepted; it is run as a QNode and its return value is passed back under 'result'.

Source code in src/superquantx/backends/pennylane_backend.py
def execute_circuit(self, circuit: PennyLaneCircuit | Callable, shots: int | None = None) -> dict[str, Any]:
    """Sample the circuit and return counts (big-endian: wire 0 is the leftmost bit).

    A plain quantum function (legacy API) is also accepted; it is run as a
    QNode and its return value is passed back under ``'result'``.
    """
    shots = shots or self.shots
    if not isinstance(circuit, PennyLaneCircuit):
        qnode = qml.set_shots(qml.QNode(circuit, self._device(self.wires)), shots=shots)
        return {'result': qnode(), 'shots': shots, 'device': self.device}

    wires = circuit.measured if circuit.measured is not None else list(range(circuit.n_qubits))

    def qfunc():
        circuit.apply()
        return qml.counts(wires=wires)

    qnode = qml.set_shots(qml.QNode(qfunc, self._device(circuit.n_qubits)), shots=shots)
    counts = {str(k): int(v) for k, v in qnode().items()}
    return {'counts': counts, 'shots': shots, 'device': self.device}

get_statevector

get_statevector(circuit: PennyLaneCircuit | Callable) -> np.ndarray

Exact statevector (big-endian, wire 0 most significant).

Source code in src/superquantx/backends/pennylane_backend.py
def get_statevector(self, circuit: PennyLaneCircuit | Callable) -> np.ndarray:
    """Exact statevector (big-endian, wire 0 most significant)."""
    n = circuit.n_qubits if isinstance(circuit, PennyLaneCircuit) else self.wires

    def qfunc():
        circuit()
        return qml.state()

    return np.asarray(qml.QNode(qfunc, self._device(n))())

Google Cirq Backend

superquantx.backends.CirqBackend

CirqBackend(device: str = 'simulator', processor_id: str | None = None, shots: int = 1024, **kwargs)

Bases: BaseBackend

Cirq backend.

Circuits are (cirq.Circuit, [LineQubit, ...]) tuples. Counts and statevectors are big-endian (qubit 0 is the leftmost bit).

Parameters:

Name Type Description Default
device str

'simulator' (default).

'simulator'
processor_id str | None

Google Quantum AI processor id (hardware, untested).

None
shots int

Number of measurement shots.

1024
Source code in src/superquantx/backends/cirq_backend.py
def __init__(self, device: str = 'simulator', processor_id: str | None = None,
             shots: int = 1024, **kwargs):
    if not CIRQ_AVAILABLE:
        raise ImportError("Cirq is required for CirqBackend. Install with: pip install 'superquantx[cirq]'")
    # These must exist before BaseBackend.__init__ calls _initialize_backend().
    self.processor_id = processor_id
    self.simulator = None
    self.quantum_engine = None
    super().__init__(device=device, shots=shots, **kwargs)
    self.capabilities = {
        'supports_gradient': False,
        'supports_parameter_shift': True,
        'supports_finite_diff': True,
        'supports_hardware': processor_id is not None,
        'supports_noise_models': True,
    }

Functions

execute_circuit

execute_circuit(circuit_info: Any, shots: int | None = None) -> dict[str, Any]

Sample the circuit; unmeasured circuits get all qubits measured on a copy.

Source code in src/superquantx/backends/cirq_backend.py
def execute_circuit(self, circuit_info: Any, shots: int | None = None) -> dict[str, Any]:
    """Sample the circuit; unmeasured circuits get all qubits measured on a copy."""
    circuit, qubit_list = self._unpack(circuit_info)
    shots = shots or self.shots
    if not circuit.has_measurements():
        circuit = circuit + cirq.Circuit(cirq.measure(*qubit_list, key='result'))

    if self.quantum_engine is not None:
        processor = self.quantum_engine.get_processor(self.processor_id)
        job = processor.run(circuit, repetitions=shots)
        result = job.results()[0]
        backend_name = f'google_quantum_{self.processor_id}'
    else:
        result = self.simulator.run(circuit, repetitions=shots)
        backend_name = 'cirq_simulator'

    keys = list(result.measurements)
    bits = np.concatenate([result.measurements[k] for k in keys], axis=1)
    values, freq = np.unique(bits, axis=0, return_counts=True)
    counts = {''.join(str(int(b)) for b in row): int(c) for row, c in zip(values, freq, strict=True)}
    return {'counts': counts, 'shots': shots, 'backend': backend_name}

Amazon Braket Backend

superquantx.backends.BraketBackend

BraketBackend(device: str = 'local:braket/braket_sv', shots: int = 1024, aws_session=None, s3_folder: tuple[str, str] | None = None, **kwargs)

Bases: BaseBackend

AWS Braket backend for quantum computing operations.

This backend provides access to AWS Braket's quantum devices including local simulators, managed simulators, and QPU hardware from IonQ, Rigetti, and other providers available on AWS.

Parameters:

Name Type Description Default
device str

Device name or ARN (e.g., 'local:braket/braket_sv', 'arn:aws:braket::device/qpu/ionq/ionQdevice')

'local:braket/braket_sv'
shots int

Number of measurement shots

1024
aws_session

Optional AWS session for authentication

None
s3_folder tuple[str, str] | None

S3 bucket folder for results (required for hardware)

None
**kwargs

Additional device configuration

{}
Example

Local simulator

backend = BraketBackend(device='local:braket/braket_sv')

AWS hardware (requires authentication)

backend = BraketBackend( ... device='arn:aws:braket::device/qpu/ionq/ionQdevice', ... s3_folder=('my-bucket', 'quantum-results') ... )

Source code in src/superquantx/backends/braket_backend.py
def __init__(
    self,
    device: str = 'local:braket/braket_sv',
    shots: int = 1024,
    aws_session = None,
    s3_folder: tuple[str, str] | None = None,
    **kwargs
) -> None:
    if not BRAKET_AVAILABLE:
        raise ImportError(
            "AWS Braket not available. Install with: pip install amazon-braket-sdk"
        )

    self.device_name = device
    self.aws_session = aws_session
    self.s3_folder = s3_folder
    self._device = None

    super().__init__(device=device, shots=shots, **kwargs)

Functions

create_circuit

create_circuit(n_qubits: int) -> BraketCircuit

Create a Braket circuit on n_qubits qubits.

Braket circuits only know about qubits that carry an instruction, so an identity is placed on every qubit to fix the register size.

Source code in src/superquantx/backends/braket_backend.py
def create_circuit(self, n_qubits: int) -> BraketCircuit:
    """Create a Braket circuit on ``n_qubits`` qubits.

    Braket circuits only know about qubits that carry an instruction, so an
    identity is placed on every qubit to fix the register size.
    """
    if n_qubits > self._get_max_qubits():
        raise ValueError(
            f"Requested {n_qubits} qubits exceeds the device limit of {self._get_max_qubits()}"
        )
    circuit = BraketCircuit()
    for q in range(n_qubits):
        circuit.add_instruction(Instruction(bg.I(), q))
    return circuit

add_gate

add_gate(circuit: Circuit, gate: str, qubits: int | list[int], params: list[float] | None = None) -> BraketCircuit

Add a quantum gate to the circuit.

Source code in src/superquantx/backends/braket_backend.py
def add_gate(self, circuit: BraketCircuit, gate: str, qubits: int | list[int],
             params: list[float] | None = None) -> BraketCircuit:
    """Add a quantum gate to the circuit."""
    if isinstance(qubits, int):
        qubits = [qubits]
    name = self._GATES.get(gate.lower())
    if name is None:
        raise ValueError(f"Gate '{gate}' not supported in Braket backend")
    gate_class = getattr(bg, name)
    if name in self._PARAMETRIC:
        if not params:
            raise ValueError(f"Gate '{gate}' needs a rotation angle")
        op = gate_class(float(params[0]))
    else:
        op = gate_class()
    target = qubits[0] if len(qubits) == 1 else list(qubits)
    circuit.add_instruction(Instruction(op, target))
    return circuit

add_measurement

add_measurement(circuit: Circuit, qubits: int | list[int] | None = None) -> BraketCircuit

Record which qubits to measure (all qubits when qubits is None).

Source code in src/superquantx/backends/braket_backend.py
def add_measurement(self, circuit: BraketCircuit, qubits: int | list[int] | None = None) -> BraketCircuit:
    """Record which qubits to measure (all qubits when ``qubits`` is None)."""
    if qubits is None:
        qubits = list(range(circuit.qubit_count))
    elif isinstance(qubits, int):
        qubits = [qubits]
    if not hasattr(circuit, '_measurement_qubits'):
        circuit._measurement_qubits = set()
    circuit._measurement_qubits.update(qubits)
    return circuit

execute_circuit

execute_circuit(circuit: Circuit, shots: int | None = None) -> dict[str, Any]

Sample the circuit. Counts are big-endian (qubit 0 is the leftmost bit).

Source code in src/superquantx/backends/braket_backend.py
def execute_circuit(self, circuit: BraketCircuit, shots: int | None = None) -> dict[str, Any]:
    """Sample the circuit. Counts are big-endian (qubit 0 is the leftmost bit)."""
    shots = shots or self.shots
    measure_qubits = sorted(getattr(circuit, '_measurement_qubits', range(circuit.qubit_count)))

    measured_circuit = circuit.copy()
    if measure_qubits != list(range(circuit.qubit_count)):
        measured_circuit.measure(measure_qubits)

    if self.s3_folder and not self.device_name.startswith('local:'):
        task = self._device.run(measured_circuit, shots=shots, s3_destination_folder=self.s3_folder)
    else:
        task = self._device.run(measured_circuit, shots=shots)
    result = task.result()
    counts = {str(k): int(v) for k, v in result.measurement_counts.items()}

    return {
        'counts': counts,
        'shots': shots,
        'success': True,
        'measurement_qubits': measure_qubits,
        'task_arn': getattr(task, 'id', 'local'),
        'device': self.device_name,
    }

create_parameterized_circuit

create_parameterized_circuit(n_qubits: int, n_params: int) -> tuple[BraketCircuit, list[str]]

Create a parameterized quantum circuit for variational algorithms.

Source code in src/superquantx/backends/braket_backend.py
def create_parameterized_circuit(self, n_qubits: int, n_params: int) -> tuple[BraketCircuit, list[str]]:
    """Create a parameterized quantum circuit for variational algorithms."""
    circuit = self.create_circuit(n_qubits)

    # Create parameter names
    param_names = [f"theta_{i}" for i in range(n_params)]

    # Store parameter info
    circuit._param_names = param_names
    circuit._n_params = n_params

    return circuit, param_names

get_backend_info

get_backend_info() -> dict[str, Any]

Get information about the Braket backend.

Source code in src/superquantx/backends/braket_backend.py
def get_backend_info(self) -> dict[str, Any]:
    """Get information about the Braket backend."""
    info = {
        'backend_name': 'braket',
        'device': self.device_name,
        'provider': 'AWS Braket',
        'shots': self.shots,
        'capabilities': self.capabilities,
        'local_simulator': self.device_name.startswith('local:'),
    }

    if hasattr(self._device, 'properties'):
        try:
            props = self._device.properties
            info.update({
                'device_type': getattr(props, 'deviceType', 'unknown'),
                'provider_name': getattr(props, 'providerName', 'AWS'),
                'max_qubits': getattr(props.paradigm, 'qubit_count', 'unknown') if hasattr(props, 'paradigm') else 'unknown',
            })
        except (AttributeError, Exception):
            pass

    return info

get_version_info

get_version_info() -> dict[str, str]

Get version information for Braket dependencies.

Source code in src/superquantx/backends/braket_backend.py
def get_version_info(self) -> dict[str, str]:
    """Get version information for Braket dependencies."""
    from importlib.metadata import PackageNotFoundError, version
    try:
        sdk = version('amazon-braket-sdk')
    except PackageNotFoundError:
        sdk = 'unknown'
    return {'braket_sdk': sdk, 'backend_version': '1.0.0'}

is_available

is_available() -> bool

Check if the backend is available and properly configured.

Source code in src/superquantx/backends/braket_backend.py
def is_available(self) -> bool:
    """Check if the backend is available and properly configured."""
    return BRAKET_AVAILABLE and self._device is not None

get_circuit_info

get_circuit_info() -> dict[str, Any]

Get information about circuit execution capabilities.

Source code in src/superquantx/backends/braket_backend.py
def get_circuit_info(self) -> dict[str, Any]:
    """Get information about circuit execution capabilities."""
    return {
        'max_qubits': self._get_max_qubits(),
        'native_gates': self._get_native_gates(),
        'supports_mid_circuit_measurement': False,
        'supports_reset': False,
        'supports_conditional': False,
    }

get_statevector

get_statevector(circuit: Circuit) -> np.ndarray

Exact statevector (big-endian) from Braket's local state-vector simulator.

Source code in src/superquantx/backends/braket_backend.py
def get_statevector(self, circuit: BraketCircuit) -> np.ndarray:
    """Exact statevector (big-endian) from Braket's local state-vector simulator."""
    sv_circuit = BraketCircuit()
    for instr in circuit.instructions:
        if not isinstance(instr.operator, Measure):
            sv_circuit.add_instruction(instr)
    sv_circuit.state_vector()
    result = LocalSimulator('braket_sv').run(sv_circuit, shots=0).result()
    return np.asarray(result.values[0], dtype=complex)

TKET/Quantinuum Backend

superquantx.backends.TKETBackend

TKETBackend(device: str = 'aer_simulator', shots: int = 1024, machine: str | None = None, api_key: str | None = None, **kwargs)

Bases: BaseBackend

TKET (Quantum Toolkit) backend for quantum computing operations.

This backend provides access to TKET's quantum circuit compilation, optimization, and execution capabilities, including Quantinuum hardware.

Parameters:

Name Type Description Default
device str

Device name (e.g., 'aer_simulator', 'H1-1E', 'H1-2E', 'simulator')

'aer_simulator'
shots int

Number of measurement shots

1024
machine str | None

Specific Quantinuum machine for hardware execution

None
api_key str | None

Quantinuum API key (required for hardware)

None
**kwargs

Additional backend configuration

{}
Example

Local simulator

backend = TKETBackend(device='aer_simulator')

Quantinuum hardware (requires API key)

backend = TKETBackend( ... device='H1-1E', ... api_key='your-quantinuum-api-key' ... )

Source code in src/superquantx/backends/tket_backend.py
def __init__(
    self,
    device: str = 'aer_simulator',
    shots: int = 1024,
    machine: str | None = None,
    api_key: str | None = None,
    **kwargs
) -> None:
    if not TKET_AVAILABLE:
        raise ImportError(
            "TKET not available. Install with: pip install pytket"
        )

    self.device_name = device
    self.machine = machine or device
    self.api_key = api_key
    self._backend = None

    super().__init__(device=device, shots=shots, **kwargs)

Functions

create_circuit

create_circuit(n_qubits: int) -> Circuit

Create a TKET quantum circuit.

Source code in src/superquantx/backends/tket_backend.py
def create_circuit(self, n_qubits: int) -> Circuit:
    """Create a TKET quantum circuit."""
    if n_qubits > self._get_max_qubits():
        logger.warning(f"Requested {n_qubits} qubits exceeds device limit")

    circuit = Circuit(n_qubits)
    return circuit

add_gate

add_gate(circuit: Circuit, gate: str, qubits: int | list[int], params: list[float] | None = None) -> Circuit

Add a gate. Angles are given in radians (converted to TKET half-turns).

Source code in src/superquantx/backends/tket_backend.py
def add_gate(self, circuit: Circuit, gate: str, qubits: int | list[int],
             params: list[float] | None = None) -> Circuit:
    """Add a gate. Angles are given in radians (converted to TKET half-turns)."""
    if isinstance(qubits, int):
        qubits = [qubits]
    name = self._GATES.get(gate.lower())
    if name is None:
        raise ValueError(f"Gate '{gate}' not supported in TKET backend")
    op_type = getattr(OpType, name)
    tket_qubits = [circuit.qubits[q] for q in qubits]
    if params:
        circuit.add_gate(op_type, [float(p) / np.pi for p in params], tket_qubits)
    else:
        circuit.add_gate(op_type, tket_qubits)
    return circuit

add_measurement

add_measurement(circuit: Circuit, qubits: int | list[int] | None = None) -> Circuit

Measure qubits (all qubits by default) into classical bits 0..k-1.

Source code in src/superquantx/backends/tket_backend.py
def add_measurement(self, circuit: Circuit, qubits: int | list[int] | None = None) -> Circuit:
    """Measure ``qubits`` (all qubits by default) into classical bits 0..k-1."""
    if qubits is None:
        qubits = list(range(circuit.n_qubits))
    elif isinstance(qubits, int):
        qubits = [qubits]
    if circuit.n_bits < len(qubits):
        circuit.add_c_register("c", len(qubits) - circuit.n_bits)
    for i, qubit in enumerate(qubits):
        circuit.Measure(circuit.qubits[qubit], circuit.bits[i])
    return circuit

execute_circuit

execute_circuit(circuit: Circuit, shots: int | None = None) -> dict[str, Any]

Compile and run the circuit. Counts are big-endian (bit 0 is the leftmost character).

Unmeasured circuits get all qubits measured on a copy.

Source code in src/superquantx/backends/tket_backend.py
def execute_circuit(self, circuit: Circuit, shots: int | None = None) -> dict[str, Any]:
    """Compile and run the circuit. Counts are big-endian (bit 0 is the leftmost character).

    Unmeasured circuits get all qubits measured on a copy.
    """
    shots = shots or self.shots
    if circuit.n_gates_of_type(OpType.Measure) == 0:
        circuit = circuit.copy()
        circuit.measure_all()
    compiled_circuit = self._backend.get_compiled_circuit(circuit)
    handle = self._backend.process_circuit(compiled_circuit, n_shots=shots)
    result = self._backend.get_result(handle)
    counts = {''.join(str(int(b)) for b in key): int(v) for key, v in result.get_counts().items()}
    return {
        'counts': counts,
        'shots': shots,
        'success': True,
        'backend': self._backend.__class__.__name__,
        'compiled': True,
        'device': self.device_name,
    }

optimize_circuit

optimize_circuit(circuit: Circuit, optimization_level: int = 2) -> Circuit

Optimize quantum circuit using TKET compiler passes.

Source code in src/superquantx/backends/tket_backend.py
def optimize_circuit(self, circuit: Circuit, optimization_level: int = 2) -> Circuit:
    """Optimize quantum circuit using TKET compiler passes."""
    try:
        from pytket.passes import (
            CliffordSimp,
            DecomposeBoxes,
            OptimisePhaseGadgets,
            RemoveRedundancies,
            SequencePass,
        )

        optimized = circuit.copy()

        if optimization_level >= 1:
            # Basic optimization
            basic_pass = SequencePass([
                DecomposeBoxes(),
                CliffordSimp(),
                RemoveRedundancies()
            ])
            basic_pass.apply(optimized)

        if optimization_level >= 2:
            # Advanced optimization
            advanced_pass = SequencePass([
                OptimisePhaseGadgets(),
                CliffordSimp(),
                RemoveRedundancies()
            ])
            advanced_pass.apply(optimized)

        if optimization_level >= 3 and self._backend:
            # Backend-specific optimization
            backend_pass = self._backend.default_compilation_pass()
            backend_pass.apply(optimized)

        logger.info(f"Circuit optimized: {circuit.n_gates} -> {optimized.n_gates} gates")
        return optimized

    except Exception as e:
        logger.error(f"Circuit optimization failed: {e}")
        return circuit

get_backend_info

get_backend_info() -> dict[str, Any]

Get information about the TKET backend.

Source code in src/superquantx/backends/tket_backend.py
def get_backend_info(self) -> dict[str, Any]:
    """Get information about the TKET backend."""
    info = {
        'backend_name': 'tket',
        'device': self.device_name,
        'provider': 'Quantinuum/Cambridge Quantum Computing',
        'shots': self.shots,
        'capabilities': self.capabilities,
    }

    if self._backend:
        info.update({
            'backend_class': self._backend.__class__.__name__,
            'supports_compilation': True,
            'supports_optimization': True,
        })

        if hasattr(self._backend, 'device'):
            device_info = self._backend.device
            info['device_info'] = str(device_info)

    return info

get_version_info

get_version_info() -> dict[str, str]

Get version information for TKET dependencies.

Source code in src/superquantx/backends/tket_backend.py
def get_version_info(self) -> dict[str, str]:
    """Get version information for TKET dependencies."""
    version_info = {'backend_version': '1.0.0'}

    try:
        import pytket
        version_info['pytket'] = pytket.__version__
    except (ImportError, AttributeError):
        pass

    if QUANTINUUM_AVAILABLE:
        try:
            import pytket.extensions.quantinuum
            version_info['pytket_quantinuum'] = getattr(pytket.extensions.quantinuum, '__version__', 'unknown')
        except (ImportError, AttributeError):
            pass

    return version_info

is_available

is_available() -> bool

Check if the backend is available and properly configured.

Source code in src/superquantx/backends/tket_backend.py
def is_available(self) -> bool:
    """Check if the backend is available and properly configured."""
    return TKET_AVAILABLE

get_circuit_info

get_circuit_info() -> dict[str, Any]

Get information about circuit execution capabilities.

Source code in src/superquantx/backends/tket_backend.py
def get_circuit_info(self) -> dict[str, Any]:
    """Get information about circuit execution capabilities."""
    return {
        'max_qubits': self._get_max_qubits(),
        'native_gates': self._get_native_gates(),
        'supports_mid_circuit_measurement': True,
        'supports_reset': True,
        'supports_conditional': True,
        'supports_optimization': True,
        'supports_compilation': True,
    }

get_statevector

get_statevector(circuit: Circuit) -> np.ndarray

Exact statevector (big-endian) computed by pytket, ignoring measurements.

Source code in src/superquantx/backends/tket_backend.py
def get_statevector(self, circuit: Circuit) -> np.ndarray:
    """Exact statevector (big-endian) computed by pytket, ignoring measurements."""
    clean = Circuit(circuit.n_qubits)
    for cmd in circuit.get_commands():
        if cmd.op.type == OpType.Measure:
            continue
        clean.add_gate(cmd.op, cmd.args)
    return np.asarray(clean.get_statevector(), dtype=complex)

D-Wave Ocean Backend

superquantx.backends.OceanBackend

OceanBackend(device: str = 'simulator', solver: str | None = None, token: str | None = None, endpoint: str | None = None, shots: int = 1000, **kwargs)

Bases: BaseBackend

D-Wave Ocean backend for quantum annealing operations.

This backend provides access to D-Wave's quantum annealing systems for solving optimization problems formulated as QUBO or Ising models.

Note: Unlike gate-model quantum computers, D-Wave systems solve optimization problems rather than running quantum circuits.

Parameters:

Name Type Description Default
device str

Sampler type ('DWave', 'hybrid', 'simulator', 'advantage')

'simulator'
solver str | None

Specific solver name (optional)

None
token str | None

D-Wave API token (required for hardware)

None
endpoint str | None

D-Wave API endpoint

None
shots int

Number of samples (reads)

1000
**kwargs

Additional sampler configuration

{}
Example

Simulated annealing (no hardware required)

backend = OceanBackend(device='simulator')

D-Wave hardware (requires API token)

backend = OceanBackend( ... device='advantage', ... token='your-dwave-token' ... )

Source code in src/superquantx/backends/ocean_backend.py
def __init__(
    self,
    device: str = 'simulator',
    solver: str | None = None,
    token: str | None = None,
    endpoint: str | None = None,
    shots: int = 1000,  # Called "num_reads" in D-Wave
    **kwargs
) -> None:
    if not OCEAN_AVAILABLE:
        raise ImportError(
            "D-Wave Ocean not available. Install with: pip install dwave-ocean-sdk"
        )

    self.device_name = device
    self.solver_name = solver
    self.token = token
    self.endpoint = endpoint
    self.num_reads = shots
    self._sampler = None
    self._is_quantum_annealing = True  # This backend is for annealing, not gates
    self.gate_model = False

    super().__init__(device=device, shots=shots, **kwargs)

Functions

solve_qubo

solve_qubo(Q: dict[tuple[int, int], float], **kwargs) -> dict[str, Any]

Solve a Quadratic Unconstrained Binary Optimization (QUBO) problem.

Parameters:

Name Type Description Default
Q dict[tuple[int, int], float]

QUBO dictionary where keys are (i, j) variable pairs and values are coefficients

required
**kwargs

Additional solving parameters

{}

Returns:

Type Description
dict[str, Any]

Solution results with energies and samples

Source code in src/superquantx/backends/ocean_backend.py
def solve_qubo(self, Q: dict[tuple[int, int], float], **kwargs) -> dict[str, Any]:
    """Solve a Quadratic Unconstrained Binary Optimization (QUBO) problem.

    Args:
        Q: QUBO dictionary where keys are (i, j) variable pairs and values are coefficients
        **kwargs: Additional solving parameters

    Returns:
        Solution results with energies and samples

    """
    try:
        num_reads = kwargs.pop('num_reads', self.num_reads)

        # Create BQM from QUBO
        bqm = dimod.BinaryQuadraticModel.from_qubo(Q)

        # Sample from the BQM
        sampleset = self._sampler.sample(bqm, num_reads=num_reads, **kwargs)

        # Convert results to standard format
        results = {
            'samples': [],
            'energies': [],
            'num_occurrences': [],
            'success': True,
            'num_reads': len(sampleset),
            'timing': getattr(sampleset, 'info', {}).get('timing', {}),
            'problem_type': 'QUBO'
        }

        for sample, energy, num_occur in sampleset.data(['sample', 'energy', 'num_occurrences']):
            results['samples'].append(dict(sample))
            results['energies'].append(energy)
            results['num_occurrences'].append(num_occur)

        return results

    except Exception as e:
        logger.error(f"QUBO solving failed: {e}")
        return {
            'samples': [],
            'energies': [],
            'success': False,
            'error': str(e),
            'problem_type': 'QUBO'
        }

solve_ising

solve_ising(h: dict[int, float], J: dict[tuple[int, int], float], **kwargs) -> dict[str, Any]

Solve an Ising model problem.

Parameters:

Name Type Description Default
h dict[int, float]

Linear coefficients (bias terms) for each variable

required
J dict[tuple[int, int], float]

Quadratic coefficients (coupling terms) between variables

required
**kwargs

Additional solving parameters

{}

Returns:

Type Description
dict[str, Any]

Solution results with energies and samples

Source code in src/superquantx/backends/ocean_backend.py
def solve_ising(self, h: dict[int, float], J: dict[tuple[int, int], float], **kwargs) -> dict[str, Any]:
    """Solve an Ising model problem.

    Args:
        h: Linear coefficients (bias terms) for each variable
        J: Quadratic coefficients (coupling terms) between variables
        **kwargs: Additional solving parameters

    Returns:
        Solution results with energies and samples

    """
    try:
        num_reads = kwargs.pop('num_reads', self.num_reads)

        # Create BQM from Ising model
        bqm = dimod.BinaryQuadraticModel.from_ising(h, J)

        # Sample from the BQM
        sampleset = self._sampler.sample(bqm, num_reads=num_reads, **kwargs)

        # Convert results to standard format
        results = {
            'samples': [],
            'energies': [],
            'num_occurrences': [],
            'success': True,
            'num_reads': len(sampleset),
            'timing': getattr(sampleset, 'info', {}).get('timing', {}),
            'problem_type': 'Ising'
        }

        for sample, energy, num_occur in sampleset.data(['sample', 'energy', 'num_occurrences']):
            results['samples'].append(dict(sample))
            results['energies'].append(energy)
            results['num_occurrences'].append(num_occur)

        return results

    except Exception as e:
        logger.error(f"Ising model solving failed: {e}")
        return {
            'samples': [],
            'energies': [],
            'success': False,
            'error': str(e),
            'problem_type': 'Ising'
        }

solve_optimization_problem

solve_optimization_problem(problem: dict | Any, problem_type: str = 'auto') -> dict[str, Any]

Generic optimization problem solver.

Parameters:

Name Type Description Default
problem dict | Any

Problem specification (QUBO dict, Ising model, or BQM)

required
problem_type str

Type of problem ('qubo', 'ising', 'bqm', 'auto')

'auto'

Returns:

Type Description
dict[str, Any]

Solution results

Source code in src/superquantx/backends/ocean_backend.py
def solve_optimization_problem(self, problem: dict | Any, problem_type: str = 'auto') -> dict[str, Any]:
    """Generic optimization problem solver.

    Args:
        problem: Problem specification (QUBO dict, Ising model, or BQM)
        problem_type: Type of problem ('qubo', 'ising', 'bqm', 'auto')

    Returns:
        Solution results

    """
    try:
        if problem_type == 'auto':
            # Try to detect problem type
            if isinstance(problem, dict) and all(len(k) == 2 for k in problem.keys()):
                problem_type = 'qubo'
            elif hasattr(problem, 'linear') and hasattr(problem, 'quadratic'):
                problem_type = 'bqm'
            else:
                raise ValueError("Cannot auto-detect problem type")

        if problem_type == 'qubo':
            return self.solve_qubo(problem)
        elif problem_type == 'ising':
            h, J = problem  # Expecting tuple (h, J)
            return self.solve_ising(h, J)
        elif problem_type == 'bqm':
            # Direct BQM solving
            sampleset = self._sampler.sample(problem, num_reads=self.num_reads)
            return self._convert_sampleset(sampleset, problem_type)
        else:
            raise ValueError(f"Unknown problem type: {problem_type}")

    except Exception as e:
        logger.error(f"Optimization problem solving failed: {e}")
        return {
            'samples': [],
            'energies': [],
            'success': False,
            'error': str(e),
            'problem_type': problem_type
        }

create_circuit

create_circuit(n_qubits: int) -> dict[str, Any]

Not supported: annealers do not run gate-model circuits.

Source code in src/superquantx/backends/ocean_backend.py
def create_circuit(self, n_qubits: int) -> dict[str, Any]:
    """Not supported: annealers do not run gate-model circuits."""
    raise NotImplementedError(self._NOT_GATE_MODEL)

add_gate

add_gate(circuit: dict, gate: str, qubits: int | list[int], params: list[float] | None = None) -> dict

Not supported: annealers do not run gate-model circuits.

Source code in src/superquantx/backends/ocean_backend.py
def add_gate(self, circuit: dict, gate: str, qubits: int | list[int],
             params: list[float] | None = None) -> dict:
    """Not supported: annealers do not run gate-model circuits."""
    raise NotImplementedError(self._NOT_GATE_MODEL)

add_measurement

add_measurement(circuit: dict, qubits: int | list[int] | None = None) -> dict

Not supported: annealers do not run gate-model circuits.

Source code in src/superquantx/backends/ocean_backend.py
def add_measurement(self, circuit: dict, qubits: int | list[int] | None = None) -> dict:
    """Not supported: annealers do not run gate-model circuits."""
    raise NotImplementedError(self._NOT_GATE_MODEL)

execute_circuit

execute_circuit(circuit: dict, shots: int | None = None) -> dict[str, Any]

Not supported: annealers do not run gate-model circuits.

Source code in src/superquantx/backends/ocean_backend.py
def execute_circuit(self, circuit: dict, shots: int | None = None) -> dict[str, Any]:
    """Not supported: annealers do not run gate-model circuits."""
    raise NotImplementedError(self._NOT_GATE_MODEL)

get_backend_info

get_backend_info() -> dict[str, Any]

Get information about the D-Wave Ocean backend.

Source code in src/superquantx/backends/ocean_backend.py
def get_backend_info(self) -> dict[str, Any]:
    """Get information about the D-Wave Ocean backend."""
    info = {
        'backend_name': 'ocean',
        'device': self.device_name,
        'provider': 'D-Wave Systems',
        'num_reads': self.num_reads,
        'capabilities': self.capabilities,
        'quantum_annealing': True,
        'gate_model': False,
    }

    if self._sampler and hasattr(self._sampler, 'properties'):
        try:
            props = self._sampler.properties
            info.update({
                'solver_name': getattr(self._sampler, 'solver', {}).get('name', 'unknown'),
                'num_qubits': len(props.get('qubits', [])),
                'connectivity': 'Chimera/Pegasus/Zephyr',  # D-Wave topologies
            })
        except (AttributeError, Exception):
            pass

    return info

get_version_info

get_version_info() -> dict[str, str]

Get version information for Ocean dependencies.

Source code in src/superquantx/backends/ocean_backend.py
def get_version_info(self) -> dict[str, str]:
    """Get version information for Ocean dependencies."""
    version_info = {'backend_version': '1.0.0'}

    try:
        version_info['dimod'] = dimod.__version__
    except (AttributeError, ImportError):
        pass

    try:
        import dwave.system
        version_info['dwave_system'] = dwave.system.__version__
    except (ImportError, AttributeError):
        pass

    try:
        import dwave.samplers
        version_info['dwave_samplers'] = dwave.samplers.__version__
    except (ImportError, AttributeError):
        pass

    return version_info

is_available

is_available() -> bool

Check if the backend is available and properly configured.

Source code in src/superquantx/backends/ocean_backend.py
def is_available(self) -> bool:
    """Check if the backend is available and properly configured."""
    return OCEAN_AVAILABLE and self._sampler is not None

get_circuit_info

get_circuit_info() -> dict[str, Any]

Get circuit capabilities (limited for annealing backend).

Source code in src/superquantx/backends/ocean_backend.py
def get_circuit_info(self) -> dict[str, Any]:
    """Get circuit capabilities (limited for annealing backend)."""
    return {
        'max_qubits': 0,  # Not applicable
        'max_variables': self._get_max_variables(),
        'native_gates': [],  # Not applicable
        'supports_mid_circuit_measurement': False,
        'supports_reset': False,
        'supports_conditional': False,
        'supports_optimization': True,
        'quantum_annealing': True,
    }

get_statevector

get_statevector(circuit: dict) -> np.ndarray

Not supported: annealers have no gate-model statevector.

Source code in src/superquantx/backends/ocean_backend.py
def get_statevector(self, circuit: dict) -> np.ndarray:
    """Not supported: annealers have no gate-model statevector."""
    raise NotImplementedError(self._NOT_GATE_MODEL)

solve_max_cut

solve_max_cut(graph: Any | list[tuple], **kwargs) -> dict[str, Any]

Solve Maximum Cut problem on a graph.

Source code in src/superquantx/backends/ocean_backend.py
def solve_max_cut(self, graph: Any | list[tuple], **kwargs) -> dict[str, Any]:
    """Solve Maximum Cut problem on a graph."""
    try:
        if not nx:
            raise ImportError("NetworkX not available for graph operations")

        if isinstance(graph, list):
            # Convert edge list to networkx graph
            G = nx.Graph()
            G.add_edges_from(graph)
        else:
            G = graph

        # cut(x) = sum_ij w_ij (x_i + x_j - 2 x_i x_j); samplers minimise energy,
        # so the QUBO is -cut(x) and the lowest energy is the maximum cut.
        Q = {}
        for i, j, data in G.edges(data=True):
            w = data.get('weight', 1.0)
            Q[(i, i)] = Q.get((i, i), 0) - w
            Q[(j, j)] = Q.get((j, j), 0) - w
            Q[(i, j)] = Q.get((i, j), 0) + 2 * w

        result = self.solve_qubo(Q, **kwargs)
        if result.get('success') and result['energies']:
            best = int(np.argmin(result['energies']))
            result['best_sample'] = result['samples'][best]
            result['best_cut_value'] = -float(result['energies'][best])
        return result

    except Exception as e:
        logger.error(f"Max Cut solving failed: {e}")
        return {'success': False, 'error': str(e)}

solve_tsp

solve_tsp(distance_matrix: ndarray, **kwargs) -> dict[str, Any]

Not implemented: a correct TSP QUBO needs one-hot constraints (planned).

Source code in src/superquantx/backends/ocean_backend.py
def solve_tsp(self, distance_matrix: np.ndarray, **kwargs) -> dict[str, Any]:
    """Not implemented: a correct TSP QUBO needs one-hot constraints (planned)."""
    raise NotImplementedError(
        "TSP is not implemented yet; formulate it as a QUBO with one-hot "
        "penalties and call solve_qubo()."
    )

Utility Functions

Backend Management

superquantx.backends.get_backend

get_backend(backend: str | BaseBackend, **kwargs) -> BaseBackend

Get a quantum backend instance.

Parameters:

Name Type Description Default
backend str | BaseBackend

Backend name or instance

required
**kwargs

Backend configuration parameters

{}

Returns:

Type Description
BaseBackend

Backend instance

Raises:

Type Description
ValueError

If backend is not supported

ImportError

If backend dependencies are missing

Example

backend = get_backend('pennylane', device='default.qubit') backend = get_backend('qiskit', provider='IBMQ')

Source code in src/superquantx/backends/__init__.py
def get_backend(backend: str | BaseBackend, **kwargs) -> BaseBackend:
    """Get a quantum backend instance.

    Args:
        backend: Backend name or instance
        **kwargs: Backend configuration parameters

    Returns:
        Backend instance

    Raises:
        ValueError: If backend is not supported
        ImportError: If backend dependencies are missing

    Example:
        >>> backend = get_backend('pennylane', device='default.qubit')
        >>> backend = get_backend('qiskit', provider='IBMQ')

    """
    if isinstance(backend, BaseBackend):
        return backend

    if not isinstance(backend, str):
        raise ValueError(f"Backend must be string or BaseBackend instance, got {type(backend)}")

    # Resolve aliases
    backend_name = BACKEND_ALIASES.get(backend.lower(), backend.lower())

    # Auto-select backend if requested
    if backend_name == 'auto':
        backend_name = _auto_select_backend()

    # Get backend class
    if backend_name not in BACKEND_REGISTRY:
        available = list(BACKEND_REGISTRY.keys())
        raise ValueError(f"Backend '{backend_name}' not supported. Available: {available}")

    backend_class = BACKEND_REGISTRY[backend_name]

    try:
        logger.info(f"Initializing {backend_name} backend")
        return backend_class(**kwargs)
    except ImportError as e:
        logger.error(f"Failed to import {backend_name} backend: {e}")
        raise ImportError(f"Backend '{backend_name}' requires additional dependencies: {e}")
    except Exception as e:
        logger.error(f"Failed to initialize {backend_name} backend: {e}")
        raise

superquantx.backends.list_available_backends

list_available_backends() -> dict[str, dict[str, Any]]

List all available backends and their status.

Returns:

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

Dictionary with backend information

Source code in src/superquantx/backends/__init__.py
def list_available_backends() -> dict[str, dict[str, Any]]:
    """List all available backends and their status.

    Returns:
        Dictionary with backend information

    """
    backend_info = {}

    for name, backend_class in BACKEND_REGISTRY.items():
        if name == 'auto' or backend_class is None:
            continue

        try:
            # Try to instantiate to check availability
            test_instance = backend_class()
            backend_info[name] = {
                'available': True,
                'class': backend_class.__name__,
                'description': getattr(backend_class, '__doc__', '').split('\n')[0] if backend_class.__doc__ else '',
                'capabilities': getattr(test_instance, 'capabilities', {}),
                'gate_model': getattr(test_instance, 'gate_model', True),
            }
        except ImportError:
            backend_info[name] = {
                'available': False,
                'class': backend_class.__name__,
                'reason': 'Missing dependencies',
            }
        except Exception as e:
            backend_info[name] = {
                'available': False,
                'class': backend_class.__name__,
                'reason': str(e),
            }

    return backend_info

superquantx.backends.check_backend_compatibility

check_backend_compatibility(backend_name: str) -> dict[str, Any]

Check compatibility and requirements for a specific backend.

Parameters:

Name Type Description Default
backend_name str

Name of the backend to check

required

Returns:

Type Description
dict[str, Any]

Compatibility information

Source code in src/superquantx/backends/__init__.py
def check_backend_compatibility(backend_name: str) -> dict[str, Any]:
    """Check compatibility and requirements for a specific backend.

    Args:
        backend_name: Name of the backend to check

    Returns:
        Compatibility information

    """
    backend_name = BACKEND_ALIASES.get(backend_name.lower(), backend_name.lower())

    if backend_name not in BACKEND_REGISTRY:
        return {'compatible': False, 'reason': 'Backend not supported'}

    backend_class = BACKEND_REGISTRY[backend_name]

    try:
        # Try basic instantiation
        test_backend = backend_class()

        return {
            'compatible': True,
            'backend_class': backend_class.__name__,
            'requirements_met': True,
            'capabilities': getattr(test_backend, 'capabilities', {}),
            'version_info': getattr(test_backend, 'get_version_info', lambda: {})(),
        }

    except ImportError as e:
        return {
            'compatible': False,
            'reason': 'Missing dependencies',
            'missing_packages': str(e),
            'requirements_met': False,
        }
    except Exception as e:
        return {
            'compatible': False,
            'reason': str(e),
            'requirements_met': False,
        }

Backend Selection Guide

By Use Case

Development & Prototyping

# Fast local simulation
backend = sqx.get_backend('simulator', max_qubits=10)

# Cross-platform testing
backend = sqx.get_backend('pennylane', device='default.qubit')

Production & Research

# IBM Quantum hardware
backend = sqx.get_backend('qiskit', device='ibmq_manila', token='your-token')

# Google Quantum AI
backend = sqx.get_backend('cirq', processor_id='rainbow', project_id='your-project')

# AWS Braket cloud
backend = sqx.get_backend('braket', device_arn='arn:aws:braket:us-east-1::device/qpu/ionq/ionQdevice')

Specialized Applications

# Quantum chemistry (TKET optimization)
backend = sqx.get_backend('tket', device='H1-1E', api_key='quantinuum-key')

# Optimization problems (D-Wave annealing)
backend = sqx.get_backend('ocean', device='advantage', token='dwave-token')

By Performance Requirements

High Accuracy (Large Shot Counts)

backends_high_accuracy = {
    'simulator': sqx.get_backend('simulator', shots=100000),
    'ibm_hardware': sqx.get_backend('qiskit', device='ibmq_montreal', shots=8192),
    'aws_sv1': sqx.get_backend('braket', device='sv1', shots=100000)
}

Fast Iteration (Low Latency)

backends_fast = {
    'local_sim': sqx.get_backend('simulator', shots=1000),
    'pennylane': sqx.get_backend('pennylane', device='lightning.qubit'),
    'braket_local': sqx.get_backend('braket', device='braket_sv')
}

Cost Optimization

# Free tier resources
free_backends = {
    'simulator': sqx.get_backend('simulator'),
    'ibm_free': sqx.get_backend('qiskit', device='ibmq_qasm_simulator'),
    'aws_sim': sqx.get_backend('braket', device='braket_sv')  # First 1 hour free
}

Integration Examples

Multi-Backend Algorithm Testing

import superquantx as sqx

def test_algorithm_across_backends(algorithm_func, backends, *args, **kwargs):
    """Test quantum algorithm across multiple backends."""

    results = {}

    for backend_name, backend in backends.items():
        try:
            print(f"Testing on {backend_name}...")

            # Run algorithm
            result = algorithm_func(backend, *args, **kwargs)
            results[backend_name] = result

            print(f"  ✓ Success: {result}")

        except Exception as e:
            print(f"  ✗ Failed: {e}")
            results[backend_name] = None

    return results

# Define test backends
test_backends = {
    'simulator': sqx.get_backend('simulator'),
    'pennylane': sqx.get_backend('pennylane', device='default.qubit'),
}

# Example quantum algorithm
def simple_bell_state(backend):
    circuit = backend.create_circuit(2)
    circuit = backend.add_gate(circuit, 'h', 0)
    circuit = backend.add_gate(circuit, 'cx', [0, 1])
    return backend.execute_circuit(circuit)

# Test across backends
results = test_algorithm_across_backends(simple_bell_state, test_backends)

Backend Fallback Strategy

def get_backend_with_fallback(preferences, **kwargs):
    """Get backend with fallback strategy."""

    for backend_name in preferences:
        try:
            backend = sqx.get_backend(backend_name, **kwargs)
            if backend.is_available():
                print(f"Using backend: {backend_name}")
                return backend
        except Exception as e:
            print(f"Backend {backend_name} failed: {e}")
            continue

    raise RuntimeError("No backends available")

# Usage
backend = get_backend_with_fallback([
    'qiskit',      # Try IBM first
    'pennylane',   # Fallback to PennyLane  
    'simulator'    # Final fallback
], shots=1024)

Performance Benchmarking

import time
import numpy as np

def benchmark_backends(backends, circuit_sizes=[2, 4, 6, 8]):
    """Benchmark quantum backends across different circuit sizes."""

    results = {}

    for backend_name, backend in backends.items():
        print(f"\nBenchmarking {backend_name}:")
        results[backend_name] = {}

        for n_qubits in circuit_sizes:
            if n_qubits > backend.get_backend_info().get('capabilities', {}).get('max_qubits', 32):
                continue

            # Create test circuit
            circuit = backend.create_circuit(n_qubits)

            # Add random gates
            for _ in range(n_qubits * 2):
                qubit = np.random.randint(0, n_qubits)
                circuit = backend.add_gate(circuit, 'h', qubit)

            for _ in range(n_qubits - 1):
                q1, q2 = np.random.choice(n_qubits, 2, replace=False)
                circuit = backend.add_gate(circuit, 'cx', [q1, q2])

            # Benchmark execution
            start_time = time.time()
            try:
                result = backend.execute_circuit(circuit, shots=1000)
                execution_time = time.time() - start_time

                results[backend_name][n_qubits] = {
                    'time': execution_time,
                    'success': result.get('success', True),
                    'total_counts': sum(result.get('counts', {}).values())
                }

                print(f"  {n_qubits} qubits: {execution_time:.3f}s")

            except Exception as e:
                print(f"  {n_qubits} qubits: Failed - {e}")
                results[backend_name][n_qubits] = {'error': str(e)}

    return results

# Run benchmark
benchmark_backends({
    'simulator': sqx.get_backend('simulator'),
    'pennylane': sqx.get_backend('pennylane'),
})

Backend Configuration

Environment Setup

import os
import superquantx as sqx

# Configure backends via environment variables
os.environ['QISKIT_IBMQ_TOKEN'] = 'your-ibm-token'
os.environ['BRAKET_AWS_REGION'] = 'us-east-1'
os.environ['DWAVE_API_TOKEN'] = 'your-dwave-token'

# Test configurations
def validate_backend_config():
    """Validate backend configurations."""

    configs = {
        'qiskit': {
            'required_env': ['QISKIT_IBMQ_TOKEN'],
            'test_device': 'ibmq_qasm_simulator'
        },
        'braket': {
            'required_env': ['AWS_ACCESS_KEY_ID', 'AWS_SECRET_ACCESS_KEY'],
            'test_device': 'braket_sv'
        },
        'ocean': {
            'required_env': ['DWAVE_API_TOKEN'],
            'test_device': 'simulator'
        }
    }

    for backend_name, config in configs.items():
        print(f"Validating {backend_name}:")

        # Check environment variables
        missing_env = [env for env in config['required_env'] 
                      if not os.getenv(env)]

        if missing_env:
            print(f"  ✗ Missing environment variables: {missing_env}")
            continue

        # Test backend creation
        try:
            backend = sqx.get_backend(backend_name, device=config['test_device'])
            if backend.is_available():
                print(f"  ✓ Backend available")
            else:
                print(f"  ✗ Backend not available")
        except Exception as e:
            print(f"  ✗ Configuration error: {e}")

validate_backend_config()

Custom Backend Configuration

# Advanced backend configuration
backend_configs = {
    'qiskit_optimized': {
        'backend_type': 'qiskit',
        'device': 'ibmq_montreal',
        'shots': 4096,
        'optimization_level': 3,
        'error_mitigation': True,
        'noise_model': 'device_noise'
    },

    'pennylane_gpu': {
        'backend_type': 'pennylane', 
        'device': 'lightning.gpu',
        'shots': 100000,
        'batch_size': 1024
    },

    'braket_cost_optimized': {
        'backend_type': 'braket',
        'device': 'sv1',  # Simulator for cost optimization
        'shots': 1000,
        'max_parallel_tasks': 5
    }
}

def create_configured_backend(config_name):
    """Create backend from configuration."""
    config = backend_configs[config_name]
    backend_type = config.pop('backend_type')
    return sqx.get_backend(backend_type, **config)

Error Handling

Backend-Specific Error Handling

from superquantx.exceptions import (
    QuantumBackendError, 
    DeviceOfflineError,
    AuthenticationError,
    ResourceExhaustedError
)

def robust_backend_execution(backend, circuit, max_retries=3):
    """Execute circuit with comprehensive error handling."""

    for attempt in range(max_retries):
        try:
            result = backend.execute_circuit(circuit)
            return result

        except AuthenticationError:
            print("Authentication failed - check API tokens")
            raise  # Don't retry auth errors

        except DeviceOfflineError as e:
            print(f"Device offline: {e}")
            if attempt < max_retries - 1:
                print("Waiting 30s before retry...")
                time.sleep(30)

        except ResourceExhaustedError as e:
            print(f"Resources exhausted: {e}")
            # Reduce shots and retry
            circuit.shots = max(circuit.shots // 2, 100)

        except QuantumBackendError as e:
            print(f"Backend error on attempt {attempt + 1}: {e}")
            if attempt == max_retries - 1:
                raise

    raise RuntimeError("All execution attempts failed")

# Usage with error handling
try:
    backend = sqx.get_backend('qiskit', device='ibmq_manila')
    result = robust_backend_execution(backend, circuit)
except Exception as e:
    print(f"Execution failed: {e}")
    # Fallback to simulator
    fallback_backend = sqx.get_backend('simulator')
    result = fallback_backend.execute_circuit(circuit)

Best Practices

Backend Selection Strategy

  1. Development Phase: Use simulator or pennylane for rapid iteration
  2. Testing Phase: Use cloud simulators (braket_sv, qiskit_aer) for validation
  3. Production Phase: Use real hardware with appropriate error mitigation
  4. Cost Optimization: Use free simulators when possible, batch hardware jobs

Performance Optimization

# Optimize circuit for specific backend
def optimize_for_backend(circuit, backend):
    """Optimize circuit for specific backend capabilities."""

    backend_info = backend.get_backend_info()

    if 'qiskit' in backend_info.get('backend_name', ''):
        # Use Qiskit-specific optimizations
        return backend.transpile_circuit(circuit, optimization_level=2)

    elif 'tket' in backend_info.get('backend_name', ''):
        # Use TKET optimizations
        return backend.optimize_circuit(circuit, optimization_level=3)

    elif 'ocean' in backend_info.get('backend_name', ''):
        # Ocean backends use different problem formulations
        return backend.convert_to_qubo(circuit)

    else:
        # Generic optimization
        return circuit

# Batch processing for hardware backends  
def batch_execute_circuits(backend, circuits, max_batch_size=10):
    """Execute circuits in batches for efficiency."""

    results = []

    for i in range(0, len(circuits), max_batch_size):
        batch = circuits[i:i + max_batch_size]

        if hasattr(backend, 'execute_batch'):
            # Use native batch execution if available
            batch_results = backend.execute_batch(batch)
        else:
            # Sequential execution fallback
            batch_results = [backend.execute_circuit(c) for c in batch]

        results.extend(batch_results)

    return results

For detailed backend integration guides, see: - Qiskit Integration - PennyLane Integration - Cirq Integration - Braket Integration - TKET Integration - Ocean Integration - Simulator Backend