Backends API Reference
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
|
create_feature_map
create_feature_map(n_features: int, feature_map: str, reps: int = 1) -> Any
Create quantum feature map for data encoding.
Source code in src/superquantx/backends/base_backend.py
| def create_feature_map(self, n_features: int, feature_map: str, reps: int = 1) -> Any:
"""Create quantum feature map for data encoding."""
logger.warning(f"Feature map '{feature_map}' not implemented in {self.__class__.__name__}")
return self.create_circuit(n_features)
|
compute_kernel_matrix
compute_kernel_matrix(X1: ndarray, X2: ndarray, feature_map: Any, shots: int | None = None) -> np.ndarray
Compute quantum kernel matrix between data points.
Source code in src/superquantx/backends/base_backend.py
| def compute_kernel_matrix(self, X1: np.ndarray, X2: np.ndarray,
feature_map: Any, shots: int | None = None) -> np.ndarray:
"""Compute quantum kernel matrix between data points."""
logger.warning(f"Kernel matrix computation not implemented in {self.__class__.__name__}")
# Fallback to RBF kernel
from sklearn.metrics.pairwise import rbf_kernel
return rbf_kernel(X1, X2)
|
create_ansatz
create_ansatz(ansatz_type: str, n_qubits: int, params: ndarray, include_custom_gates: bool = False) -> Any
Create parameterized ansatz circuit.
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) -> Any:
"""Create parameterized ansatz circuit."""
logger.warning(f"Ansatz '{ansatz_type}' not implemented in {self.__class__.__name__}")
return self.create_circuit(n_qubits)
|
compute_expectation
compute_expectation(circuit: Any, hamiltonian: Any, shots: int | None = None) -> float
Compute expectation value of Hamiltonian.
Source code in src/superquantx/backends/base_backend.py
| def compute_expectation(self, circuit: Any, hamiltonian: Any,
shots: int | None = None) -> float:
"""Compute expectation value of Hamiltonian."""
logger.warning(f"Expectation computation not implemented in {self.__class__.__name__}")
return 0.0
|
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
Create QAOA circuit with given parameters.
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:
"""Create QAOA circuit with given parameters."""
logger.warning(f"QAOA circuit not implemented in {self.__class__.__name__}")
return self.create_circuit(n_qubits)
|
execute_qaoa
execute_qaoa(circuit: Any, problem_hamiltonian: Any, problem_instance: Any, shots: int | None = None) -> float
Execute QAOA circuit and return expectation value.
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:
"""Execute QAOA circuit and return expectation value."""
logger.warning(f"QAOA execution not implemented in {self.__class__.__name__}")
return 0.0
|
sample_circuit
sample_circuit(circuit: Any, shots: int | None = None) -> np.ndarray
Sample bit strings from quantum circuit.
Source code in src/superquantx/backends/base_backend.py
| def sample_circuit(self, circuit: Any, shots: int | None = None) -> np.ndarray:
"""Sample bit strings from quantum circuit."""
result = self.execute_circuit(circuit, shots)
# Convert result to bit string array
return self._result_to_bitstrings(result)
|
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
Compute quantum distance between two data points.
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:
"""Compute quantum distance between two data points."""
# Encode both data points
self.encode_data_point(x1, encoding, n_qubits)
self.encode_data_point(x2, encoding, n_qubits)
# Simple distance approximation using overlap
# This is a placeholder - actual implementation would use swap test or similar
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."""
input_data.shape[0]
n_qubits = len(weights) // len(quantum_layers) if quantum_layers else 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:
# Create circuit
circuit = self.create_circuit(n_qubits)
# Encode input data
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
len(result)
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
|
|
|
{}
|
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:
logger.warning(f"Requested {n_qubits} qubits, but max is {self.max_qubits}")
n_qubits = self.max_qubits
return QuantumState(n_qubits)
|
add_gate
add_gate(circuit: QuantumState, gate: str, qubits: int | list[int], params: list[float] | None = None) -> QuantumState
Add a quantum gate to the circuit.
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:
"""Add a quantum gate to the circuit."""
if isinstance(qubits, int):
qubits = [qubits]
params = params or []
try:
# Rotation gates
if gate.upper().startswith('R'):
axis = gate.upper()[1:]
angle = params[0] if params else 0
gate_matrix = self._rotation_gate(axis, angle)
circuit.apply_gate(gate_matrix, qubits)
# Fixed gates
elif gate.upper() in self.gates:
gate_matrix = self.gates[gate.upper()]
circuit.apply_gate(gate_matrix, qubits)
# Special cases
elif gate.upper() == 'CCX' or gate.upper() == 'TOFFOLI':
# Simplified Toffoli implementation
if len(qubits) >= 3:
self._apply_toffoli(circuit, qubits[:3])
else:
logger.warning(f"Unknown gate: {gate}")
except Exception as e:
logger.error(f"Failed to add gate {gate}: {e}")
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]
Execute quantum circuit and return results.
Source code in src/superquantx/backends/simulator_backend.py
| def execute_circuit(self, circuit: QuantumState, shots: int | None = None) -> dict[str, Any]:
"""Execute quantum circuit and return results."""
shots = shots or self.shots
try:
# Measure the circuit
probabilities = np.abs(circuit.state)**2
# Sample outcomes
outcomes = np.random.choice(len(circuit.state), size=shots, p=probabilities)
# Convert to bit strings and count
counts = {}
for outcome in outcomes:
bit_string = format(outcome, f'0{circuit.n_qubits}b')
counts[bit_string] = counts.get(bit_string, 0) + 1
return {
'counts': counts,
'shots': shots,
'backend': 'python_simulator',
}
except Exception as e:
logger.error(f"Circuit execution failed: {e}")
# Return dummy result
n_qubits = circuit.n_qubits
return {
'counts': {'0' * n_qubits: shots},
'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()
|
compute_kernel_matrix
compute_kernel_matrix(X1: ndarray, X2: ndarray, feature_map: Any, shots: int | None = None) -> np.ndarray
Compute quantum kernel matrix using simulator.
Source code in src/superquantx/backends/simulator_backend.py
| def compute_kernel_matrix(self, X1: np.ndarray, X2: np.ndarray,
feature_map: Any, shots: int | None = None) -> np.ndarray:
"""Compute quantum kernel matrix using simulator."""
n1, n2 = len(X1), len(X2)
kernel_matrix = np.zeros((n1, n2))
for i in range(n1):
for j in range(n2):
try:
# Simple kernel computation based on data similarity
# This is a placeholder - actual implementation would use feature maps
similarity = np.exp(-np.linalg.norm(X1[i] - X2[j])**2 / 2)
kernel_matrix[i, j] = similarity
except Exception as e:
logger.warning(f"Kernel computation failed for ({i},{j}): {e}")
kernel_matrix[i, j] = 0.0
return kernel_matrix
|
create_feature_map
create_feature_map(n_features: int, feature_map: str, reps: int = 1) -> Callable
Create quantum feature map for data encoding.
Source code in src/superquantx/backends/simulator_backend.py
| def create_feature_map(self, n_features: int, feature_map: str, reps: int = 1) -> Callable:
"""Create quantum feature map for data encoding."""
def feature_map_circuit(x):
circuit = self.create_circuit(n_features)
for r in range(reps):
if feature_map == 'ZZFeatureMap':
# ZZ feature map implementation
for i in range(n_features):
circuit = self.add_gate(circuit, 'H', i)
circuit = self.add_gate(circuit, 'RZ', i, [x[i]])
# ZZ interactions
for i in range(n_features - 1):
circuit = self.add_gate(circuit, 'CNOT', [i, i + 1])
circuit = self.add_gate(circuit, 'RZ', i + 1, [x[i] * x[i + 1]])
circuit = self.add_gate(circuit, 'CNOT', [i, i + 1])
elif feature_map == 'PauliFeatureMap':
# Pauli feature map implementation
for i in range(n_features):
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]])
# Entangling
for i in range(n_features - 1):
circuit = self.add_gate(circuit, 'CNOT', [i, i + 1])
else: # Default angle encoding
for i in range(n_features):
circuit = self.add_gate(circuit, 'RY', i, [x[i]])
return circuit
return feature_map_circuit
|
create_ansatz
create_ansatz(ansatz_type: str, n_qubits: int, params: ndarray, include_custom_gates: bool = False) -> Callable
Create parameterized ansatz circuit.
Source code in src/superquantx/backends/simulator_backend.py
| def create_ansatz(self, ansatz_type: str, n_qubits: int, params: np.ndarray,
include_custom_gates: bool = False) -> Callable:
"""Create parameterized ansatz circuit."""
def ansatz_circuit():
circuit = self.create_circuit(n_qubits)
param_idx = 0
if ansatz_type == 'RealAmplitudes':
n_layers = len(params) // (n_qubits * 2)
for layer in range(n_layers):
# RY rotations
for i in range(n_qubits):
if param_idx < len(params):
circuit = self.add_gate(circuit, 'RY', i, [params[param_idx]])
param_idx += 1
# Entangling
for i in range(n_qubits - 1):
circuit = self.add_gate(circuit, 'CNOT', [i, i + 1])
# RZ rotations
for i in range(n_qubits):
if param_idx < len(params):
circuit = self.add_gate(circuit, 'RZ', i, [params[param_idx]])
param_idx += 1
elif ansatz_type == 'EfficientSU2':
n_layers = len(params) // (n_qubits * 3)
for layer in range(n_layers):
# SU(2) rotations
for i in range(n_qubits):
if param_idx + 2 < len(params):
circuit = self.add_gate(circuit, 'RY', i, [params[param_idx]])
circuit = self.add_gate(circuit, 'RZ', i, [params[param_idx + 1]])
circuit = self.add_gate(circuit, 'RY', i, [params[param_idx + 2]])
param_idx += 3
# Entangling
for i in range(n_qubits - 1):
circuit = self.add_gate(circuit, 'CNOT', [i, i + 1])
else: # Default to simple parameterized circuit
for i in range(n_qubits):
if param_idx < len(params):
circuit = self.add_gate(circuit, 'RY', i, [params[param_idx]])
param_idx += 1
for i in range(n_qubits - 1):
circuit = self.add_gate(circuit, 'CNOT', [i, i + 1])
return circuit
return ansatz_circuit
|
compute_expectation
compute_expectation(circuit: QuantumState, hamiltonian: Any, shots: int | None = None) -> float
Compute expectation value of Hamiltonian.
Source code in src/superquantx/backends/simulator_backend.py
| def compute_expectation(self, circuit: QuantumState, hamiltonian: Any,
shots: int | None = None) -> float:
"""Compute expectation value of Hamiltonian."""
try:
if isinstance(hamiltonian, np.ndarray):
# Compute ⟨ψ|H|ψ⟩
statevector = circuit.get_statevector()
expectation = np.real(np.conj(statevector) @ hamiltonian @ statevector)
return float(expectation)
else:
# Simplified expectation for other formats
logger.warning("Simplified Hamiltonian expectation")
return np.random.random() * 2 - 1 # Random value between -1 and 1
except Exception as e:
logger.error(f"Expectation computation failed: {e}")
return 0.0
|
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
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: str | None = None, shots: int = 1024, **kwargs)
Bases: BaseBackend
Qiskit backend for quantum computing operations.
This backend provides access to Qiskit simulators and IBM Quantum
hardware for quantum algorithm execution.
Parameters:
Name |
Type |
Description |
Default |
device
|
str
|
Qiskit backend name ('aer_simulator', 'ibmq_qasm_simulator', etc.)
|
'aer_simulator'
|
provider
|
str | None
|
IBM Quantum provider (if using IBMQ)
|
None
|
shots
|
int
|
Number of measurement shots
|
1024
|
**kwargs
|
|
Additional backend parameters
|
{}
|
Source code in src/superquantx/backends/qiskit_backend.py
| def __init__(self, device: str = 'aer_simulator', provider: str | None = None,
shots: int = 1024, **kwargs):
if not QISKIT_AVAILABLE:
raise ImportError("Qiskit is required for QiskitBackend. Install with: pip install qiskit")
super().__init__(device=device, shots=shots, **kwargs)
self.provider = provider
self.backend = None
self.capabilities = {
'supports_gradient': False,
'supports_parameter_shift': True,
'supports_finite_diff': True,
'supports_hardware': IBM_PROVIDER_AVAILABLE,
'supports_noise_models': True,
}
# Initialize the backend
self._initialize_backend()
|
Functions
create_circuit
create_circuit(n_qubits: int) -> Any
Create a quantum circuit with n qubits.
Source code in src/superquantx/backends/qiskit_backend.py
| def create_circuit(self, n_qubits: int) -> Any:
"""Create a quantum circuit with n qubits."""
qreg = QuantumRegister(n_qubits, 'q')
creg = ClassicalRegister(n_qubits, 'c')
circuit = QuantumCircuit(qreg, creg)
return circuit
|
add_gate
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/qiskit_backend.py
| 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."""
if isinstance(qubits, int):
qubits = [qubits]
params = params or []
try:
if gate.upper() == 'H' or gate.upper() == 'HADAMARD':
circuit.h(qubits[0])
elif gate.upper() == 'X' or gate.upper() == 'PAULI_X':
circuit.x(qubits[0])
elif gate.upper() == 'Y' or gate.upper() == 'PAULI_Y':
circuit.y(qubits[0])
elif gate.upper() == 'Z' or gate.upper() == 'PAULI_Z':
circuit.z(qubits[0])
elif gate.upper() == 'RX':
circuit.rx(params[0] if params else 0, qubits[0])
elif gate.upper() == 'RY':
circuit.ry(params[0] if params else 0, qubits[0])
elif gate.upper() == 'RZ':
circuit.rz(params[0] if params else 0, qubits[0])
elif gate.upper() == 'CNOT' or gate.upper() == 'CX':
circuit.cx(qubits[0], qubits[1])
elif gate.upper() == 'CZ':
circuit.cz(qubits[0], qubits[1])
elif gate.upper() == 'SWAP':
circuit.swap(qubits[0], qubits[1])
elif gate.upper() == 'CCX' or gate.upper() == 'TOFFOLI':
circuit.ccx(qubits[0], qubits[1], qubits[2])
else:
logger.warning(f"Unknown gate: {gate}")
except Exception as e:
logger.error(f"Failed to add gate {gate}: {e}")
return circuit
|
add_measurement
add_measurement(circuit: Any, qubits: list[int] | None = None) -> Any
Add measurement operations to the circuit.
Source code in src/superquantx/backends/qiskit_backend.py
| def add_measurement(self, circuit: Any, qubits: list[int] | None = None) -> Any:
"""Add measurement operations to the circuit."""
if qubits is None:
qubits = list(range(circuit.num_qubits))
for i, qubit in enumerate(qubits):
if i < circuit.num_clbits:
circuit.measure(qubit, i)
return circuit
|
execute_circuit
execute_circuit(circuit: Any, shots: int | None = None) -> dict[str, Any]
Execute quantum circuit and return results.
Source code in src/superquantx/backends/qiskit_backend.py
| def execute_circuit(self, circuit: Any, shots: int | None = None) -> dict[str, Any]:
"""Execute quantum circuit and return results."""
shots = shots or self.shots
try:
# Add measurements if not present
has_measurements = circuit.num_clbits > 0 and any(
hasattr(instr.operation, 'name') and instr.operation.name == 'measure'
for instr in circuit.data
)
if not has_measurements:
circuit.add_register(ClassicalRegister(circuit.num_qubits, 'c'))
circuit.measure_all()
# Transpile circuit
transpiled = transpile(circuit, self.backend)
# Execute using modern Qiskit API
job = self.backend.run(transpiled, shots=shots)
result = job.result()
# Get counts
counts = result.get_counts()
return {
'counts': counts,
'shots': shots,
'backend': self.device,
'job_id': job.job_id(),
}
except Exception as e:
logger.error(f"Circuit execution failed: {e}")
raise
|
get_statevector
get_statevector(circuit: Any) -> np.ndarray
Get the statevector from a quantum circuit.
Source code in src/superquantx/backends/qiskit_backend.py
| def get_statevector(self, circuit: Any) -> np.ndarray:
"""Get the statevector from a quantum circuit."""
try:
# Use statevector simulator
backend = AerSimulator(method='statevector')
# Create circuit copy without measurements
circuit_copy = circuit.copy()
circuit_copy.remove_final_measurements()
# Execute
job = execute(circuit_copy, backend, shots=1)
result = job.result()
# Get statevector
statevector = result.get_statevector()
return np.array(statevector.data)
except Exception as e:
logger.error(f"Statevector computation failed: {e}")
return np.array([1.0] + [0.0] * (2**circuit.num_qubits - 1))
|
create_feature_map
create_feature_map(n_features: int, feature_map: str, reps: int = 1) -> Any
Create quantum feature map for data encoding.
Source code in src/superquantx/backends/qiskit_backend.py
| def create_feature_map(self, n_features: int, feature_map: str, reps: int = 1) -> Any:
"""Create quantum feature map for data encoding."""
if feature_map == 'ZZFeatureMap':
return ZZFeatureMap(n_features, reps=reps)
elif feature_map == 'PauliFeatureMap':
return self._create_pauli_feature_map(n_features, reps)
elif feature_map == 'AmplitudeMap':
return self._create_amplitude_map(n_features)
else:
logger.warning(f"Unknown feature map '{feature_map}', using angle encoding")
return self._create_angle_encoding_map(n_features)
|
compute_kernel_matrix
compute_kernel_matrix(X1: ndarray, X2: ndarray, feature_map: QuantumCircuit, shots: int | None = None) -> np.ndarray
Compute quantum kernel matrix using Qiskit.
Source code in src/superquantx/backends/qiskit_backend.py
| def compute_kernel_matrix(self, X1: np.ndarray, X2: np.ndarray,
feature_map: QuantumCircuit, shots: int | None = None) -> np.ndarray:
"""Compute quantum kernel matrix using Qiskit."""
n1, n2 = len(X1), len(X2)
kernel_matrix = np.zeros((n1, n2))
for i in range(n1):
for j in range(n2):
try:
# Create kernel evaluation circuit
circuit = QuantumCircuit(feature_map.num_qubits, feature_map.num_qubits)
# Encode first data point
circuit.compose(feature_map.bind_parameters(X1[i]), inplace=True)
# Encode second data point with inverse
inverse_map = feature_map.bind_parameters(-X2[j]).inverse()
circuit.compose(inverse_map, inplace=True)
# Measure
circuit.measure_all()
# Execute
result = self.execute_circuit(circuit, shots)
counts = result['counts']
# Kernel value is probability of measuring |00...0⟩
zero_state = '0' * feature_map.num_qubits
kernel_matrix[i, j] = counts.get(zero_state, 0) / sum(counts.values())
except Exception as e:
logger.warning(f"Kernel computation failed for ({i},{j}): {e}")
kernel_matrix[i, j] = 0.0
return kernel_matrix
|
create_ansatz
create_ansatz(ansatz_type: str, n_qubits: int, params: ndarray, include_custom_gates: bool = False) -> Any
Create parameterized ansatz circuit.
Source code in src/superquantx/backends/qiskit_backend.py
| def create_ansatz(self, ansatz_type: str, n_qubits: int, params: np.ndarray,
include_custom_gates: bool = False) -> Any:
"""Create parameterized ansatz circuit."""
if ansatz_type == 'RealAmplitudes':
return RealAmplitudes(n_qubits, reps=len(params) // (n_qubits * 2))
elif ansatz_type == 'EfficientSU2':
return EfficientSU2(n_qubits, reps=len(params) // (n_qubits * 3))
elif ansatz_type == 'TwoLocal':
return self._create_two_local_ansatz(n_qubits, params)
elif ansatz_type == 'UCCSD':
return self._create_uccsd_ansatz(n_qubits, params)
else:
logger.warning(f"Unknown ansatz '{ansatz_type}', using RealAmplitudes")
return RealAmplitudes(n_qubits, reps=len(params) // (n_qubits * 2))
|
compute_expectation
compute_expectation(circuit: Any, hamiltonian: Any, shots: int | None = None) -> float
Compute expectation value of Hamiltonian.
Source code in src/superquantx/backends/qiskit_backend.py
| def compute_expectation(self, circuit: Any, hamiltonian: Any,
shots: int | None = None) -> float:
"""Compute expectation value of Hamiltonian."""
try:
# For Qiskit, we need to decompose Hamiltonian into Pauli terms
if isinstance(hamiltonian, np.ndarray):
# Compute expectation using statevector
statevector = self.get_statevector(circuit)
expectation = np.real(np.conj(statevector) @ hamiltonian @ statevector)
return float(expectation)
else:
logger.warning("Hamiltonian expectation not fully implemented")
return 0.0
except Exception as e:
logger.error(f"Expectation computation failed: {e}")
return 0.0
|
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
Create QAOA circuit with given parameters.
Source code in src/superquantx/backends/qiskit_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:
"""Create QAOA circuit with given parameters."""
circuit = QuantumCircuit(n_qubits)
# Initial state (uniform superposition)
for i in range(n_qubits):
circuit.h(i)
# QAOA layers
for gamma, beta in zip(gammas, betas, strict=False):
# Problem Hamiltonian layer
self._apply_problem_hamiltonian(circuit, gamma, problem_instance)
# Mixer Hamiltonian layer
self._apply_mixer_hamiltonian(circuit, beta)
return circuit
|
get_version_info
get_version_info() -> dict[str, Any]
Get Qiskit version information.
Source code in src/superquantx/backends/qiskit_backend.py
| def get_version_info(self) -> dict[str, Any]:
"""Get Qiskit version information."""
info = super().get_version_info()
try:
import qiskit
info.update({
'qiskit_version': qiskit.__version__,
'backend_name': self.backend.name() if self.backend else 'Unknown',
'backend_version': getattr(self.backend, 'version', 'Unknown'),
})
except Exception as e:
info['version_error'] = str(e)
return info
|
PennyLane Backend
superquantx.backends.PennyLaneBackend
PennyLaneBackend(device: str = 'default.qubit', wires: int = 4, shots: int = 1024, **kwargs)
Bases: BaseBackend
PennyLane backend for quantum computing operations.
This backend provides access to PennyLane's quantum devices and
automatic differentiation capabilities for variational quantum
algorithms.
Parameters:
Name |
Type |
Description |
Default |
device
|
str
|
PennyLane device name ('default.qubit', 'qiskit.aer', etc.)
|
'default.qubit'
|
wires
|
int
|
|
4
|
shots
|
int
|
Number of measurement shots
|
1024
|
**kwargs
|
|
Additional device parameters
|
{}
|
Source code in src/superquantx/backends/pennylane_backend.py
| def __init__(self, device: str = 'default.qubit', wires: int = 4, shots: int = 1024, **kwargs):
if not PENNYLANE_AVAILABLE:
raise ImportError("PennyLane is required for PennyLaneBackend. Install with: pip install pennylane")
self.wires = wires
super().__init__(device=device, shots=shots, **kwargs)
self.dev = None
self.capabilities = {
'supports_gradient': True,
'supports_parameter_shift': True,
'supports_finite_diff': True,
'supports_backprop': device in ['default.qubit'],
'supports_adjoint': device in ['default.qubit'],
}
|
Functions
create_circuit
create_circuit(n_qubits: int) -> Callable
Create a PennyLane quantum function template.
Source code in src/superquantx/backends/pennylane_backend.py
| def create_circuit(self, n_qubits: int) -> Callable:
"""Create a PennyLane quantum function template."""
if n_qubits > self.wires:
logger.warning(f"Requested {n_qubits} qubits, but device only has {self.wires} wires")
n_qubits = self.wires
def circuit_template():
"""Empty circuit template."""
return [qml.expval(qml.PauliZ(i)) for i in range(n_qubits)]
return circuit_template
|
add_gate
add_gate(circuit: Callable, gate: str, qubits: int | list[int], params: list[float] | None = None) -> Callable
Add a quantum gate to the circuit (conceptual - PennyLane uses functions).
Source code in src/superquantx/backends/pennylane_backend.py
| def add_gate(self, circuit: Callable, gate: str, qubits: int | list[int],
params: list[float] | None = None) -> Callable:
"""Add a quantum gate to the circuit (conceptual - PennyLane uses functions)."""
# In PennyLane, gates are added within quantum functions
# This method is more for compatibility with the base interface
logger.debug(f"Gate {gate} would be added to qubits {qubits} with params {params}")
return circuit
|
add_measurement
add_measurement(circuit: Callable, qubits: list[int] | None = None) -> Callable
Add measurement operations (conceptual in PennyLane).
Source code in src/superquantx/backends/pennylane_backend.py
| def add_measurement(self, circuit: Callable, qubits: list[int] | None = None) -> Callable:
"""Add measurement operations (conceptual in PennyLane)."""
return circuit
|
execute_circuit
execute_circuit(circuit: Callable, shots: int | None = None) -> dict[str, Any]
Execute quantum circuit and return results.
Source code in src/superquantx/backends/pennylane_backend.py
| def execute_circuit(self, circuit: Callable, shots: int | None = None) -> dict[str, Any]:
"""Execute quantum circuit and return results."""
try:
# Create QNode
if shots is not None:
dev = qml.device(self.device, wires=self.wires, shots=shots)
qnode = qml.QNode(circuit, dev)
else:
qnode = qml.QNode(circuit, self.dev)
# Execute
result = qnode()
return {
'result': result,
'shots': shots or self.shots,
'device': self.device,
}
except Exception as e:
logger.error(f"Circuit execution failed: {e}")
raise
|
get_statevector
get_statevector(circuit: Callable) -> np.ndarray
Get the statevector from a quantum circuit.
Source code in src/superquantx/backends/pennylane_backend.py
| def get_statevector(self, circuit: Callable) -> np.ndarray:
"""Get the statevector from a quantum circuit."""
# Create a statevector device
dev_statevector = qml.device('default.qubit', wires=self.wires)
@qml.qnode(dev_statevector)
def statevector_circuit():
circuit()
return qml.state()
return np.array(statevector_circuit())
|
create_feature_map
create_feature_map(n_features: int, feature_map: str, reps: int = 1) -> Callable
Create quantum feature map for data encoding.
Source code in src/superquantx/backends/pennylane_backend.py
| def create_feature_map(self, n_features: int, feature_map: str, reps: int = 1) -> Callable:
"""Create quantum feature map for data encoding."""
if feature_map == 'ZZFeatureMap':
return self._create_zz_feature_map(n_features, reps)
elif feature_map == 'PauliFeatureMap':
return self._create_pauli_feature_map(n_features, reps)
elif feature_map == 'AmplitudeMap':
return self._create_amplitude_map(n_features)
else:
logger.warning(f"Unknown feature map '{feature_map}', using angle encoding")
return self._create_angle_encoding_map(n_features)
|
compute_kernel_matrix
compute_kernel_matrix(X1: ndarray, X2: ndarray, feature_map: Callable, shots: int | None = None) -> np.ndarray
Compute quantum kernel matrix using PennyLane.
Source code in src/superquantx/backends/pennylane_backend.py
| def compute_kernel_matrix(self, X1: np.ndarray, X2: np.ndarray,
feature_map: Callable, shots: int | None = None) -> np.ndarray:
"""Compute quantum kernel matrix using PennyLane."""
n1, n2 = len(X1), len(X2)
kernel_matrix = np.zeros((n1, n2))
# Create kernel evaluation circuit
def kernel_circuit(x1, x2):
# Encode first data point
for i in range(min(len(x1), self.wires)):
qml.RY(x1[i], wires=i)
# Encode second data point with inverse
for i in range(min(len(x2), self.wires)):
qml.RY(-x2[i], wires=i)
# Measure probability of |00...0⟩ state
return qml.probs(wires=range(min(len(x1), self.wires)))
# Create QNode
dev = qml.device(self.device, wires=self.wires, shots=shots) if shots else self.dev
kernel_qnode = qml.QNode(kernel_circuit, dev)
# Compute kernel matrix
for i in range(n1):
for j in range(n2):
try:
probs = kernel_qnode(X1[i], X2[j])
kernel_matrix[i, j] = probs[0] # Probability of |00...0⟩
except Exception as e:
logger.warning(f"Kernel computation failed for ({i},{j}): {e}")
kernel_matrix[i, j] = 0.0
return kernel_matrix
|
create_ansatz
create_ansatz(ansatz_type: str, n_qubits: int, params: ndarray, include_custom_gates: bool = False) -> Callable
Create parameterized ansatz circuit.
Source code in src/superquantx/backends/pennylane_backend.py
| def create_ansatz(self, ansatz_type: str, n_qubits: int, params: np.ndarray,
include_custom_gates: bool = False) -> Callable:
"""Create parameterized ansatz circuit."""
if ansatz_type == 'RealAmplitudes':
return self._create_real_amplitudes_ansatz(n_qubits, params)
elif ansatz_type == 'EfficientSU2':
return self._create_efficient_su2_ansatz(n_qubits, params)
elif ansatz_type == 'TwoLocal':
return self._create_two_local_ansatz(n_qubits, params)
elif ansatz_type == 'UCCSD':
return self._create_uccsd_ansatz(n_qubits, params)
else:
logger.warning(f"Unknown ansatz '{ansatz_type}', using RealAmplitudes")
return self._create_real_amplitudes_ansatz(n_qubits, params)
|
compute_expectation
compute_expectation(circuit: Callable, hamiltonian: Any, shots: int | None = None) -> float
Compute expectation value of Hamiltonian.
Source code in src/superquantx/backends/pennylane_backend.py
| def compute_expectation(self, circuit: Callable, hamiltonian: Any,
shots: int | None = None) -> float:
"""Compute expectation value of Hamiltonian."""
try:
# If hamiltonian is a PennyLane Hamiltonian
if hasattr(hamiltonian, 'coeffs') and hasattr(hamiltonian, 'ops'):
@qml.qnode(self.dev if shots is None else qml.device(self.device, wires=self.wires, shots=shots))
def expectation_circuit():
circuit()
return qml.expval(hamiltonian)
return float(expectation_circuit())
# If hamiltonian is a matrix, decompose it
elif isinstance(hamiltonian, np.ndarray):
return self._compute_matrix_expectation(circuit, hamiltonian, shots)
else:
logger.warning("Unknown Hamiltonian format, returning 0")
return 0.0
except Exception as e:
logger.error(f"Expectation computation failed: {e}")
return 0.0
|
get_version_info
get_version_info() -> dict[str, Any]
Get PennyLane version information.
Source code in src/superquantx/backends/pennylane_backend.py
| def get_version_info(self) -> dict[str, Any]:
"""Get PennyLane version information."""
info = super().get_version_info()
info.update({
'pennylane_version': qml.version() if qml else 'Not available',
'available_devices': qml.plugin_devices if qml else [],
})
return info
|
Google Cirq Backend
superquantx.backends.CirqBackend
CirqBackend(device: str = 'simulator', processor_id: str | None = None, shots: int = 1024, **kwargs)
Bases: BaseBackend
Cirq backend for quantum computing operations.
This backend provides access to Cirq simulators and Google Quantum AI
hardware for quantum algorithm execution.
Parameters:
Name |
Type |
Description |
Default |
device
|
str
|
Cirq device name ('simulator', 'sycamore', etc.)
|
'simulator'
|
processor_id
|
str | None
|
Google Quantum AI processor ID
|
None
|
shots
|
int
|
Number of measurement shots
|
1024
|
**kwargs
|
|
Additional backend parameters
|
{}
|
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 cirq")
super().__init__(device=device, shots=shots, **kwargs)
self.processor_id = processor_id
self.simulator = None
self.quantum_engine = None
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
create_circuit
create_circuit(n_qubits: int) -> Any
Create a quantum circuit with n qubits.
Source code in src/superquantx/backends/cirq_backend.py
| def create_circuit(self, n_qubits: int) -> Any:
"""Create a quantum circuit with n qubits."""
qubits = [cirq.LineQubit(i) for i in range(n_qubits)]
circuit = cirq.Circuit()
return circuit, qubits # Return both circuit and qubits for convenience
|
add_gate
add_gate(circuit_info: tuple[Any, list], gate: str, qubits: int | list[int], params: list[float] | None = None) -> tuple[Any, list]
Add a quantum gate to the circuit.
Source code in src/superquantx/backends/cirq_backend.py
| def add_gate(self, circuit_info: tuple[Any, list], gate: str,
qubits: int | list[int], params: list[float] | None = None) -> tuple[Any, list]:
"""Add a quantum gate to the circuit."""
circuit, qubit_list = circuit_info
if isinstance(qubits, int):
qubits = [qubits]
params = params or []
try:
if gate.upper() == 'H' or gate.upper() == 'HADAMARD':
circuit.append(cirq.H(qubit_list[qubits[0]]))
elif gate.upper() == 'X' or gate.upper() == 'PAULI_X':
circuit.append(cirq.X(qubit_list[qubits[0]]))
elif gate.upper() == 'Y' or gate.upper() == 'PAULI_Y':
circuit.append(cirq.Y(qubit_list[qubits[0]]))
elif gate.upper() == 'Z' or gate.upper() == 'PAULI_Z':
circuit.append(cirq.Z(qubit_list[qubits[0]]))
elif gate.upper() == 'RX':
circuit.append(cirq.rx(params[0] if params else 0)(qubit_list[qubits[0]]))
elif gate.upper() == 'RY':
circuit.append(cirq.ry(params[0] if params else 0)(qubit_list[qubits[0]]))
elif gate.upper() == 'RZ':
circuit.append(cirq.rz(params[0] if params else 0)(qubit_list[qubits[0]]))
elif gate.upper() == 'CNOT' or gate.upper() == 'CX':
circuit.append(cirq.CNOT(qubit_list[qubits[0]], qubit_list[qubits[1]]))
elif gate.upper() == 'CZ':
circuit.append(cirq.CZ(qubit_list[qubits[0]], qubit_list[qubits[1]]))
elif gate.upper() == 'SWAP':
circuit.append(cirq.SWAP(qubit_list[qubits[0]], qubit_list[qubits[1]]))
elif gate.upper() == 'CCX' or gate.upper() == 'TOFFOLI':
circuit.append(cirq.CCX(qubit_list[qubits[0]], qubit_list[qubits[1]], qubit_list[qubits[2]]))
else:
logger.warning(f"Unknown gate: {gate}")
except Exception as e:
logger.error(f"Failed to add gate {gate}: {e}")
return circuit, qubit_list
|
add_measurement
add_measurement(circuit_info: tuple[Any, list], qubits: list[int] | None = None) -> tuple[Any, list]
Add measurement operations to the circuit.
Source code in src/superquantx/backends/cirq_backend.py
| def add_measurement(self, circuit_info: tuple[Any, list],
qubits: list[int] | None = None) -> tuple[Any, list]:
"""Add measurement operations to the circuit."""
circuit, qubit_list = circuit_info
if qubits is None:
qubits = list(range(len(qubit_list)))
measurement_qubits = [qubit_list[i] for i in qubits]
circuit.append(cirq.measure(*measurement_qubits, key='result'))
return circuit, qubit_list
|
execute_circuit
execute_circuit(circuit_info: Any | tuple, shots: int | None = None) -> dict[str, Any]
Execute quantum circuit and return results.
Source code in src/superquantx/backends/cirq_backend.py
| def execute_circuit(self, circuit_info: Any | tuple, shots: int | None = None) -> dict[str, Any]:
"""Execute quantum circuit and return results."""
if isinstance(circuit_info, tuple):
circuit, qubit_list = circuit_info
else:
circuit = circuit_info
qubit_list = sorted(circuit.all_qubits())
shots = shots or self.shots
try:
if self.simulator:
# Run on simulator
result = self.simulator.run(circuit, repetitions=shots)
# Convert to counts format
if 'result' in result.measurements:
measurements = result.measurements['result']
counts = {}
for measurement in measurements:
bitstring = ''.join(str(bit) for bit in measurement)
counts[bitstring] = counts.get(bitstring, 0) + 1
else:
counts = {'0' * len(qubit_list): shots}
return {
'counts': counts,
'shots': shots,
'backend': 'cirq_simulator',
}
elif self.quantum_engine and self.processor_id:
# Run on Google Quantum AI hardware
processor = self.quantum_engine.get_processor(self.processor_id)
job = processor.run(circuit, repetitions=shots)
result = job.results()[0]
# Convert to counts format
measurements = result.measurements['result']
counts = {}
for measurement in measurements:
bitstring = ''.join(str(bit) for bit in measurement)
counts[bitstring] = counts.get(bitstring, 0) + 1
return {
'counts': counts,
'shots': shots,
'backend': f'google_quantum_{self.processor_id}',
'job_id': job.id(),
}
else:
raise ValueError("No execution backend available")
except Exception as e:
logger.error(f"Circuit execution failed: {e}")
raise
|
get_statevector
get_statevector(circuit_info: Any | tuple) -> np.ndarray
Get the statevector from a quantum circuit.
Source code in src/superquantx/backends/cirq_backend.py
| def get_statevector(self, circuit_info: Any | tuple) -> np.ndarray:
"""Get the statevector from a quantum circuit."""
if isinstance(circuit_info, tuple):
circuit, qubit_list = circuit_info
else:
circuit = circuit_info
qubit_list = sorted(circuit.all_qubits())
try:
# Remove measurements for statevector simulation
circuit_copy = circuit.copy()
circuit_copy = cirq.Circuit([op for op in circuit_copy.all_operations()
if not isinstance(op.gate, cirq.MeasurementGate)])
# Simulate
result = self.simulator.simulate(circuit_copy)
statevector = result.final_state_vector
return np.array(statevector)
except Exception as e:
logger.error(f"Statevector computation failed: {e}")
n_qubits = len(qubit_list)
return np.array([1.0] + [0.0] * (2**n_qubits - 1))
|
create_feature_map
create_feature_map(n_features: int, feature_map: str, reps: int = 1) -> tuple[Any, list]
Create quantum feature map for data encoding.
Source code in src/superquantx/backends/cirq_backend.py
| def create_feature_map(self, n_features: int, feature_map: str, reps: int = 1) -> tuple[Any, list]:
"""Create quantum feature map for data encoding."""
[cirq.LineQubit(i) for i in range(n_features)]
cirq.Circuit()
if feature_map == 'ZZFeatureMap':
circuit_info = self._create_zz_feature_map(n_features, reps)
elif feature_map == 'PauliFeatureMap':
circuit_info = self._create_pauli_feature_map(n_features, reps)
elif feature_map == 'AmplitudeMap':
circuit_info = self._create_amplitude_map(n_features)
else:
logger.warning(f"Unknown feature map '{feature_map}', using angle encoding")
circuit_info = self._create_angle_encoding_map(n_features)
return circuit_info
|
create_ansatz
create_ansatz(ansatz_type: str, n_qubits: int, params: ndarray, include_custom_gates: bool = False) -> tuple[Any, list]
Create parameterized ansatz circuit.
Source code in src/superquantx/backends/cirq_backend.py
| def create_ansatz(self, ansatz_type: str, n_qubits: int, params: np.ndarray,
include_custom_gates: bool = False) -> tuple[Any, list]:
"""Create parameterized ansatz circuit."""
if ansatz_type == 'RealAmplitudes':
return self._create_real_amplitudes_ansatz(n_qubits, params)
elif ansatz_type == 'EfficientSU2':
return self._create_efficient_su2_ansatz(n_qubits, params)
elif ansatz_type == 'TwoLocal':
return self._create_two_local_ansatz(n_qubits, params)
elif ansatz_type == 'UCCSD':
return self._create_uccsd_ansatz(n_qubits, params)
else:
logger.warning(f"Unknown ansatz '{ansatz_type}', using RealAmplitudes")
return self._create_real_amplitudes_ansatz(n_qubits, params)
|
compute_expectation
compute_expectation(circuit_info: Any | tuple, hamiltonian: Any, shots: int | None = None) -> float
Compute expectation value of Hamiltonian.
Source code in src/superquantx/backends/cirq_backend.py
| def compute_expectation(self, circuit_info: Any | tuple, hamiltonian: Any,
shots: int | None = None) -> float:
"""Compute expectation value of Hamiltonian."""
try:
if isinstance(hamiltonian, np.ndarray):
# Compute expectation using statevector
statevector = self.get_statevector(circuit_info)
expectation = np.real(np.conj(statevector) @ hamiltonian @ statevector)
return float(expectation)
else:
logger.warning("Hamiltonian expectation not fully implemented")
return 0.0
except Exception as e:
logger.error(f"Expectation computation failed: {e}")
return 0.0
|
get_version_info
get_version_info() -> dict[str, Any]
Get Cirq version information.
Source code in src/superquantx/backends/cirq_backend.py
| def get_version_info(self) -> dict[str, Any]:
"""Get Cirq version information."""
info = super().get_version_info()
try:
info.update({
'cirq_version': cirq.__version__,
'processor_id': self.processor_id,
})
except Exception as e:
info['version_error'] = str(e)
return info
|
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 quantum circuit.
Source code in src/superquantx/backends/braket_backend.py
| def create_circuit(self, n_qubits: int) -> BraketCircuit:
"""Create a Braket quantum circuit."""
if n_qubits > self._get_max_qubits():
logger.warning(f"Requested {n_qubits} qubits exceeds device limit")
return BraketCircuit()
|
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]
params = params or []
# Map gate names to Braket gates
gate_mapping = {
'i': I, 'x': X, 'y': Y, 'z': Z, 'h': H,
's': S, 'sdg': Si, 't': T, 'tdg': Ti,
'rx': RX, 'ry': RY, 'rz': RZ,
'cnot': CNot, 'cx': CNot, 'cz': CZ, 'cy': CY,
'swap': Swap, 'iswap': ISwap,
'ccnot': CCNot, 'toffoli': CCNot,
'cswap': CSwap, 'fredkin': CSwap
}
gate_lower = gate.lower()
if gate_lower not in gate_mapping:
raise ValueError(f"Gate '{gate}' not supported in Braket backend")
gate_class = gate_mapping[gate_lower]
try:
if len(params) == 0:
# Parameter-less gates
if len(qubits) == 1:
circuit.add_instruction(Instruction(gate_class(), qubits[0]))
elif len(qubits) == 2:
circuit.add_instruction(Instruction(gate_class(), qubits))
elif len(qubits) == 3:
circuit.add_instruction(Instruction(gate_class(), qubits))
else:
raise ValueError(f"Too many qubits for gate {gate}")
else:
# Parameterized gates
if gate_lower in ['rx', 'ry', 'rz']:
circuit.add_instruction(Instruction(gate_class(params[0]), qubits[0]))
elif gate_lower == 'phaseshift':
circuit.add_instruction(Instruction(PhaseShift(params[0]), qubits[0]))
elif gate_lower == 'cphaseshift':
circuit.add_instruction(Instruction(CPhaseShift(params[0]), qubits))
else:
raise ValueError(f"Parameters not supported for gate {gate}")
except Exception as e:
logger.error(f"Failed to add gate {gate} to circuit: {e}")
raise
return circuit
|
add_measurement
add_measurement(circuit: Circuit, qubits: int | list[int]) -> BraketCircuit
Add measurement instructions to specified qubits.
Source code in src/superquantx/backends/braket_backend.py
| def add_measurement(self, circuit: BraketCircuit, qubits: int | list[int]) -> BraketCircuit:
"""Add measurement instructions to specified qubits."""
if isinstance(qubits, int):
qubits = [qubits]
# Braket doesn't use explicit measurement instructions in circuits
# Measurements are handled during task submission
# Store measurement info for later use
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]
Execute quantum circuit and return results.
Source code in src/superquantx/backends/braket_backend.py
| def execute_circuit(self, circuit: BraketCircuit, shots: int | None = None) -> dict[str, Any]:
"""Execute quantum circuit and return results."""
shots = shots or self.shots
try:
# Get measurement qubits (all qubits if not specified)
if hasattr(circuit, '_measurement_qubits'):
measure_qubits = sorted(circuit._measurement_qubits)
else:
# Measure all qubits that have gates applied
measure_qubits = list(range(circuit.qubit_count))
# Add measurement to circuit copy
measured_circuit = circuit.copy()
for qubit in measure_qubits:
measured_circuit.add_instruction(Instruction(Measure(), qubit))
# Execute task
if self.s3_folder and hasattr(self._device, 'run'):
# AWS device with S3 storage
task = self._device.run(measured_circuit, shots=shots, s3_destination_folder=self.s3_folder)
result = task.result()
else:
# Local simulator
task = self._device.run(measured_circuit, shots=shots)
result = task.result()
# Process measurement results
measurement_counts = result.measurement_counts
# Convert to standard format
counts = {}
for bitstring, count in measurement_counts.items():
counts[bitstring] = count
return {
'counts': counts,
'shots': shots,
'success': True,
'measurement_qubits': measure_qubits,
'task_arn': getattr(task, 'id', 'local'),
'device': self.device_name,
}
except Exception as e:
logger.error(f"Circuit execution failed: {e}")
return {
'counts': {},
'shots': shots,
'success': False,
'error': str(e),
'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
|
bind_parameters
bind_parameters(circuit: Circuit, param_values: dict[str, float]) -> BraketCircuit
Bind parameter values to parameterized circuit.
Source code in src/superquantx/backends/braket_backend.py
| def bind_parameters(self, circuit: BraketCircuit, param_values: dict[str, float]) -> BraketCircuit:
"""Bind parameter values to parameterized circuit."""
# Braket handles parameterization differently - would need custom implementation
# For now, create a new circuit with bound parameters
bound_circuit = circuit.copy()
# This is a simplified implementation
# In practice, you'd need to track parameterized gates and substitute values
logger.warning("Parameter binding in Braket backend is simplified")
return bound_circuit
|
expectation_value
expectation_value(circuit: Circuit, observable: str | ndarray, shots: int | None = None) -> float
Calculate expectation value of observable.
Source code in src/superquantx/backends/braket_backend.py
| def expectation_value(self, circuit: BraketCircuit, observable: str | np.ndarray,
shots: int | None = None) -> float:
"""Calculate expectation value of observable."""
shots = shots or self.shots
try:
# Simple implementation for Pauli observables
if isinstance(observable, str):
if observable.upper() == 'Z':
# Measure in Z basis
result = self.execute_circuit(circuit, shots)
counts = result['counts']
# Calculate <Z> expectation
expectation = 0.0
total_counts = sum(counts.values())
for bitstring, count in counts.items():
# Z expectation: +1 for |0>, -1 for |1>
prob = count / total_counts
if bitstring == '0' or (len(bitstring) > 0 and bitstring[0] == '0'):
expectation += prob
else:
expectation -= prob
return expectation
else:
logger.warning(f"Observable {observable} not fully implemented")
return 0.0
else:
logger.warning("Matrix observables not implemented")
return 0.0
except Exception as e:
logger.error(f"Expectation value calculation failed: {e}")
return 0.0
|
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."""
import braket
return {
'braket_sdk': getattr(braket, '__version__', 'unknown'),
'backend_version': '1.0.0',
}
|
is_available
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
Get statevector from Braket circuit.
Source code in src/superquantx/backends/braket_backend.py
| def get_statevector(self, circuit: BraketCircuit) -> np.ndarray:
"""Get statevector from Braket circuit."""
try:
# Use local simulator for statevector
from braket.devices import LocalSimulator
sv_device = LocalSimulator("braket_sv")
# Execute without measurements for statevector
task = sv_device.run(circuit, shots=0)
result = task.result()
if hasattr(result, 'get_value_by_result_type'):
from braket.circuits.result_types import StateVector
return result.get_value_by_result_type(StateVector())
else:
logger.warning("Statevector not available")
return np.zeros(2**circuit.qubit_count, dtype=complex)
except Exception as e:
logger.error(f"Failed to get statevector: {e}")
return np.zeros(2**circuit.qubit_count, 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 quantum gate to the circuit.
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 quantum gate to the circuit."""
if isinstance(qubits, int):
qubits = [qubits]
params = params or []
# Map gate names to TKET OpTypes
gate_mapping = {
'i': OpType.noop, # Identity
'x': OpType.X, 'y': OpType.Y, 'z': OpType.Z, 'h': OpType.H,
's': OpType.S, 'sdg': OpType.Sdg, 't': OpType.T, 'tdg': OpType.Tdg,
'rx': OpType.Rx, 'ry': OpType.Ry, 'rz': OpType.Rz,
'cnot': OpType.CX, 'cx': OpType.CX, 'cz': OpType.CZ, 'cy': OpType.CY,
'ch': OpType.CH, 'swap': OpType.SWAP,
'ccnot': OpType.CCX, 'ccx': OpType.CCX, 'toffoli': OpType.CCX,
'cswap': OpType.CSWAP, 'fredkin': OpType.CSWAP,
'iswap': OpType.ISWAPMax,
'u1': OpType.U1, 'u2': OpType.U2, 'u3': OpType.U3,
}
gate_upper = gate.upper()
gate_lower = gate.lower()
# Try exact match first, then case variations
op_type = None
if hasattr(OpType, gate_upper):
op_type = getattr(OpType, gate_upper)
elif gate_lower in gate_mapping:
op_type = gate_mapping[gate_lower]
if op_type is None:
raise ValueError(f"Gate '{gate}' not supported in TKET backend")
try:
# Convert qubit indices to TKET Qubit objects
tket_qubits = [circuit.qubits[q] for q in qubits]
if len(params) == 0:
# Parameter-less gates
circuit.add_gate(op_type, tket_qubits)
else:
# Parameterized gates
circuit.add_gate(op_type, tket_qubits, params)
except Exception as e:
logger.error(f"Failed to add gate {gate} to TKET circuit: {e}")
raise
return circuit
|
add_measurement
add_measurement(circuit: Circuit, qubits: int | list[int]) -> Circuit
Add measurement instructions to specified qubits.
Source code in src/superquantx/backends/tket_backend.py
| def add_measurement(self, circuit: Circuit, qubits: int | list[int]) -> Circuit:
"""Add measurement instructions to specified qubits."""
if isinstance(qubits, int):
qubits = [qubits]
# TKET requires explicit bit allocation for measurements
n_bits = len(qubits)
if circuit.n_bits < n_bits:
circuit.add_c_register("c", n_bits - 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]
Execute quantum circuit and return results.
Source code in src/superquantx/backends/tket_backend.py
| def execute_circuit(self, circuit: Circuit, shots: int | None = None) -> dict[str, Any]:
"""Execute quantum circuit and return results."""
shots = shots or self.shots
try:
if self._backend is None:
# Simple simulation fallback
logger.warning("No TKET backend available, using simulation fallback")
n_qubits = circuit.n_qubits
n_bits = circuit.n_bits or n_qubits
# Generate random results for fallback
counts = {}
for _ in range(shots):
bitstring = ''.join([str(np.random.randint(0, 2)) for _ in range(n_bits)])
counts[bitstring] = counts.get(bitstring, 0) + 1
return {
'counts': counts,
'shots': shots,
'success': True,
'backend': 'tket_fallback',
}
# Compile circuit for backend
compiled_circuit = self._backend.get_compiled_circuit(circuit)
# Execute on backend
handle = self._backend.process_circuit(compiled_circuit, n_shots=shots)
result = self._backend.get_result(handle)
# Extract counts
counts_dict = {}
if hasattr(result, 'get_counts'):
counts_dict = result.get_counts()
elif hasattr(result, 'counts'):
counts_dict = result.counts
else:
logger.warning("Could not extract counts from TKET result")
return {
'counts': counts_dict,
'shots': shots,
'success': True,
'backend': self._backend.__class__.__name__,
'compiled': True,
'device': self.device_name,
}
except Exception as e:
logger.error(f"TKET circuit execution failed: {e}")
return {
'counts': {},
'shots': shots,
'success': False,
'error': str(e),
'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
|
create_parameterized_circuit
create_parameterized_circuit(n_qubits: int, n_params: int) -> tuple[Circuit, list[str]]
Create a parameterized quantum circuit for variational algorithms.
Source code in src/superquantx/backends/tket_backend.py
| def create_parameterized_circuit(self, n_qubits: int, n_params: int) -> tuple[Circuit, list[str]]:
"""Create a parameterized quantum circuit for variational algorithms."""
from pytket.circuit import fresh_symbol
circuit = self.create_circuit(n_qubits)
# Create symbolic parameters
symbols = [fresh_symbol(f"theta_{i}") for i in range(n_params)]
param_names = [str(symbol) for symbol in symbols]
# Store parameter info
circuit._symbols = symbols
circuit._param_names = param_names
return circuit, param_names
|
bind_parameters
bind_parameters(circuit: Circuit, param_values: dict[str, float]) -> Circuit
Bind parameter values to parameterized circuit.
Source code in src/superquantx/backends/tket_backend.py
| def bind_parameters(self, circuit: Circuit, param_values: dict[str, float]) -> Circuit:
"""Bind parameter values to parameterized circuit."""
try:
bound_circuit = circuit.copy()
# Create symbol substitution map
if hasattr(circuit, '_symbols'):
symbol_map = {}
for symbol, name in zip(circuit._symbols, circuit._param_names, strict=False):
if name in param_values:
symbol_map[symbol] = param_values[name]
# Substitute symbols with values
bound_circuit.symbol_substitution(symbol_map)
return bound_circuit
except Exception as e:
logger.error(f"Parameter binding failed: {e}")
return circuit
|
expectation_value
expectation_value(circuit: Circuit, observable: str | ndarray, shots: int | None = None) -> float
Calculate expectation value of observable using TKET.
Source code in src/superquantx/backends/tket_backend.py
| def expectation_value(self, circuit: Circuit, observable: str | np.ndarray,
shots: int | None = None) -> float:
"""Calculate expectation value of observable using TKET."""
shots = shots or self.shots
try:
if isinstance(observable, str) and observable.upper() == 'Z':
# Measure in Z basis
measured_circuit = circuit.copy()
measured_circuit.add_c_register("c", 1)
measured_circuit.Measure(measured_circuit.qubits[0], measured_circuit.bits[0])
result = self.execute_circuit(measured_circuit, shots)
counts = result['counts']
# Calculate <Z> expectation
expectation = 0.0
total_counts = sum(counts.values())
for bitstring, count in counts.items():
prob = count / total_counts
if bitstring[0] == '0':
expectation += prob
else:
expectation -= prob
return expectation
else:
logger.warning("Only Z observable currently implemented")
return 0.0
except Exception as e:
logger.error(f"Expectation value calculation failed: {e}")
return 0.0
|
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
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
Get statevector from TKET circuit.
Source code in src/superquantx/backends/tket_backend.py
| def get_statevector(self, circuit: Circuit) -> np.ndarray:
"""Get statevector from TKET circuit."""
try:
if TKET_EXTENSIONS_AVAILABLE:
from pytket.extensions.qiskit import AerStateBackend
state_backend = AerStateBackend()
compiled_circuit = state_backend.get_compiled_circuit(circuit)
handle = state_backend.process_circuit(compiled_circuit)
result = state_backend.get_result(handle)
if hasattr(result, 'get_state'):
return result.get_state()
logger.warning("Statevector not available with current TKET setup")
return np.zeros(2**circuit.n_qubits, dtype=complex)
except Exception as e:
logger.error(f"Failed to get statevector: {e}")
return np.zeros(2**circuit.n_qubits, 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
|
|
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
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.get('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.get('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]
|
|
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]
Limited circuit support for compatibility.
Note: D-Wave is not a gate-model quantum computer.
This returns a placeholder for optimization problems.
Source code in src/superquantx/backends/ocean_backend.py
| def create_circuit(self, n_qubits: int) -> dict[str, Any]:
"""Limited circuit support for compatibility.
Note: D-Wave is not a gate-model quantum computer.
This returns a placeholder for optimization problems.
"""
logger.warning("D-Wave Ocean backend does not support gate-model circuits")
return {
'type': 'optimization_placeholder',
'n_variables': n_qubits,
'backend': 'ocean',
'problem': None
}
|
add_gate
add_gate(circuit: dict, gate: str, qubits: int | list[int], params: list[float] | None = None) -> dict
Limited gate support - not applicable for annealing.
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:
"""Limited gate support - not applicable for annealing."""
logger.warning("Gate operations not supported on D-Wave annealing backend")
return circuit
|
add_measurement
add_measurement(circuit: dict, qubits: int | list[int]) -> dict
Limited measurement support - not applicable for annealing.
Source code in src/superquantx/backends/ocean_backend.py
| def add_measurement(self, circuit: dict, qubits: int | list[int]) -> dict:
"""Limited measurement support - not applicable for annealing."""
logger.warning("Measurements not applicable for D-Wave annealing backend")
return circuit
|
execute_circuit
execute_circuit(circuit: dict, shots: int | None = None) -> dict[str, Any]
Limited circuit execution - redirects to optimization solving.
Source code in src/superquantx/backends/ocean_backend.py
| def execute_circuit(self, circuit: dict, shots: int | None = None) -> dict[str, Any]:
"""Limited circuit execution - redirects to optimization solving."""
logger.warning("Circuit execution not supported - use solve_qubo() or solve_ising() instead")
return {
'counts': {},
'shots': shots or self.shots,
'success': False,
'error': 'Use optimization problem methods instead of circuit execution',
'backend': 'ocean'
}
|
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
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
Get statevector (not applicable for annealing backend).
Source code in src/superquantx/backends/ocean_backend.py
| def get_statevector(self, circuit: dict) -> np.ndarray:
"""Get statevector (not applicable for annealing backend)."""
logger.warning("Statevector not applicable for quantum annealing backend")
return np.array([1.0 + 0j]) # Dummy statevector
|
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
# Convert to QUBO formulation
Q = {}
for i, j in G.edges():
Q[(i, i)] = Q.get((i, i), 0) + 1
Q[(j, j)] = Q.get((j, j), 0) + 1
Q[(i, j)] = Q.get((i, j), 0) - 2
return self.solve_qubo(Q, **kwargs)
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]
Solve Traveling Salesman Problem (simplified formulation).
Source code in src/superquantx/backends/ocean_backend.py
| def solve_tsp(self, distance_matrix: np.ndarray, **kwargs) -> dict[str, Any]:
"""Solve Traveling Salesman Problem (simplified formulation)."""
try:
n_cities = len(distance_matrix)
# This is a simplified TSP formulation
# Full TSP requires more complex constraints
logger.warning("TSP formulation is simplified - may not give valid tours")
Q = {}
# Add distance costs
for i in range(n_cities):
for j in range(i+1, n_cities):
for t in range(n_cities):
# Variable x_it means city i is visited at time t
var_i = i * n_cities + t
var_j = j * n_cities + ((t + 1) % n_cities)
Q[(var_i, var_j)] = distance_matrix[i, j]
return self.solve_qubo(Q, **kwargs)
except Exception as e:
logger.error(f"TSP solving failed: {e}")
return {'success': False, 'error': str(e)}
|
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
|
|
required
|
**kwargs
|
|
Backend configuration parameters
|
{}
|
Returns:
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', {}),
}
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')
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)
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
- Development Phase: Use
simulator
or pennylane
for rapid iteration
- Testing Phase: Use cloud simulators (
braket_sv
, qiskit_aer
) for validation
- Production Phase: Use real hardware with appropriate error mitigation
- Cost Optimization: Use free simulators when possible, batch hardware jobs
# 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