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.
Files changed (51) hide show
  1. superquantx/__init__.py +24 -12
  2. superquantx/algorithms/__init__.py +1 -1
  3. superquantx/algorithms/base_algorithm.py +36 -36
  4. superquantx/algorithms/hybrid_classifier.py +22 -22
  5. superquantx/algorithms/qaoa.py +29 -28
  6. superquantx/algorithms/quantum_agents.py +57 -56
  7. superquantx/algorithms/quantum_kmeans.py +17 -17
  8. superquantx/algorithms/quantum_nn.py +18 -18
  9. superquantx/algorithms/quantum_pca.py +26 -26
  10. superquantx/algorithms/quantum_svm.py +26 -25
  11. superquantx/algorithms/vqe.py +40 -39
  12. superquantx/algorithms.py +56 -55
  13. superquantx/backends/__init__.py +12 -12
  14. superquantx/backends/base_backend.py +25 -24
  15. superquantx/backends/braket_backend.py +21 -21
  16. superquantx/backends/cirq_backend.py +26 -26
  17. superquantx/backends/ocean_backend.py +38 -38
  18. superquantx/backends/pennylane_backend.py +12 -11
  19. superquantx/backends/qiskit_backend.py +12 -12
  20. superquantx/backends/simulator_backend.py +31 -17
  21. superquantx/backends/tket_backend.py +23 -23
  22. superquantx/circuits.py +25 -25
  23. superquantx/cli/commands.py +6 -7
  24. superquantx/cli/main.py +5 -6
  25. superquantx/client.py +42 -42
  26. superquantx/config.py +14 -14
  27. superquantx/datasets/__init__.py +58 -0
  28. superquantx/datasets/molecular.py +307 -0
  29. superquantx/datasets/preprocessing.py +279 -0
  30. superquantx/datasets/quantum_datasets.py +277 -0
  31. superquantx/datasets/synthetic.py +300 -0
  32. superquantx/exceptions.py +29 -29
  33. superquantx/gates.py +26 -26
  34. superquantx/logging_config.py +29 -29
  35. superquantx/measurements.py +53 -54
  36. superquantx/ml.py +51 -52
  37. superquantx/noise.py +49 -49
  38. superquantx/utils/benchmarking.py +41 -36
  39. superquantx/utils/classical_utils.py +32 -32
  40. superquantx/utils/feature_mapping.py +40 -35
  41. superquantx/utils/optimization.py +28 -26
  42. superquantx/utils/quantum_utils.py +47 -48
  43. superquantx/utils/visualization.py +49 -49
  44. superquantx/version.py +3 -3
  45. {superquantx-0.1.0.dist-info → superquantx-0.1.1.dist-info}/METADATA +18 -16
  46. superquantx-0.1.1.dist-info/RECORD +51 -0
  47. superquantx-0.1.1.dist-info/licenses/LICENSE +180 -0
  48. superquantx-0.1.0.dist-info/RECORD +0 -46
  49. superquantx-0.1.0.dist-info/licenses/LICENSE +0 -21
  50. {superquantx-0.1.0.dist-info → superquantx-0.1.1.dist-info}/WHEEL +0 -0
  51. {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 typing import Any, Callable, Dict, List, Optional, Union
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: Union[int, List[int]],
90
- params: Optional[List[float]] = None) -> Callable:
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: Optional[List[int]] = None) -> Callable:
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: Optional[int] = None) -> Dict[str, Any]:
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: Optional[int] = None) -> np.ndarray:
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: Optional[int] = None) -> float:
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: Optional[int]) -> float:
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) -> Dict[str, Any]:
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, Dict, List, Optional, Union
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: Optional[str] = None,
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: Union[int, List[int]],
134
- params: Optional[List[float]] = None) -> Any:
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: Optional[List[int]] = None) -> Any:
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: Optional[int] = None) -> Dict[str, Any]:
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: Optional[int] = None) -> np.ndarray:
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: Optional[int] = None) -> float:
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) -> Dict[str, Any]:
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 typing import Any, Callable, Dict, List, Optional, Union
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: List[int]) -> None:
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: List[int]) -> None:
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) -> Dict[str, int]:
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) -> Dict[str, np.ndarray]:
155
+ def _define_gates(self) -> dict[str, np.ndarray]:
153
156
  """Define quantum gate matrices."""
154
157
  # Pauli matrices
155
- I = np.array([[1, 0], [0, 1]], dtype=complex)
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': I, 'X': X, 'Y': Y, 'Z': Z, 'H': H, 'S': S, 'T': T,
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: Union[int, List[int]],
226
- params: Optional[List[float]] = None) -> QuantumState:
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: List[int]) -> None:
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: Optional[List[int]] = None) -> QuantumState:
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: Optional[int] = None) -> Dict[str, Any]:
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: Optional[int] = None) -> np.ndarray:
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: Optional[int] = None) -> float:
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) -> Dict[str, Any]:
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, Dict, List, Optional, Tuple, Union
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: Optional[str] = None,
78
- api_key: Optional[str] = None,
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) -> List[str]:
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: Union[int, List[int]],
191
- params: Optional[List[float]] = None) -> Circuit:
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: Union[int, List[int]]) -> Circuit:
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: Optional[int] = None) -> Dict[str, Any]:
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) -> Tuple[Circuit, List[str]]:
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: Dict[str, float]) -> Circuit:
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: Union[str, np.ndarray],
401
- shots: Optional[int] = None) -> float:
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) -> Dict[str, Any]:
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) -> Dict[str, str]:
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) -> Dict[str, Any]:
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, Dict, List, Optional, Tuple, Union
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: List[int] = Field(..., description="Target qubit indices")
17
- parameters: List[float] = Field(default_factory=list, description="Gate parameters")
18
- classical_condition: Optional[Tuple[str, int]] = Field(
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) -> Dict[str, Any]:
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: Dict[str, Any]) -> "QuantumGate":
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: Optional[int] = None,
74
- name: Optional[str] = None
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: List[QuantumRegister] = [
88
+ self.quantum_registers: list[QuantumRegister] = [
89
89
  QuantumRegister(name="q", size=num_qubits)
90
90
  ]
91
- self.classical_registers: List[ClassicalRegister] = [
91
+ self.classical_registers: list[ClassicalRegister] = [
92
92
  ClassicalRegister(name="c", size=self.num_classical_bits)
93
93
  ]
94
94
 
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
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: Union[QuantumRegister, ClassicalRegister]) -> None:
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: Optional[List[int]] = None) -> "QuantumCircuit":
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: Optional[List[int]] = None) -> "QuantumCircuit":
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) -> Dict[str, Any]:
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: Dict[str, Any]) -> "QuantumCircuit":
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
- max_qubit = max(gate.qubits)
420
+ max(gate.qubits)
421
421
  gate_repr = gate.name
422
422
 
423
423
  if len(gate.qubits) == 1: