superquantx 0.1.0__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 (46) hide show
  1. superquantx/__init__.py +321 -0
  2. superquantx/algorithms/__init__.py +55 -0
  3. superquantx/algorithms/base_algorithm.py +413 -0
  4. superquantx/algorithms/hybrid_classifier.py +628 -0
  5. superquantx/algorithms/qaoa.py +406 -0
  6. superquantx/algorithms/quantum_agents.py +1006 -0
  7. superquantx/algorithms/quantum_kmeans.py +575 -0
  8. superquantx/algorithms/quantum_nn.py +544 -0
  9. superquantx/algorithms/quantum_pca.py +499 -0
  10. superquantx/algorithms/quantum_svm.py +346 -0
  11. superquantx/algorithms/vqe.py +553 -0
  12. superquantx/algorithms.py +863 -0
  13. superquantx/backends/__init__.py +265 -0
  14. superquantx/backends/base_backend.py +321 -0
  15. superquantx/backends/braket_backend.py +420 -0
  16. superquantx/backends/cirq_backend.py +466 -0
  17. superquantx/backends/ocean_backend.py +491 -0
  18. superquantx/backends/pennylane_backend.py +419 -0
  19. superquantx/backends/qiskit_backend.py +451 -0
  20. superquantx/backends/simulator_backend.py +455 -0
  21. superquantx/backends/tket_backend.py +519 -0
  22. superquantx/circuits.py +447 -0
  23. superquantx/cli/__init__.py +28 -0
  24. superquantx/cli/commands.py +528 -0
  25. superquantx/cli/main.py +254 -0
  26. superquantx/client.py +298 -0
  27. superquantx/config.py +326 -0
  28. superquantx/exceptions.py +287 -0
  29. superquantx/gates.py +588 -0
  30. superquantx/logging_config.py +347 -0
  31. superquantx/measurements.py +702 -0
  32. superquantx/ml.py +936 -0
  33. superquantx/noise.py +760 -0
  34. superquantx/utils/__init__.py +83 -0
  35. superquantx/utils/benchmarking.py +523 -0
  36. superquantx/utils/classical_utils.py +575 -0
  37. superquantx/utils/feature_mapping.py +467 -0
  38. superquantx/utils/optimization.py +410 -0
  39. superquantx/utils/quantum_utils.py +456 -0
  40. superquantx/utils/visualization.py +654 -0
  41. superquantx/version.py +33 -0
  42. superquantx-0.1.0.dist-info/METADATA +365 -0
  43. superquantx-0.1.0.dist-info/RECORD +46 -0
  44. superquantx-0.1.0.dist-info/WHEEL +4 -0
  45. superquantx-0.1.0.dist-info/entry_points.txt +2 -0
  46. superquantx-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,519 @@
1
+ """TKET/Quantinuum backend implementation for SuperQuantX.
2
+
3
+ This module provides integration with TKET (Quantum Toolkit) and Quantinuum
4
+ hardware for advanced quantum circuit compilation and optimization.
5
+ """
6
+
7
+ import logging
8
+ from typing import Any, Dict, List, Optional, Tuple, Union
9
+
10
+ import numpy as np
11
+
12
+ from .base_backend import BaseBackend
13
+
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ # Try to import TKET/pytket
18
+ try:
19
+ from pytket import Circuit, OpType
20
+ from pytket.backends import Backend
21
+ from pytket.backends.simulator import AerBackend
22
+ from pytket.circuit import Bit, Qubit
23
+
24
+ # Try to import Quantinuum backend
25
+ try:
26
+ from pytket.extensions.quantinuum import QuantinuumBackend
27
+ QUANTINUUM_AVAILABLE = True
28
+ except ImportError:
29
+ QUANTINUUM_AVAILABLE = False
30
+
31
+ # Try to import other TKET backends
32
+ try:
33
+ from pytket.extensions.cirq import CirqBackend as TKETCirqBackend
34
+ from pytket.extensions.qiskit import AerStateBackend
35
+ TKET_EXTENSIONS_AVAILABLE = True
36
+ except ImportError:
37
+ TKET_EXTENSIONS_AVAILABLE = False
38
+
39
+ TKET_AVAILABLE = True
40
+
41
+ except ImportError:
42
+ TKET_AVAILABLE = False
43
+ QUANTINUUM_AVAILABLE = False
44
+ TKET_EXTENSIONS_AVAILABLE = False
45
+ Circuit = None
46
+ OpType = None
47
+
48
+ class TKETBackend(BaseBackend):
49
+ """TKET (Quantum Toolkit) backend for quantum computing operations.
50
+
51
+ This backend provides access to TKET's quantum circuit compilation,
52
+ optimization, and execution capabilities, including Quantinuum hardware.
53
+
54
+ Args:
55
+ device: Device name (e.g., 'aer_simulator', 'H1-1E', 'H1-2E', 'simulator')
56
+ shots: Number of measurement shots
57
+ machine: Specific Quantinuum machine for hardware execution
58
+ api_key: Quantinuum API key (required for hardware)
59
+ **kwargs: Additional backend configuration
60
+
61
+ Example:
62
+ >>> # Local simulator
63
+ >>> backend = TKETBackend(device='aer_simulator')
64
+ >>>
65
+ >>> # Quantinuum hardware (requires API key)
66
+ >>> backend = TKETBackend(
67
+ ... device='H1-1E',
68
+ ... api_key='your-quantinuum-api-key'
69
+ ... )
70
+
71
+ """
72
+
73
+ def __init__(
74
+ self,
75
+ device: str = 'aer_simulator',
76
+ shots: int = 1024,
77
+ machine: Optional[str] = None,
78
+ api_key: Optional[str] = None,
79
+ **kwargs
80
+ ) -> None:
81
+ if not TKET_AVAILABLE:
82
+ raise ImportError(
83
+ "TKET not available. Install with: pip install pytket"
84
+ )
85
+
86
+ self.device_name = device
87
+ self.machine = machine or device
88
+ self.api_key = api_key
89
+ self._backend = None
90
+
91
+ super().__init__(device=device, shots=shots, **kwargs)
92
+
93
+ def _initialize_backend(self) -> None:
94
+ """Initialize TKET backend and device."""
95
+ try:
96
+ if self.device_name in ['aer_simulator', 'simulator']:
97
+ # Use TKET Aer simulator
98
+ if TKET_EXTENSIONS_AVAILABLE:
99
+ from pytket.extensions.qiskit import AerBackend
100
+ self._backend = AerBackend()
101
+ else:
102
+ # Fallback to basic simulator
103
+ logger.warning("TKET extensions not available, using basic simulator")
104
+ self._backend = None
105
+
106
+ elif self.device_name.startswith('H') and '-' in self.device_name:
107
+ # Quantinuum hardware (H1-1E, H1-2E, H2-1, etc.)
108
+ if not QUANTINUUM_AVAILABLE:
109
+ raise ImportError("Quantinuum backend not available. Install with: pip install pytket-quantinuum")
110
+
111
+ if not self.api_key:
112
+ raise ValueError("API key required for Quantinuum hardware")
113
+
114
+ self._backend = QuantinuumBackend(
115
+ device_name=self.machine,
116
+ api_key=self.api_key
117
+ )
118
+ logger.info(f"Initialized Quantinuum backend: {self.machine}")
119
+
120
+ elif self.device_name in ['cirq', 'cirq_simulator']:
121
+ # TKET Cirq integration
122
+ if TKET_EXTENSIONS_AVAILABLE:
123
+ self._backend = TKETCirqBackend()
124
+ else:
125
+ raise ImportError("TKET Cirq extension not available")
126
+
127
+ else:
128
+ # Try to create generic backend
129
+ logger.warning(f"Unknown device {self.device_name}, using simulator fallback")
130
+ self._backend = None
131
+
132
+ self.capabilities = {
133
+ 'supports_measurements': True,
134
+ 'supports_parameterized_circuits': True,
135
+ 'supports_classical_control': True,
136
+ 'supports_mid_circuit_measurement': True,
137
+ 'max_qubits': self._get_max_qubits(),
138
+ 'native_gates': self._get_native_gates(),
139
+ 'supports_optimization': True, # TKET's key feature
140
+ }
141
+
142
+ except Exception as e:
143
+ logger.error(f"Failed to initialize TKET backend: {e}")
144
+ raise
145
+
146
+ def _get_max_qubits(self) -> int:
147
+ """Get maximum number of qubits for the device."""
148
+ if self._backend and hasattr(self._backend, 'device'):
149
+ try:
150
+ device_info = self._backend.device
151
+ if hasattr(device_info, 'n_nodes'):
152
+ return device_info.n_nodes
153
+ except:
154
+ pass
155
+
156
+ # Default estimates based on device name
157
+ if 'H1-1' in self.device_name:
158
+ return 20 # H1-1E
159
+ elif 'H1-2' in self.device_name:
160
+ return 56 # H1-2E
161
+ elif 'H2' in self.device_name:
162
+ return 32 # H2-1
163
+ else:
164
+ return 32 # Conservative estimate
165
+
166
+ def _get_native_gates(self) -> List[str]:
167
+ """Get native gates supported by TKET."""
168
+ # TKET supports a rich set of gates
169
+ return [
170
+ 'H', 'X', 'Y', 'Z', 'S', 'Sdg', 'T', 'Tdg', 'V', 'Vdg',
171
+ 'Rx', 'Ry', 'Rz', 'R1', 'U1', 'U2', 'U3',
172
+ 'CX', 'CY', 'CZ', 'CH', 'CV', 'CVdg', 'CS', 'CSdg',
173
+ 'CRx', 'CRy', 'CRz', 'CU1', 'CU2', 'CU3',
174
+ 'CCX', 'SWAP', 'CSWAP', 'ISWAP', 'PHASEDX',
175
+ 'ZZMax', 'XXPhase', 'YYPhase', 'ZZPhase'
176
+ ]
177
+
178
+ # ========================================================================
179
+ # Core Circuit Operations
180
+ # ========================================================================
181
+
182
+ def create_circuit(self, n_qubits: int) -> Circuit:
183
+ """Create a TKET quantum circuit."""
184
+ if n_qubits > self._get_max_qubits():
185
+ logger.warning(f"Requested {n_qubits} qubits exceeds device limit")
186
+
187
+ circuit = Circuit(n_qubits)
188
+ return circuit
189
+
190
+ def add_gate(self, circuit: Circuit, gate: str, qubits: Union[int, List[int]],
191
+ params: Optional[List[float]] = None) -> Circuit:
192
+ """Add a quantum gate to the circuit."""
193
+ if isinstance(qubits, int):
194
+ qubits = [qubits]
195
+
196
+ params = params or []
197
+
198
+ # Map gate names to TKET OpTypes
199
+ gate_mapping = {
200
+ 'i': OpType.noop, # Identity
201
+ 'x': OpType.X, 'y': OpType.Y, 'z': OpType.Z, 'h': OpType.H,
202
+ 's': OpType.S, 'sdg': OpType.Sdg, 't': OpType.T, 'tdg': OpType.Tdg,
203
+ 'rx': OpType.Rx, 'ry': OpType.Ry, 'rz': OpType.Rz,
204
+ 'cnot': OpType.CX, 'cx': OpType.CX, 'cz': OpType.CZ, 'cy': OpType.CY,
205
+ 'ch': OpType.CH, 'swap': OpType.SWAP,
206
+ 'ccnot': OpType.CCX, 'ccx': OpType.CCX, 'toffoli': OpType.CCX,
207
+ 'cswap': OpType.CSWAP, 'fredkin': OpType.CSWAP,
208
+ 'iswap': OpType.ISWAPMax,
209
+ 'u1': OpType.U1, 'u2': OpType.U2, 'u3': OpType.U3,
210
+ }
211
+
212
+ gate_upper = gate.upper()
213
+ gate_lower = gate.lower()
214
+
215
+ # Try exact match first, then case variations
216
+ op_type = None
217
+ if hasattr(OpType, gate_upper):
218
+ op_type = getattr(OpType, gate_upper)
219
+ elif gate_lower in gate_mapping:
220
+ op_type = gate_mapping[gate_lower]
221
+
222
+ if op_type is None:
223
+ raise ValueError(f"Gate '{gate}' not supported in TKET backend")
224
+
225
+ try:
226
+ # Convert qubit indices to TKET Qubit objects
227
+ tket_qubits = [circuit.qubits[q] for q in qubits]
228
+
229
+ if len(params) == 0:
230
+ # Parameter-less gates
231
+ circuit.add_gate(op_type, tket_qubits)
232
+ else:
233
+ # Parameterized gates
234
+ circuit.add_gate(op_type, tket_qubits, params)
235
+
236
+ except Exception as e:
237
+ logger.error(f"Failed to add gate {gate} to TKET circuit: {e}")
238
+ raise
239
+
240
+ return circuit
241
+
242
+ def add_measurement(self, circuit: Circuit, qubits: Union[int, List[int]]) -> Circuit:
243
+ """Add measurement instructions to specified qubits."""
244
+ if isinstance(qubits, int):
245
+ qubits = [qubits]
246
+
247
+ # TKET requires explicit bit allocation for measurements
248
+ n_bits = len(qubits)
249
+ if circuit.n_bits < n_bits:
250
+ circuit.add_c_register("c", n_bits - circuit.n_bits)
251
+
252
+ for i, qubit in enumerate(qubits):
253
+ circuit.Measure(circuit.qubits[qubit], circuit.bits[i])
254
+
255
+ return circuit
256
+
257
+ def execute_circuit(self, circuit: Circuit, shots: Optional[int] = None) -> Dict[str, Any]:
258
+ """Execute quantum circuit and return results."""
259
+ shots = shots or self.shots
260
+
261
+ try:
262
+ if self._backend is None:
263
+ # Simple simulation fallback
264
+ logger.warning("No TKET backend available, using simulation fallback")
265
+ n_qubits = circuit.n_qubits
266
+ n_bits = circuit.n_bits or n_qubits
267
+
268
+ # Generate random results for fallback
269
+ counts = {}
270
+ for _ in range(shots):
271
+ bitstring = ''.join([str(np.random.randint(0, 2)) for _ in range(n_bits)])
272
+ counts[bitstring] = counts.get(bitstring, 0) + 1
273
+
274
+ return {
275
+ 'counts': counts,
276
+ 'shots': shots,
277
+ 'success': True,
278
+ 'backend': 'tket_fallback',
279
+ }
280
+
281
+ # Compile circuit for backend
282
+ compiled_circuit = self._backend.get_compiled_circuit(circuit)
283
+
284
+ # Execute on backend
285
+ handle = self._backend.process_circuit(compiled_circuit, n_shots=shots)
286
+ result = self._backend.get_result(handle)
287
+
288
+ # Extract counts
289
+ counts_dict = {}
290
+ if hasattr(result, 'get_counts'):
291
+ counts_dict = result.get_counts()
292
+ elif hasattr(result, 'counts'):
293
+ counts_dict = result.counts
294
+ else:
295
+ logger.warning("Could not extract counts from TKET result")
296
+
297
+ return {
298
+ 'counts': counts_dict,
299
+ 'shots': shots,
300
+ 'success': True,
301
+ 'backend': self._backend.__class__.__name__,
302
+ 'compiled': True,
303
+ 'device': self.device_name,
304
+ }
305
+
306
+ except Exception as e:
307
+ logger.error(f"TKET circuit execution failed: {e}")
308
+ return {
309
+ 'counts': {},
310
+ 'shots': shots,
311
+ 'success': False,
312
+ 'error': str(e),
313
+ 'device': self.device_name,
314
+ }
315
+
316
+ # ========================================================================
317
+ # TKET-Specific Features
318
+ # ========================================================================
319
+
320
+ def optimize_circuit(self, circuit: Circuit, optimization_level: int = 2) -> Circuit:
321
+ """Optimize quantum circuit using TKET compiler passes."""
322
+ try:
323
+ from pytket.passes import (
324
+ CliffordSimp,
325
+ DecomposeBoxes,
326
+ OptimisePhaseGadgets,
327
+ RemoveRedundancies,
328
+ SequencePass,
329
+ )
330
+
331
+ optimized = circuit.copy()
332
+
333
+ if optimization_level >= 1:
334
+ # Basic optimization
335
+ basic_pass = SequencePass([
336
+ DecomposeBoxes(),
337
+ CliffordSimp(),
338
+ RemoveRedundancies()
339
+ ])
340
+ basic_pass.apply(optimized)
341
+
342
+ if optimization_level >= 2:
343
+ # Advanced optimization
344
+ advanced_pass = SequencePass([
345
+ OptimisePhaseGadgets(),
346
+ CliffordSimp(),
347
+ RemoveRedundancies()
348
+ ])
349
+ advanced_pass.apply(optimized)
350
+
351
+ if optimization_level >= 3 and self._backend:
352
+ # Backend-specific optimization
353
+ backend_pass = self._backend.default_compilation_pass()
354
+ backend_pass.apply(optimized)
355
+
356
+ logger.info(f"Circuit optimized: {circuit.n_gates} -> {optimized.n_gates} gates")
357
+ return optimized
358
+
359
+ except Exception as e:
360
+ logger.error(f"Circuit optimization failed: {e}")
361
+ return circuit
362
+
363
+ def create_parameterized_circuit(self, n_qubits: int, n_params: int) -> Tuple[Circuit, List[str]]:
364
+ """Create a parameterized quantum circuit for variational algorithms."""
365
+ from pytket.circuit import fresh_symbol
366
+
367
+ circuit = self.create_circuit(n_qubits)
368
+
369
+ # Create symbolic parameters
370
+ symbols = [fresh_symbol(f"theta_{i}") for i in range(n_params)]
371
+ param_names = [str(symbol) for symbol in symbols]
372
+
373
+ # Store parameter info
374
+ circuit._symbols = symbols
375
+ circuit._param_names = param_names
376
+
377
+ return circuit, param_names
378
+
379
+ def bind_parameters(self, circuit: Circuit, param_values: Dict[str, float]) -> Circuit:
380
+ """Bind parameter values to parameterized circuit."""
381
+ try:
382
+ bound_circuit = circuit.copy()
383
+
384
+ # Create symbol substitution map
385
+ if hasattr(circuit, '_symbols'):
386
+ symbol_map = {}
387
+ for symbol, name in zip(circuit._symbols, circuit._param_names):
388
+ if name in param_values:
389
+ symbol_map[symbol] = param_values[name]
390
+
391
+ # Substitute symbols with values
392
+ bound_circuit.symbol_substitution(symbol_map)
393
+
394
+ return bound_circuit
395
+
396
+ except Exception as e:
397
+ logger.error(f"Parameter binding failed: {e}")
398
+ return circuit
399
+
400
+ def expectation_value(self, circuit: Circuit, observable: Union[str, np.ndarray],
401
+ shots: Optional[int] = None) -> float:
402
+ """Calculate expectation value of observable using TKET."""
403
+ shots = shots or self.shots
404
+
405
+ try:
406
+ if isinstance(observable, str) and observable.upper() == 'Z':
407
+ # Measure in Z basis
408
+ measured_circuit = circuit.copy()
409
+ measured_circuit.add_c_register("c", 1)
410
+ measured_circuit.Measure(measured_circuit.qubits[0], measured_circuit.bits[0])
411
+
412
+ result = self.execute_circuit(measured_circuit, shots)
413
+ counts = result['counts']
414
+
415
+ # Calculate <Z> expectation
416
+ expectation = 0.0
417
+ total_counts = sum(counts.values())
418
+
419
+ for bitstring, count in counts.items():
420
+ prob = count / total_counts
421
+ if bitstring[0] == '0':
422
+ expectation += prob
423
+ else:
424
+ expectation -= prob
425
+
426
+ return expectation
427
+ else:
428
+ logger.warning("Only Z observable currently implemented")
429
+ return 0.0
430
+
431
+ except Exception as e:
432
+ logger.error(f"Expectation value calculation failed: {e}")
433
+ return 0.0
434
+
435
+ # ========================================================================
436
+ # Backend Information
437
+ # ========================================================================
438
+
439
+ def get_backend_info(self) -> Dict[str, Any]:
440
+ """Get information about the TKET backend."""
441
+ info = {
442
+ 'backend_name': 'tket',
443
+ 'device': self.device_name,
444
+ 'provider': 'Quantinuum/Cambridge Quantum Computing',
445
+ 'shots': self.shots,
446
+ 'capabilities': self.capabilities,
447
+ }
448
+
449
+ if self._backend:
450
+ info.update({
451
+ 'backend_class': self._backend.__class__.__name__,
452
+ 'supports_compilation': True,
453
+ 'supports_optimization': True,
454
+ })
455
+
456
+ if hasattr(self._backend, 'device'):
457
+ device_info = self._backend.device
458
+ info['device_info'] = str(device_info)
459
+
460
+ return info
461
+
462
+ def get_version_info(self) -> Dict[str, str]:
463
+ """Get version information for TKET dependencies."""
464
+ version_info = {'backend_version': '1.0.0'}
465
+
466
+ try:
467
+ import pytket
468
+ version_info['pytket'] = pytket.__version__
469
+ except:
470
+ pass
471
+
472
+ if QUANTINUUM_AVAILABLE:
473
+ try:
474
+ import pytket.extensions.quantinuum
475
+ version_info['pytket_quantinuum'] = getattr(pytket.extensions.quantinuum, '__version__', 'unknown')
476
+ except:
477
+ pass
478
+
479
+ return version_info
480
+
481
+ def is_available(self) -> bool:
482
+ """Check if the backend is available and properly configured."""
483
+ return TKET_AVAILABLE
484
+
485
+ def get_circuit_info(self) -> Dict[str, Any]:
486
+ """Get information about circuit execution capabilities."""
487
+ return {
488
+ 'max_qubits': self._get_max_qubits(),
489
+ 'native_gates': self._get_native_gates(),
490
+ 'supports_mid_circuit_measurement': True,
491
+ 'supports_reset': True,
492
+ 'supports_conditional': True,
493
+ 'supports_optimization': True,
494
+ 'supports_compilation': True,
495
+ }
496
+
497
+ def _get_n_qubits(self, circuit: Circuit) -> int:
498
+ """Get number of qubits in TKET circuit."""
499
+ return circuit.n_qubits
500
+
501
+ def get_statevector(self, circuit: Circuit) -> np.ndarray:
502
+ """Get statevector from TKET circuit."""
503
+ try:
504
+ if TKET_EXTENSIONS_AVAILABLE:
505
+ from pytket.extensions.qiskit import AerStateBackend
506
+ state_backend = AerStateBackend()
507
+ compiled_circuit = state_backend.get_compiled_circuit(circuit)
508
+ handle = state_backend.process_circuit(compiled_circuit)
509
+ result = state_backend.get_result(handle)
510
+
511
+ if hasattr(result, 'get_state'):
512
+ return result.get_state()
513
+
514
+ logger.warning("Statevector not available with current TKET setup")
515
+ return np.zeros(2**circuit.n_qubits, dtype=complex)
516
+
517
+ except Exception as e:
518
+ logger.error(f"Failed to get statevector: {e}")
519
+ return np.zeros(2**circuit.n_qubits, dtype=complex)