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,466 @@
1
+ """Cirq backend implementation for SuperQuantX.
2
+
3
+ This module provides integration with Google's Cirq for quantum computing
4
+ operations and access to Google Quantum AI hardware.
5
+ """
6
+
7
+ import logging
8
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
9
+
10
+ import numpy as np
11
+
12
+ from .base_backend import BaseBackend
13
+
14
+
15
+ if TYPE_CHECKING:
16
+ import cirq
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+ # Try to import Cirq
21
+ try:
22
+ import cirq
23
+ CIRQ_AVAILABLE = True
24
+ except ImportError:
25
+ CIRQ_AVAILABLE = False
26
+ cirq = None
27
+
28
+ class CirqBackend(BaseBackend):
29
+ """Cirq backend for quantum computing operations.
30
+
31
+ This backend provides access to Cirq simulators and Google Quantum AI
32
+ hardware for quantum algorithm execution.
33
+
34
+ Args:
35
+ device: Cirq device name ('simulator', 'sycamore', etc.)
36
+ processor_id: Google Quantum AI processor ID
37
+ shots: Number of measurement shots
38
+ **kwargs: Additional backend parameters
39
+
40
+ """
41
+
42
+ def __init__(self, device: str = 'simulator', processor_id: Optional[str] = None,
43
+ shots: int = 1024, **kwargs):
44
+ if not CIRQ_AVAILABLE:
45
+ raise ImportError("Cirq is required for CirqBackend. Install with: pip install cirq")
46
+
47
+ super().__init__(device=device, shots=shots, **kwargs)
48
+
49
+ self.processor_id = processor_id
50
+ self.simulator = None
51
+ self.quantum_engine = None
52
+ self.capabilities = {
53
+ 'supports_gradient': False,
54
+ 'supports_parameter_shift': True,
55
+ 'supports_finite_diff': True,
56
+ 'supports_hardware': processor_id is not None,
57
+ 'supports_noise_models': True,
58
+ }
59
+
60
+ def _initialize_backend(self) -> None:
61
+ """Initialize Cirq backend."""
62
+ try:
63
+ if self.device == 'simulator':
64
+ self.simulator = cirq.Simulator()
65
+ logger.info("Initialized Cirq Simulator")
66
+
67
+ elif self.processor_id:
68
+ try:
69
+ import cirq_google
70
+ # Initialize Google Quantum Engine
71
+ self.quantum_engine = cirq_google.get_engine()
72
+ logger.info(f"Initialized Google Quantum Engine with processor {self.processor_id}")
73
+ except ImportError:
74
+ logger.error("cirq-google required for hardware access")
75
+ self.simulator = cirq.Simulator()
76
+ logger.warning("Falling back to simulator")
77
+
78
+ else:
79
+ self.simulator = cirq.Simulator()
80
+ logger.info("Initialized default Cirq Simulator")
81
+
82
+ except Exception as e:
83
+ logger.error(f"Failed to initialize Cirq backend: {e}")
84
+ self.simulator = cirq.Simulator()
85
+ logger.warning("Falling back to default simulator")
86
+
87
+ def create_circuit(self, n_qubits: int) -> Any:
88
+ """Create a quantum circuit with n qubits."""
89
+ qubits = [cirq.LineQubit(i) for i in range(n_qubits)]
90
+ circuit = cirq.Circuit()
91
+ return circuit, qubits # Return both circuit and qubits for convenience
92
+
93
+ def add_gate(self, circuit_info: Tuple[Any, List], gate: str,
94
+ qubits: Union[int, List[int]], params: Optional[List[float]] = None) -> Tuple[Any, List]:
95
+ """Add a quantum gate to the circuit."""
96
+ circuit, qubit_list = circuit_info
97
+
98
+ if isinstance(qubits, int):
99
+ qubits = [qubits]
100
+
101
+ params = params or []
102
+
103
+ try:
104
+ if gate.upper() == 'H' or gate.upper() == 'HADAMARD':
105
+ circuit.append(cirq.H(qubit_list[qubits[0]]))
106
+ elif gate.upper() == 'X' or gate.upper() == 'PAULI_X':
107
+ circuit.append(cirq.X(qubit_list[qubits[0]]))
108
+ elif gate.upper() == 'Y' or gate.upper() == 'PAULI_Y':
109
+ circuit.append(cirq.Y(qubit_list[qubits[0]]))
110
+ elif gate.upper() == 'Z' or gate.upper() == 'PAULI_Z':
111
+ circuit.append(cirq.Z(qubit_list[qubits[0]]))
112
+ elif gate.upper() == 'RX':
113
+ circuit.append(cirq.rx(params[0] if params else 0)(qubit_list[qubits[0]]))
114
+ elif gate.upper() == 'RY':
115
+ circuit.append(cirq.ry(params[0] if params else 0)(qubit_list[qubits[0]]))
116
+ elif gate.upper() == 'RZ':
117
+ circuit.append(cirq.rz(params[0] if params else 0)(qubit_list[qubits[0]]))
118
+ elif gate.upper() == 'CNOT' or gate.upper() == 'CX':
119
+ circuit.append(cirq.CNOT(qubit_list[qubits[0]], qubit_list[qubits[1]]))
120
+ elif gate.upper() == 'CZ':
121
+ circuit.append(cirq.CZ(qubit_list[qubits[0]], qubit_list[qubits[1]]))
122
+ elif gate.upper() == 'SWAP':
123
+ circuit.append(cirq.SWAP(qubit_list[qubits[0]], qubit_list[qubits[1]]))
124
+ elif gate.upper() == 'CCX' or gate.upper() == 'TOFFOLI':
125
+ circuit.append(cirq.CCX(qubit_list[qubits[0]], qubit_list[qubits[1]], qubit_list[qubits[2]]))
126
+ else:
127
+ logger.warning(f"Unknown gate: {gate}")
128
+
129
+ except Exception as e:
130
+ logger.error(f"Failed to add gate {gate}: {e}")
131
+
132
+ return circuit, qubit_list
133
+
134
+ def add_measurement(self, circuit_info: Tuple[Any, List],
135
+ qubits: Optional[List[int]] = None) -> Tuple[Any, List]:
136
+ """Add measurement operations to the circuit."""
137
+ circuit, qubit_list = circuit_info
138
+
139
+ if qubits is None:
140
+ qubits = list(range(len(qubit_list)))
141
+
142
+ measurement_qubits = [qubit_list[i] for i in qubits]
143
+ circuit.append(cirq.measure(*measurement_qubits, key='result'))
144
+
145
+ return circuit, qubit_list
146
+
147
+ def execute_circuit(self, circuit_info: Union[Any, Tuple], shots: Optional[int] = None) -> Dict[str, Any]:
148
+ """Execute quantum circuit and return results."""
149
+ if isinstance(circuit_info, tuple):
150
+ circuit, qubit_list = circuit_info
151
+ else:
152
+ circuit = circuit_info
153
+ qubit_list = sorted(circuit.all_qubits())
154
+
155
+ shots = shots or self.shots
156
+
157
+ try:
158
+ if self.simulator:
159
+ # Run on simulator
160
+ result = self.simulator.run(circuit, repetitions=shots)
161
+
162
+ # Convert to counts format
163
+ if 'result' in result.measurements:
164
+ measurements = result.measurements['result']
165
+ counts = {}
166
+ for measurement in measurements:
167
+ bitstring = ''.join(str(bit) for bit in measurement)
168
+ counts[bitstring] = counts.get(bitstring, 0) + 1
169
+ else:
170
+ counts = {'0' * len(qubit_list): shots}
171
+
172
+ return {
173
+ 'counts': counts,
174
+ 'shots': shots,
175
+ 'backend': 'cirq_simulator',
176
+ }
177
+
178
+ elif self.quantum_engine and self.processor_id:
179
+ # Run on Google Quantum AI hardware
180
+ processor = self.quantum_engine.get_processor(self.processor_id)
181
+ job = processor.run(circuit, repetitions=shots)
182
+ result = job.results()[0]
183
+
184
+ # Convert to counts format
185
+ measurements = result.measurements['result']
186
+ counts = {}
187
+ for measurement in measurements:
188
+ bitstring = ''.join(str(bit) for bit in measurement)
189
+ counts[bitstring] = counts.get(bitstring, 0) + 1
190
+
191
+ return {
192
+ 'counts': counts,
193
+ 'shots': shots,
194
+ 'backend': f'google_quantum_{self.processor_id}',
195
+ 'job_id': job.id(),
196
+ }
197
+
198
+ else:
199
+ raise ValueError("No execution backend available")
200
+
201
+ except Exception as e:
202
+ logger.error(f"Circuit execution failed: {e}")
203
+ raise
204
+
205
+ def get_statevector(self, circuit_info: Union[Any, Tuple]) -> np.ndarray:
206
+ """Get the statevector from a quantum circuit."""
207
+ if isinstance(circuit_info, tuple):
208
+ circuit, qubit_list = circuit_info
209
+ else:
210
+ circuit = circuit_info
211
+ qubit_list = sorted(circuit.all_qubits())
212
+
213
+ try:
214
+ # Remove measurements for statevector simulation
215
+ circuit_copy = circuit.copy()
216
+ circuit_copy = cirq.Circuit([op for op in circuit_copy.all_operations()
217
+ if not isinstance(op.gate, cirq.MeasurementGate)])
218
+
219
+ # Simulate
220
+ result = self.simulator.simulate(circuit_copy)
221
+ statevector = result.final_state_vector
222
+
223
+ return np.array(statevector)
224
+
225
+ except Exception as e:
226
+ logger.error(f"Statevector computation failed: {e}")
227
+ n_qubits = len(qubit_list)
228
+ return np.array([1.0] + [0.0] * (2**n_qubits - 1))
229
+
230
+ def _get_n_qubits(self, circuit_info: Union[Any, Tuple]) -> int:
231
+ """Get number of qubits in circuit."""
232
+ if isinstance(circuit_info, tuple):
233
+ circuit, qubit_list = circuit_info
234
+ return len(qubit_list)
235
+ else:
236
+ return len(circuit_info.all_qubits())
237
+
238
+ # ========================================================================
239
+ # Enhanced Cirq-specific implementations
240
+ # ========================================================================
241
+
242
+ def create_feature_map(self, n_features: int, feature_map: str, reps: int = 1) -> Tuple[Any, List]:
243
+ """Create quantum feature map for data encoding."""
244
+ qubits = [cirq.LineQubit(i) for i in range(n_features)]
245
+ circuit = cirq.Circuit()
246
+
247
+ if feature_map == 'ZZFeatureMap':
248
+ circuit_info = self._create_zz_feature_map(n_features, reps)
249
+ elif feature_map == 'PauliFeatureMap':
250
+ circuit_info = self._create_pauli_feature_map(n_features, reps)
251
+ elif feature_map == 'AmplitudeMap':
252
+ circuit_info = self._create_amplitude_map(n_features)
253
+ else:
254
+ logger.warning(f"Unknown feature map '{feature_map}', using angle encoding")
255
+ circuit_info = self._create_angle_encoding_map(n_features)
256
+
257
+ return circuit_info
258
+
259
+ def _create_zz_feature_map(self, n_features: int, reps: int) -> Tuple[Any, List]:
260
+ """Create ZZ feature map circuit."""
261
+ qubits = [cirq.LineQubit(i) for i in range(n_features)]
262
+ circuit = cirq.Circuit()
263
+
264
+ for r in range(reps):
265
+ # Hadamard layer
266
+ circuit.append([cirq.H(q) for q in qubits])
267
+
268
+ # Parameterized rotations (placeholders)
269
+ for i, q in enumerate(qubits):
270
+ circuit.append(cirq.rz(cirq.Symbol(f'x_{i}'))(q))
271
+
272
+ # ZZ interactions
273
+ for i in range(n_features - 1):
274
+ circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
275
+ circuit.append(cirq.rz(cirq.Symbol(f'x_{i}_x_{i+1}'))(qubits[i + 1]))
276
+ circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
277
+
278
+ return circuit, qubits
279
+
280
+ def _create_pauli_feature_map(self, n_features: int, reps: int) -> Tuple[Any, List]:
281
+ """Create Pauli feature map circuit."""
282
+ qubits = [cirq.LineQubit(i) for i in range(n_features)]
283
+ circuit = cirq.Circuit()
284
+
285
+ for r in range(reps):
286
+ # Pauli rotations
287
+ for i, q in enumerate(qubits):
288
+ circuit.append(cirq.rx(cirq.Symbol(f'x_{i}_rx_{r}'))(q))
289
+ circuit.append(cirq.ry(cirq.Symbol(f'x_{i}_ry_{r}'))(q))
290
+ circuit.append(cirq.rz(cirq.Symbol(f'x_{i}_rz_{r}'))(q))
291
+
292
+ # Entangling layer
293
+ for i in range(n_features - 1):
294
+ circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
295
+
296
+ return circuit, qubits
297
+
298
+ def _create_amplitude_map(self, n_features: int) -> Tuple[Any, List]:
299
+ """Create amplitude encoding map."""
300
+ n_qubits = int(np.ceil(np.log2(n_features)))
301
+ qubits = [cirq.LineQubit(i) for i in range(n_qubits)]
302
+ circuit = cirq.Circuit()
303
+
304
+ # Amplitude encoding would require state preparation
305
+ # This is a simplified placeholder
306
+ logger.warning("Amplitude encoding not fully implemented")
307
+
308
+ return circuit, qubits
309
+
310
+ def _create_angle_encoding_map(self, n_features: int) -> Tuple[Any, List]:
311
+ """Create angle encoding map."""
312
+ qubits = [cirq.LineQubit(i) for i in range(n_features)]
313
+ circuit = cirq.Circuit()
314
+
315
+ for i, q in enumerate(qubits):
316
+ circuit.append(cirq.ry(cirq.Symbol(f'x_{i}'))(q))
317
+
318
+ return circuit, qubits
319
+
320
+ def create_ansatz(self, ansatz_type: str, n_qubits: int, params: np.ndarray,
321
+ include_custom_gates: bool = False) -> Tuple[Any, List]:
322
+ """Create parameterized ansatz circuit."""
323
+ if ansatz_type == 'RealAmplitudes':
324
+ return self._create_real_amplitudes_ansatz(n_qubits, params)
325
+ elif ansatz_type == 'EfficientSU2':
326
+ return self._create_efficient_su2_ansatz(n_qubits, params)
327
+ elif ansatz_type == 'TwoLocal':
328
+ return self._create_two_local_ansatz(n_qubits, params)
329
+ elif ansatz_type == 'UCCSD':
330
+ return self._create_uccsd_ansatz(n_qubits, params)
331
+ else:
332
+ logger.warning(f"Unknown ansatz '{ansatz_type}', using RealAmplitudes")
333
+ return self._create_real_amplitudes_ansatz(n_qubits, params)
334
+
335
+ def _create_real_amplitudes_ansatz(self, n_qubits: int, params: np.ndarray) -> Tuple[Any, List]:
336
+ """Create RealAmplitudes ansatz."""
337
+ qubits = [cirq.LineQubit(i) for i in range(n_qubits)]
338
+ circuit = cirq.Circuit()
339
+
340
+ n_layers = len(params) // (n_qubits * 2)
341
+ param_idx = 0
342
+
343
+ for layer in range(n_layers):
344
+ # RY rotations
345
+ for i, q in enumerate(qubits):
346
+ if param_idx < len(params):
347
+ circuit.append(cirq.ry(params[param_idx])(q))
348
+ param_idx += 1
349
+
350
+ # Entangling layer
351
+ for i in range(n_qubits - 1):
352
+ circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
353
+
354
+ # RZ rotations
355
+ for i, q in enumerate(qubits):
356
+ if param_idx < len(params):
357
+ circuit.append(cirq.rz(params[param_idx])(q))
358
+ param_idx += 1
359
+
360
+ return circuit, qubits
361
+
362
+ def _create_efficient_su2_ansatz(self, n_qubits: int, params: np.ndarray) -> Tuple[Any, List]:
363
+ """Create EfficientSU2 ansatz."""
364
+ qubits = [cirq.LineQubit(i) for i in range(n_qubits)]
365
+ circuit = cirq.Circuit()
366
+
367
+ n_layers = len(params) // (n_qubits * 3)
368
+ param_idx = 0
369
+
370
+ for layer in range(n_layers):
371
+ # SU(2) rotations
372
+ for i, q in enumerate(qubits):
373
+ if param_idx + 2 < len(params):
374
+ circuit.append(cirq.ry(params[param_idx])(q))
375
+ circuit.append(cirq.rz(params[param_idx + 1])(q))
376
+ circuit.append(cirq.ry(params[param_idx + 2])(q))
377
+ param_idx += 3
378
+
379
+ # Entangling layer
380
+ for i in range(n_qubits - 1):
381
+ circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
382
+
383
+ return circuit, qubits
384
+
385
+ def _create_two_local_ansatz(self, n_qubits: int, params: np.ndarray) -> Tuple[Any, List]:
386
+ """Create TwoLocal ansatz."""
387
+ qubits = [cirq.LineQubit(i) for i in range(n_qubits)]
388
+ circuit = cirq.Circuit()
389
+
390
+ n_layers = len(params) // (n_qubits * 2)
391
+ param_idx = 0
392
+
393
+ for layer in range(n_layers):
394
+ # Local rotations
395
+ for i, q in enumerate(qubits):
396
+ if param_idx + 1 < len(params):
397
+ circuit.append(cirq.ry(params[param_idx])(q))
398
+ circuit.append(cirq.rz(params[param_idx + 1])(q))
399
+ param_idx += 2
400
+
401
+ # Two-qubit gates
402
+ for i in range(0, n_qubits - 1, 2):
403
+ circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
404
+ for i in range(1, n_qubits - 1, 2):
405
+ circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
406
+
407
+ return circuit, qubits
408
+
409
+ def _create_uccsd_ansatz(self, n_qubits: int, params: np.ndarray) -> Tuple[Any, List]:
410
+ """Create UCCSD ansatz (simplified)."""
411
+ qubits = [cirq.LineQubit(i) for i in range(n_qubits)]
412
+ circuit = cirq.Circuit()
413
+
414
+ param_idx = 0
415
+
416
+ # Single excitations
417
+ for i in range(0, n_qubits, 2):
418
+ for j in range(1, n_qubits, 2):
419
+ if param_idx < len(params) and i != j:
420
+ circuit.append(cirq.CNOT(qubits[i], qubits[j]))
421
+ circuit.append(cirq.ry(params[param_idx])(qubits[j]))
422
+ circuit.append(cirq.CNOT(qubits[i], qubits[j]))
423
+ param_idx += 1
424
+
425
+ # Double excitations (simplified)
426
+ for i in range(0, n_qubits - 3, 2):
427
+ if param_idx < len(params):
428
+ circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
429
+ circuit.append(cirq.CNOT(qubits[i + 2], qubits[i + 3]))
430
+ circuit.append(cirq.ry(params[param_idx])(qubits[i + 1]))
431
+ circuit.append(cirq.CNOT(qubits[i], qubits[i + 1]))
432
+ circuit.append(cirq.CNOT(qubits[i + 2], qubits[i + 3]))
433
+ param_idx += 1
434
+
435
+ return circuit, qubits
436
+
437
+ def compute_expectation(self, circuit_info: Union[Any, Tuple], hamiltonian: Any,
438
+ shots: Optional[int] = None) -> float:
439
+ """Compute expectation value of Hamiltonian."""
440
+ try:
441
+ if isinstance(hamiltonian, np.ndarray):
442
+ # Compute expectation using statevector
443
+ statevector = self.get_statevector(circuit_info)
444
+ expectation = np.real(np.conj(statevector) @ hamiltonian @ statevector)
445
+ return float(expectation)
446
+ else:
447
+ logger.warning("Hamiltonian expectation not fully implemented")
448
+ return 0.0
449
+
450
+ except Exception as e:
451
+ logger.error(f"Expectation computation failed: {e}")
452
+ return 0.0
453
+
454
+ def get_version_info(self) -> Dict[str, Any]:
455
+ """Get Cirq version information."""
456
+ info = super().get_version_info()
457
+
458
+ try:
459
+ info.update({
460
+ 'cirq_version': cirq.__version__,
461
+ 'processor_id': self.processor_id,
462
+ })
463
+ except Exception as e:
464
+ info['version_error'] = str(e)
465
+
466
+ return info