superquantx 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- superquantx/__init__.py +24 -12
- superquantx/algorithms/__init__.py +1 -1
- superquantx/algorithms/base_algorithm.py +36 -36
- superquantx/algorithms/hybrid_classifier.py +22 -22
- superquantx/algorithms/qaoa.py +29 -28
- superquantx/algorithms/quantum_agents.py +57 -56
- superquantx/algorithms/quantum_kmeans.py +17 -17
- superquantx/algorithms/quantum_nn.py +18 -18
- superquantx/algorithms/quantum_pca.py +26 -26
- superquantx/algorithms/quantum_svm.py +26 -25
- superquantx/algorithms/vqe.py +40 -39
- superquantx/algorithms.py +56 -55
- superquantx/backends/__init__.py +12 -12
- superquantx/backends/base_backend.py +25 -24
- superquantx/backends/braket_backend.py +21 -21
- superquantx/backends/cirq_backend.py +26 -26
- superquantx/backends/ocean_backend.py +38 -38
- superquantx/backends/pennylane_backend.py +12 -11
- superquantx/backends/qiskit_backend.py +12 -12
- superquantx/backends/simulator_backend.py +31 -17
- superquantx/backends/tket_backend.py +23 -23
- superquantx/circuits.py +25 -25
- superquantx/cli/commands.py +6 -7
- superquantx/cli/main.py +5 -6
- superquantx/client.py +42 -42
- superquantx/config.py +14 -14
- superquantx/datasets/__init__.py +58 -0
- superquantx/datasets/molecular.py +307 -0
- superquantx/datasets/preprocessing.py +279 -0
- superquantx/datasets/quantum_datasets.py +277 -0
- superquantx/datasets/synthetic.py +300 -0
- superquantx/exceptions.py +29 -29
- superquantx/gates.py +26 -26
- superquantx/logging_config.py +29 -29
- superquantx/measurements.py +53 -54
- superquantx/ml.py +51 -52
- superquantx/noise.py +49 -49
- superquantx/utils/benchmarking.py +41 -36
- superquantx/utils/classical_utils.py +32 -32
- superquantx/utils/feature_mapping.py +40 -35
- superquantx/utils/optimization.py +28 -26
- superquantx/utils/quantum_utils.py +47 -48
- superquantx/utils/visualization.py +49 -49
- superquantx/version.py +3 -3
- {superquantx-0.1.0.dist-info → superquantx-0.1.1.dist-info}/METADATA +18 -16
- superquantx-0.1.1.dist-info/RECORD +51 -0
- superquantx-0.1.1.dist-info/licenses/LICENSE +180 -0
- superquantx-0.1.0.dist-info/RECORD +0 -46
- superquantx-0.1.0.dist-info/licenses/LICENSE +0 -21
- {superquantx-0.1.0.dist-info → superquantx-0.1.1.dist-info}/WHEEL +0 -0
- {superquantx-0.1.0.dist-info → superquantx-0.1.1.dist-info}/entry_points.txt +0 -0
@@ -5,7 +5,8 @@ and variational quantum algorithms.
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import logging
|
8
|
-
from
|
8
|
+
from collections.abc import Callable
|
9
|
+
from typing import Any
|
9
10
|
|
10
11
|
import numpy as np
|
11
12
|
|
@@ -26,11 +27,11 @@ except ImportError:
|
|
26
27
|
|
27
28
|
class PennyLaneBackend(BaseBackend):
|
28
29
|
"""PennyLane backend for quantum computing operations.
|
29
|
-
|
30
|
+
|
30
31
|
This backend provides access to PennyLane's quantum devices and
|
31
32
|
automatic differentiation capabilities for variational quantum
|
32
33
|
algorithms.
|
33
|
-
|
34
|
+
|
34
35
|
Args:
|
35
36
|
device: PennyLane device name ('default.qubit', 'qiskit.aer', etc.)
|
36
37
|
wires: Number of qubits/wires
|
@@ -86,19 +87,19 @@ class PennyLaneBackend(BaseBackend):
|
|
86
87
|
|
87
88
|
return circuit_template
|
88
89
|
|
89
|
-
def add_gate(self, circuit: Callable, gate: str, qubits:
|
90
|
-
params:
|
90
|
+
def add_gate(self, circuit: Callable, gate: str, qubits: int | list[int],
|
91
|
+
params: list[float] | None = None) -> Callable:
|
91
92
|
"""Add a quantum gate to the circuit (conceptual - PennyLane uses functions)."""
|
92
93
|
# In PennyLane, gates are added within quantum functions
|
93
94
|
# This method is more for compatibility with the base interface
|
94
95
|
logger.debug(f"Gate {gate} would be added to qubits {qubits} with params {params}")
|
95
96
|
return circuit
|
96
97
|
|
97
|
-
def add_measurement(self, circuit: Callable, qubits:
|
98
|
+
def add_measurement(self, circuit: Callable, qubits: list[int] | None = None) -> Callable:
|
98
99
|
"""Add measurement operations (conceptual in PennyLane)."""
|
99
100
|
return circuit
|
100
101
|
|
101
|
-
def execute_circuit(self, circuit: Callable, shots:
|
102
|
+
def execute_circuit(self, circuit: Callable, shots: int | None = None) -> dict[str, Any]:
|
102
103
|
"""Execute quantum circuit and return results."""
|
103
104
|
try:
|
104
105
|
# Create QNode
|
@@ -221,7 +222,7 @@ class PennyLaneBackend(BaseBackend):
|
|
221
222
|
return angle_encoding_map
|
222
223
|
|
223
224
|
def compute_kernel_matrix(self, X1: np.ndarray, X2: np.ndarray,
|
224
|
-
feature_map: Callable, shots:
|
225
|
+
feature_map: Callable, shots: int | None = None) -> np.ndarray:
|
225
226
|
"""Compute quantum kernel matrix using PennyLane."""
|
226
227
|
n1, n2 = len(X1), len(X2)
|
227
228
|
kernel_matrix = np.zeros((n1, n2))
|
@@ -376,7 +377,7 @@ class PennyLaneBackend(BaseBackend):
|
|
376
377
|
return uccsd_circuit
|
377
378
|
|
378
379
|
def compute_expectation(self, circuit: Callable, hamiltonian: Any,
|
379
|
-
shots:
|
380
|
+
shots: int | None = None) -> float:
|
380
381
|
"""Compute expectation value of Hamiltonian."""
|
381
382
|
try:
|
382
383
|
# If hamiltonian is a PennyLane Hamiltonian
|
@@ -400,7 +401,7 @@ class PennyLaneBackend(BaseBackend):
|
|
400
401
|
logger.error(f"Expectation computation failed: {e}")
|
401
402
|
return 0.0
|
402
403
|
|
403
|
-
def _compute_matrix_expectation(self, circuit: Callable, H: np.ndarray, shots:
|
404
|
+
def _compute_matrix_expectation(self, circuit: Callable, H: np.ndarray, shots: int | None) -> float:
|
404
405
|
"""Compute expectation value for matrix Hamiltonian."""
|
405
406
|
# Get statevector
|
406
407
|
statevector = self.get_statevector(circuit)
|
@@ -409,7 +410,7 @@ class PennyLaneBackend(BaseBackend):
|
|
409
410
|
expectation = np.real(np.conj(statevector) @ H @ statevector)
|
410
411
|
return float(expectation)
|
411
412
|
|
412
|
-
def get_version_info(self) ->
|
413
|
+
def get_version_info(self) -> dict[str, Any]:
|
413
414
|
"""Get PennyLane version information."""
|
414
415
|
info = super().get_version_info()
|
415
416
|
info.update({
|
@@ -5,7 +5,7 @@ operations and access to IBM Quantum hardware.
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import logging
|
8
|
-
from typing import TYPE_CHECKING, Any
|
8
|
+
from typing import TYPE_CHECKING, Any
|
9
9
|
|
10
10
|
import numpy as np
|
11
11
|
|
@@ -52,10 +52,10 @@ except ImportError:
|
|
52
52
|
|
53
53
|
class QiskitBackend(BaseBackend):
|
54
54
|
"""Qiskit backend for quantum computing operations.
|
55
|
-
|
55
|
+
|
56
56
|
This backend provides access to Qiskit simulators and IBM Quantum
|
57
57
|
hardware for quantum algorithm execution.
|
58
|
-
|
58
|
+
|
59
59
|
Args:
|
60
60
|
device: Qiskit backend name ('aer_simulator', 'ibmq_qasm_simulator', etc.)
|
61
61
|
provider: IBM Quantum provider (if using IBMQ)
|
@@ -64,7 +64,7 @@ class QiskitBackend(BaseBackend):
|
|
64
64
|
|
65
65
|
"""
|
66
66
|
|
67
|
-
def __init__(self, device: str = 'aer_simulator', provider:
|
67
|
+
def __init__(self, device: str = 'aer_simulator', provider: str | None = None,
|
68
68
|
shots: int = 1024, **kwargs):
|
69
69
|
if not QISKIT_AVAILABLE:
|
70
70
|
raise ImportError("Qiskit is required for QiskitBackend. Install with: pip install qiskit")
|
@@ -130,8 +130,8 @@ class QiskitBackend(BaseBackend):
|
|
130
130
|
circuit = QuantumCircuit(qreg, creg)
|
131
131
|
return circuit
|
132
132
|
|
133
|
-
def add_gate(self, circuit: Any, gate: str, qubits:
|
134
|
-
params:
|
133
|
+
def add_gate(self, circuit: Any, gate: str, qubits: int | list[int],
|
134
|
+
params: list[float] | None = None) -> Any:
|
135
135
|
"""Add a quantum gate to the circuit."""
|
136
136
|
if isinstance(qubits, int):
|
137
137
|
qubits = [qubits]
|
@@ -169,7 +169,7 @@ class QiskitBackend(BaseBackend):
|
|
169
169
|
|
170
170
|
return circuit
|
171
171
|
|
172
|
-
def add_measurement(self, circuit: Any, qubits:
|
172
|
+
def add_measurement(self, circuit: Any, qubits: list[int] | None = None) -> Any:
|
173
173
|
"""Add measurement operations to the circuit."""
|
174
174
|
if qubits is None:
|
175
175
|
qubits = list(range(circuit.num_qubits))
|
@@ -180,7 +180,7 @@ class QiskitBackend(BaseBackend):
|
|
180
180
|
|
181
181
|
return circuit
|
182
182
|
|
183
|
-
def execute_circuit(self, circuit: Any, shots:
|
183
|
+
def execute_circuit(self, circuit: Any, shots: int | None = None) -> dict[str, Any]:
|
184
184
|
"""Execute quantum circuit and return results."""
|
185
185
|
shots = shots or self.shots
|
186
186
|
|
@@ -293,7 +293,7 @@ class QiskitBackend(BaseBackend):
|
|
293
293
|
return circuit
|
294
294
|
|
295
295
|
def compute_kernel_matrix(self, X1: np.ndarray, X2: np.ndarray,
|
296
|
-
feature_map: QuantumCircuit, shots:
|
296
|
+
feature_map: QuantumCircuit, shots: int | None = None) -> np.ndarray:
|
297
297
|
"""Compute quantum kernel matrix using Qiskit."""
|
298
298
|
n1, n2 = len(X1), len(X2)
|
299
299
|
kernel_matrix = np.zeros((n1, n2))
|
@@ -377,7 +377,7 @@ class QiskitBackend(BaseBackend):
|
|
377
377
|
return circuit
|
378
378
|
|
379
379
|
def compute_expectation(self, circuit: Any, hamiltonian: Any,
|
380
|
-
shots:
|
380
|
+
shots: int | None = None) -> float:
|
381
381
|
"""Compute expectation value of Hamiltonian."""
|
382
382
|
try:
|
383
383
|
# For Qiskit, we need to decompose Hamiltonian into Pauli terms
|
@@ -405,7 +405,7 @@ class QiskitBackend(BaseBackend):
|
|
405
405
|
circuit.h(i)
|
406
406
|
|
407
407
|
# QAOA layers
|
408
|
-
for gamma, beta in zip(gammas, betas):
|
408
|
+
for gamma, beta in zip(gammas, betas, strict=False):
|
409
409
|
# Problem Hamiltonian layer
|
410
410
|
self._apply_problem_hamiltonian(circuit, gamma, problem_instance)
|
411
411
|
|
@@ -434,7 +434,7 @@ class QiskitBackend(BaseBackend):
|
|
434
434
|
for i in range(circuit.num_qubits):
|
435
435
|
circuit.rx(2 * beta, i)
|
436
436
|
|
437
|
-
def get_version_info(self) ->
|
437
|
+
def get_version_info(self) -> dict[str, Any]:
|
438
438
|
"""Get Qiskit version information."""
|
439
439
|
info = super().get_version_info()
|
440
440
|
|
@@ -5,7 +5,8 @@ require external quantum computing libraries, useful for testing and fallback.
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import logging
|
8
|
-
from
|
8
|
+
from collections.abc import Callable
|
9
|
+
from typing import Any
|
9
10
|
|
10
11
|
import numpy as np
|
11
12
|
|
@@ -22,7 +23,7 @@ class QuantumState:
|
|
22
23
|
self.state = np.zeros(2**n_qubits, dtype=complex)
|
23
24
|
self.state[0] = 1.0 # |00...0⟩ state
|
24
25
|
|
25
|
-
def apply_gate(self, gate_matrix: np.ndarray, qubits:
|
26
|
+
def apply_gate(self, gate_matrix: np.ndarray, qubits: list[int]) -> None:
|
26
27
|
"""Apply gate matrix to specified qubits."""
|
27
28
|
if len(qubits) == 1:
|
28
29
|
self._apply_single_qubit_gate(gate_matrix, qubits[0])
|
@@ -56,7 +57,7 @@ class QuantumState:
|
|
56
57
|
# Apply gate
|
57
58
|
self.state = full_gate @ self.state
|
58
59
|
|
59
|
-
def _apply_two_qubit_gate(self, gate: np.ndarray, qubits:
|
60
|
+
def _apply_two_qubit_gate(self, gate: np.ndarray, qubits: list[int]) -> None:
|
60
61
|
"""Apply two qubit gate."""
|
61
62
|
# Simplified implementation for CNOT and other 2-qubit gates
|
62
63
|
q1, q2 = qubits
|
@@ -95,7 +96,7 @@ class QuantumState:
|
|
95
96
|
return False
|
96
97
|
return True
|
97
98
|
|
98
|
-
def measure(self, shots: int = 1024) ->
|
99
|
+
def measure(self, shots: int = 1024) -> dict[str, int]:
|
99
100
|
"""Measure the quantum state."""
|
100
101
|
probabilities = np.abs(self.state)**2
|
101
102
|
|
@@ -116,11 +117,11 @@ class QuantumState:
|
|
116
117
|
|
117
118
|
class SimulatorBackend(BaseBackend):
|
118
119
|
"""Pure Python quantum simulator backend.
|
119
|
-
|
120
|
+
|
120
121
|
This backend provides a simple quantum simulator implementation
|
121
122
|
that doesn't require external libraries. Useful for testing,
|
122
123
|
development, and as a fallback when other backends are unavailable.
|
123
|
-
|
124
|
+
|
124
125
|
Args:
|
125
126
|
device: Device name (always 'simulator')
|
126
127
|
max_qubits: Maximum number of qubits to simulate
|
@@ -140,6 +141,8 @@ class SimulatorBackend(BaseBackend):
|
|
140
141
|
'supports_backprop': False,
|
141
142
|
'supports_hardware': False,
|
142
143
|
'supports_noise_models': False,
|
144
|
+
'supports_measurements': True, # Can perform measurements
|
145
|
+
'supports_parameterized_circuits': True, # Can handle parameterized circuits
|
143
146
|
}
|
144
147
|
|
145
148
|
# Gate matrices
|
@@ -149,10 +152,10 @@ class SimulatorBackend(BaseBackend):
|
|
149
152
|
"""Initialize simulator backend."""
|
150
153
|
logger.info(f"Initialized Python quantum simulator with max {self.max_qubits} qubits")
|
151
154
|
|
152
|
-
def _define_gates(self) ->
|
155
|
+
def _define_gates(self) -> dict[str, np.ndarray]:
|
153
156
|
"""Define quantum gate matrices."""
|
154
157
|
# Pauli matrices
|
155
|
-
|
158
|
+
identity = np.array([[1, 0], [0, 1]], dtype=complex)
|
156
159
|
X = np.array([[0, 1], [1, 0]], dtype=complex)
|
157
160
|
Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
|
158
161
|
Z = np.array([[1, 0], [0, -1]], dtype=complex)
|
@@ -189,7 +192,7 @@ class SimulatorBackend(BaseBackend):
|
|
189
192
|
], dtype=complex)
|
190
193
|
|
191
194
|
return {
|
192
|
-
'I':
|
195
|
+
'I': identity, 'X': X, 'Y': Y, 'Z': Z, 'H': H, 'S': S, 'T': T,
|
193
196
|
'CNOT': CNOT, 'CX': CNOT, 'CZ': CZ, 'SWAP': SWAP,
|
194
197
|
'PAULI_X': X, 'PAULI_Y': Y, 'PAULI_Z': Z, 'HADAMARD': H
|
195
198
|
}
|
@@ -222,8 +225,8 @@ class SimulatorBackend(BaseBackend):
|
|
222
225
|
|
223
226
|
return QuantumState(n_qubits)
|
224
227
|
|
225
|
-
def add_gate(self, circuit: QuantumState, gate: str, qubits:
|
226
|
-
params:
|
228
|
+
def add_gate(self, circuit: QuantumState, gate: str, qubits: int | list[int],
|
229
|
+
params: list[float] | None = None) -> QuantumState:
|
227
230
|
"""Add a quantum gate to the circuit."""
|
228
231
|
if isinstance(qubits, int):
|
229
232
|
qubits = [qubits]
|
@@ -257,7 +260,7 @@ class SimulatorBackend(BaseBackend):
|
|
257
260
|
|
258
261
|
return circuit
|
259
262
|
|
260
|
-
def _apply_toffoli(self, circuit: QuantumState, qubits:
|
263
|
+
def _apply_toffoli(self, circuit: QuantumState, qubits: list[int]) -> None:
|
261
264
|
"""Apply Toffoli gate (simplified implementation)."""
|
262
265
|
# This is a simplified implementation
|
263
266
|
# Full implementation would require proper 3-qubit gate matrix
|
@@ -268,12 +271,12 @@ class SimulatorBackend(BaseBackend):
|
|
268
271
|
cnot_matrix = self.gates['CNOT']
|
269
272
|
circuit.apply_gate(cnot_matrix, qubits[1:3])
|
270
273
|
|
271
|
-
def add_measurement(self, circuit: QuantumState, qubits:
|
274
|
+
def add_measurement(self, circuit: QuantumState, qubits: list[int] | None = None) -> QuantumState:
|
272
275
|
"""Add measurement operations (no-op in this implementation)."""
|
273
276
|
# Measurements are handled in execute_circuit
|
274
277
|
return circuit
|
275
278
|
|
276
|
-
def execute_circuit(self, circuit: QuantumState, shots:
|
279
|
+
def execute_circuit(self, circuit: QuantumState, shots: int | None = None) -> dict[str, Any]:
|
277
280
|
"""Execute quantum circuit and return results."""
|
278
281
|
shots = shots or self.shots
|
279
282
|
|
@@ -310,7 +313,7 @@ class SimulatorBackend(BaseBackend):
|
|
310
313
|
# ========================================================================
|
311
314
|
|
312
315
|
def compute_kernel_matrix(self, X1: np.ndarray, X2: np.ndarray,
|
313
|
-
feature_map: Any, shots:
|
316
|
+
feature_map: Any, shots: int | None = None) -> np.ndarray:
|
314
317
|
"""Compute quantum kernel matrix using simulator."""
|
315
318
|
n1, n2 = len(X1), len(X2)
|
316
319
|
kernel_matrix = np.zeros((n1, n2))
|
@@ -423,7 +426,7 @@ class SimulatorBackend(BaseBackend):
|
|
423
426
|
return ansatz_circuit
|
424
427
|
|
425
428
|
def compute_expectation(self, circuit: QuantumState, hamiltonian: Any,
|
426
|
-
shots:
|
429
|
+
shots: int | None = None) -> float:
|
427
430
|
"""Compute expectation value of Hamiltonian."""
|
428
431
|
try:
|
429
432
|
if isinstance(hamiltonian, np.ndarray):
|
@@ -440,7 +443,7 @@ class SimulatorBackend(BaseBackend):
|
|
440
443
|
logger.error(f"Expectation computation failed: {e}")
|
441
444
|
return 0.0
|
442
445
|
|
443
|
-
def get_version_info(self) ->
|
446
|
+
def get_version_info(self) -> dict[str, Any]:
|
444
447
|
"""Get simulator version information."""
|
445
448
|
info = super().get_version_info()
|
446
449
|
info.update({
|
@@ -450,6 +453,17 @@ class SimulatorBackend(BaseBackend):
|
|
450
453
|
})
|
451
454
|
return info
|
452
455
|
|
456
|
+
def get_backend_info(self) -> dict[str, Any]:
|
457
|
+
"""Get backend information."""
|
458
|
+
return {
|
459
|
+
'backend_name': self.__class__.__name__,
|
460
|
+
'device': self.device_name,
|
461
|
+
'capabilities': self.capabilities,
|
462
|
+
'simulator_type': 'pure_python',
|
463
|
+
'max_qubits': self.max_qubits,
|
464
|
+
'available_gates': list(self.gates.keys()),
|
465
|
+
}
|
466
|
+
|
453
467
|
def is_available(self) -> bool:
|
454
468
|
"""Check if the backend is available."""
|
455
469
|
return True
|
@@ -5,7 +5,7 @@ hardware for advanced quantum circuit compilation and optimization.
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import logging
|
8
|
-
from typing import Any
|
8
|
+
from typing import Any
|
9
9
|
|
10
10
|
import numpy as np
|
11
11
|
|
@@ -47,21 +47,21 @@ except ImportError:
|
|
47
47
|
|
48
48
|
class TKETBackend(BaseBackend):
|
49
49
|
"""TKET (Quantum Toolkit) backend for quantum computing operations.
|
50
|
-
|
50
|
+
|
51
51
|
This backend provides access to TKET's quantum circuit compilation,
|
52
52
|
optimization, and execution capabilities, including Quantinuum hardware.
|
53
|
-
|
53
|
+
|
54
54
|
Args:
|
55
55
|
device: Device name (e.g., 'aer_simulator', 'H1-1E', 'H1-2E', 'simulator')
|
56
56
|
shots: Number of measurement shots
|
57
57
|
machine: Specific Quantinuum machine for hardware execution
|
58
58
|
api_key: Quantinuum API key (required for hardware)
|
59
59
|
**kwargs: Additional backend configuration
|
60
|
-
|
60
|
+
|
61
61
|
Example:
|
62
62
|
>>> # Local simulator
|
63
63
|
>>> backend = TKETBackend(device='aer_simulator')
|
64
|
-
>>>
|
64
|
+
>>>
|
65
65
|
>>> # Quantinuum hardware (requires API key)
|
66
66
|
>>> backend = TKETBackend(
|
67
67
|
... device='H1-1E',
|
@@ -74,8 +74,8 @@ class TKETBackend(BaseBackend):
|
|
74
74
|
self,
|
75
75
|
device: str = 'aer_simulator',
|
76
76
|
shots: int = 1024,
|
77
|
-
machine:
|
78
|
-
api_key:
|
77
|
+
machine: str | None = None,
|
78
|
+
api_key: str | None = None,
|
79
79
|
**kwargs
|
80
80
|
) -> None:
|
81
81
|
if not TKET_AVAILABLE:
|
@@ -150,7 +150,7 @@ class TKETBackend(BaseBackend):
|
|
150
150
|
device_info = self._backend.device
|
151
151
|
if hasattr(device_info, 'n_nodes'):
|
152
152
|
return device_info.n_nodes
|
153
|
-
except:
|
153
|
+
except (AttributeError, Exception):
|
154
154
|
pass
|
155
155
|
|
156
156
|
# Default estimates based on device name
|
@@ -163,7 +163,7 @@ class TKETBackend(BaseBackend):
|
|
163
163
|
else:
|
164
164
|
return 32 # Conservative estimate
|
165
165
|
|
166
|
-
def _get_native_gates(self) ->
|
166
|
+
def _get_native_gates(self) -> list[str]:
|
167
167
|
"""Get native gates supported by TKET."""
|
168
168
|
# TKET supports a rich set of gates
|
169
169
|
return [
|
@@ -187,8 +187,8 @@ class TKETBackend(BaseBackend):
|
|
187
187
|
circuit = Circuit(n_qubits)
|
188
188
|
return circuit
|
189
189
|
|
190
|
-
def add_gate(self, circuit: Circuit, gate: str, qubits:
|
191
|
-
params:
|
190
|
+
def add_gate(self, circuit: Circuit, gate: str, qubits: int | list[int],
|
191
|
+
params: list[float] | None = None) -> Circuit:
|
192
192
|
"""Add a quantum gate to the circuit."""
|
193
193
|
if isinstance(qubits, int):
|
194
194
|
qubits = [qubits]
|
@@ -239,7 +239,7 @@ class TKETBackend(BaseBackend):
|
|
239
239
|
|
240
240
|
return circuit
|
241
241
|
|
242
|
-
def add_measurement(self, circuit: Circuit, qubits:
|
242
|
+
def add_measurement(self, circuit: Circuit, qubits: int | list[int]) -> Circuit:
|
243
243
|
"""Add measurement instructions to specified qubits."""
|
244
244
|
if isinstance(qubits, int):
|
245
245
|
qubits = [qubits]
|
@@ -254,7 +254,7 @@ class TKETBackend(BaseBackend):
|
|
254
254
|
|
255
255
|
return circuit
|
256
256
|
|
257
|
-
def execute_circuit(self, circuit: Circuit, shots:
|
257
|
+
def execute_circuit(self, circuit: Circuit, shots: int | None = None) -> dict[str, Any]:
|
258
258
|
"""Execute quantum circuit and return results."""
|
259
259
|
shots = shots or self.shots
|
260
260
|
|
@@ -360,7 +360,7 @@ class TKETBackend(BaseBackend):
|
|
360
360
|
logger.error(f"Circuit optimization failed: {e}")
|
361
361
|
return circuit
|
362
362
|
|
363
|
-
def create_parameterized_circuit(self, n_qubits: int, n_params: int) ->
|
363
|
+
def create_parameterized_circuit(self, n_qubits: int, n_params: int) -> tuple[Circuit, list[str]]:
|
364
364
|
"""Create a parameterized quantum circuit for variational algorithms."""
|
365
365
|
from pytket.circuit import fresh_symbol
|
366
366
|
|
@@ -376,7 +376,7 @@ class TKETBackend(BaseBackend):
|
|
376
376
|
|
377
377
|
return circuit, param_names
|
378
378
|
|
379
|
-
def bind_parameters(self, circuit: Circuit, param_values:
|
379
|
+
def bind_parameters(self, circuit: Circuit, param_values: dict[str, float]) -> Circuit:
|
380
380
|
"""Bind parameter values to parameterized circuit."""
|
381
381
|
try:
|
382
382
|
bound_circuit = circuit.copy()
|
@@ -384,7 +384,7 @@ class TKETBackend(BaseBackend):
|
|
384
384
|
# Create symbol substitution map
|
385
385
|
if hasattr(circuit, '_symbols'):
|
386
386
|
symbol_map = {}
|
387
|
-
for symbol, name in zip(circuit._symbols, circuit._param_names):
|
387
|
+
for symbol, name in zip(circuit._symbols, circuit._param_names, strict=False):
|
388
388
|
if name in param_values:
|
389
389
|
symbol_map[symbol] = param_values[name]
|
390
390
|
|
@@ -397,8 +397,8 @@ class TKETBackend(BaseBackend):
|
|
397
397
|
logger.error(f"Parameter binding failed: {e}")
|
398
398
|
return circuit
|
399
399
|
|
400
|
-
def expectation_value(self, circuit: Circuit, observable:
|
401
|
-
shots:
|
400
|
+
def expectation_value(self, circuit: Circuit, observable: str | np.ndarray,
|
401
|
+
shots: int | None = None) -> float:
|
402
402
|
"""Calculate expectation value of observable using TKET."""
|
403
403
|
shots = shots or self.shots
|
404
404
|
|
@@ -436,7 +436,7 @@ class TKETBackend(BaseBackend):
|
|
436
436
|
# Backend Information
|
437
437
|
# ========================================================================
|
438
438
|
|
439
|
-
def get_backend_info(self) ->
|
439
|
+
def get_backend_info(self) -> dict[str, Any]:
|
440
440
|
"""Get information about the TKET backend."""
|
441
441
|
info = {
|
442
442
|
'backend_name': 'tket',
|
@@ -459,21 +459,21 @@ class TKETBackend(BaseBackend):
|
|
459
459
|
|
460
460
|
return info
|
461
461
|
|
462
|
-
def get_version_info(self) ->
|
462
|
+
def get_version_info(self) -> dict[str, str]:
|
463
463
|
"""Get version information for TKET dependencies."""
|
464
464
|
version_info = {'backend_version': '1.0.0'}
|
465
465
|
|
466
466
|
try:
|
467
467
|
import pytket
|
468
468
|
version_info['pytket'] = pytket.__version__
|
469
|
-
except:
|
469
|
+
except (ImportError, AttributeError):
|
470
470
|
pass
|
471
471
|
|
472
472
|
if QUANTINUUM_AVAILABLE:
|
473
473
|
try:
|
474
474
|
import pytket.extensions.quantinuum
|
475
475
|
version_info['pytket_quantinuum'] = getattr(pytket.extensions.quantinuum, '__version__', 'unknown')
|
476
|
-
except:
|
476
|
+
except (ImportError, AttributeError):
|
477
477
|
pass
|
478
478
|
|
479
479
|
return version_info
|
@@ -482,7 +482,7 @@ class TKETBackend(BaseBackend):
|
|
482
482
|
"""Check if the backend is available and properly configured."""
|
483
483
|
return TKET_AVAILABLE
|
484
484
|
|
485
|
-
def get_circuit_info(self) ->
|
485
|
+
def get_circuit_info(self) -> dict[str, Any]:
|
486
486
|
"""Get information about circuit execution capabilities."""
|
487
487
|
return {
|
488
488
|
'max_qubits': self._get_max_qubits(),
|
superquantx/circuits.py
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
import json
|
5
5
|
from copy import deepcopy
|
6
|
-
from typing import Any
|
6
|
+
from typing import Any
|
7
7
|
|
8
8
|
from pydantic import BaseModel, Field
|
9
9
|
|
@@ -13,14 +13,14 @@ class QuantumGate(BaseModel):
|
|
13
13
|
"""
|
14
14
|
|
15
15
|
name: str = Field(..., description="Gate name (e.g., 'H', 'CNOT', 'RZ')")
|
16
|
-
qubits:
|
17
|
-
parameters:
|
18
|
-
classical_condition:
|
16
|
+
qubits: list[int] = Field(..., description="Target qubit indices")
|
17
|
+
parameters: list[float] = Field(default_factory=list, description="Gate parameters")
|
18
|
+
classical_condition: tuple[str, int] | None = Field(
|
19
19
|
default=None,
|
20
20
|
description="Classical register condition (register_name, value)"
|
21
21
|
)
|
22
22
|
|
23
|
-
def to_dict(self) ->
|
23
|
+
def to_dict(self) -> dict[str, Any]:
|
24
24
|
"""Convert gate to dictionary representation"""
|
25
25
|
return {
|
26
26
|
"name": self.name,
|
@@ -30,7 +30,7 @@ class QuantumGate(BaseModel):
|
|
30
30
|
}
|
31
31
|
|
32
32
|
@classmethod
|
33
|
-
def from_dict(cls, data:
|
33
|
+
def from_dict(cls, data: dict[str, Any]) -> "QuantumGate":
|
34
34
|
"""Create gate from dictionary representation"""
|
35
35
|
return cls(**data)
|
36
36
|
|
@@ -62,7 +62,7 @@ class QuantumRegister(BaseModel):
|
|
62
62
|
|
63
63
|
class QuantumCircuit:
|
64
64
|
"""Quantum circuit representation with gate operations and measurements
|
65
|
-
|
65
|
+
|
66
66
|
This class provides a high-level interface for building and manipulating
|
67
67
|
quantum circuits compatible with multiple quantum computing frameworks.
|
68
68
|
"""
|
@@ -70,11 +70,11 @@ class QuantumCircuit:
|
|
70
70
|
def __init__(
|
71
71
|
self,
|
72
72
|
num_qubits: int,
|
73
|
-
num_classical_bits:
|
74
|
-
name:
|
73
|
+
num_classical_bits: int | None = None,
|
74
|
+
name: str | None = None
|
75
75
|
):
|
76
76
|
"""Initialize a quantum circuit
|
77
|
-
|
77
|
+
|
78
78
|
Args:
|
79
79
|
num_qubits: Number of qubits in the circuit
|
80
80
|
num_classical_bits: Number of classical bits (defaults to num_qubits)
|
@@ -85,16 +85,16 @@ class QuantumCircuit:
|
|
85
85
|
self.num_classical_bits = num_classical_bits or num_qubits
|
86
86
|
self.name = name or f"circuit_{id(self)}"
|
87
87
|
|
88
|
-
self.quantum_registers:
|
88
|
+
self.quantum_registers: list[QuantumRegister] = [
|
89
89
|
QuantumRegister(name="q", size=num_qubits)
|
90
90
|
]
|
91
|
-
self.classical_registers:
|
91
|
+
self.classical_registers: list[ClassicalRegister] = [
|
92
92
|
ClassicalRegister(name="c", size=self.num_classical_bits)
|
93
93
|
]
|
94
94
|
|
95
|
-
self.gates:
|
96
|
-
self.measurements:
|
97
|
-
self.barriers:
|
95
|
+
self.gates: list[QuantumGate] = []
|
96
|
+
self.measurements: list[tuple[int, int]] = [] # (qubit_index, classical_bit_index)
|
97
|
+
self.barriers: list[list[int]] = [] # Barrier positions
|
98
98
|
|
99
99
|
def __len__(self) -> int:
|
100
100
|
"""Return the number of gates in the circuit"""
|
@@ -107,7 +107,7 @@ class QuantumCircuit:
|
|
107
107
|
"""Create a deep copy of the circuit"""
|
108
108
|
return deepcopy(self)
|
109
109
|
|
110
|
-
def add_register(self, register:
|
110
|
+
def add_register(self, register: QuantumRegister | ClassicalRegister) -> None:
|
111
111
|
"""Add a quantum or classical register to the circuit"""
|
112
112
|
if isinstance(register, QuantumRegister):
|
113
113
|
self.quantum_registers.append(register)
|
@@ -260,7 +260,7 @@ class QuantumCircuit:
|
|
260
260
|
self.measure(i, i)
|
261
261
|
return self
|
262
262
|
|
263
|
-
def barrier(self, qubits:
|
263
|
+
def barrier(self, qubits: list[int] | None = None) -> "QuantumCircuit":
|
264
264
|
"""Add a barrier (prevents gate reordering across barrier)"""
|
265
265
|
if qubits is None:
|
266
266
|
qubits = list(range(self.num_qubits))
|
@@ -268,13 +268,13 @@ class QuantumCircuit:
|
|
268
268
|
return self
|
269
269
|
|
270
270
|
# Circuit composition
|
271
|
-
def compose(self, other: "QuantumCircuit", qubits:
|
271
|
+
def compose(self, other: "QuantumCircuit", qubits: list[int] | None = None) -> "QuantumCircuit":
|
272
272
|
"""Compose this circuit with another circuit
|
273
|
-
|
273
|
+
|
274
274
|
Args:
|
275
275
|
other: Circuit to compose with
|
276
276
|
qubits: Qubit mapping for the other circuit
|
277
|
-
|
277
|
+
|
278
278
|
Returns:
|
279
279
|
New composed circuit
|
280
280
|
|
@@ -354,7 +354,7 @@ class QuantumCircuit:
|
|
354
354
|
return gate
|
355
355
|
|
356
356
|
# Export functions
|
357
|
-
def to_dict(self) ->
|
357
|
+
def to_dict(self) -> dict[str, Any]:
|
358
358
|
"""Convert circuit to dictionary representation"""
|
359
359
|
return {
|
360
360
|
"name": self.name,
|
@@ -372,7 +372,7 @@ class QuantumCircuit:
|
|
372
372
|
return json.dumps(self.to_dict(), indent=indent)
|
373
373
|
|
374
374
|
@classmethod
|
375
|
-
def from_dict(cls, data:
|
375
|
+
def from_dict(cls, data: dict[str, Any]) -> "QuantumCircuit":
|
376
376
|
"""Create circuit from dictionary representation"""
|
377
377
|
circuit = cls(
|
378
378
|
num_qubits=data["num_qubits"],
|
@@ -400,10 +400,10 @@ class QuantumCircuit:
|
|
400
400
|
|
401
401
|
def draw(self, output: str = "text") -> str:
|
402
402
|
"""Draw the circuit in text format
|
403
|
-
|
403
|
+
|
404
404
|
Args:
|
405
405
|
output: Output format ("text" only for now)
|
406
|
-
|
406
|
+
|
407
407
|
Returns:
|
408
408
|
String representation of the circuit
|
409
409
|
|
@@ -417,7 +417,7 @@ class QuantumCircuit:
|
|
417
417
|
lines.append(line)
|
418
418
|
|
419
419
|
for gate in self.gates:
|
420
|
-
|
420
|
+
max(gate.qubits)
|
421
421
|
gate_repr = gate.name
|
422
422
|
|
423
423
|
if len(gate.qubits) == 1:
|