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,451 @@
1
+ """Qiskit backend implementation for SuperQuantX.
2
+
3
+ This module provides integration with IBM's Qiskit for quantum computing
4
+ operations and access to IBM Quantum hardware.
5
+ """
6
+
7
+ import logging
8
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
9
+
10
+ import numpy as np
11
+
12
+ from .base_backend import BaseBackend
13
+
14
+
15
+ if TYPE_CHECKING:
16
+ from qiskit import QuantumCircuit
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+ # Try to import Qiskit
21
+ try:
22
+ from qiskit import (
23
+ Aer,
24
+ ClassicalRegister,
25
+ QuantumCircuit,
26
+ QuantumRegister,
27
+ execute,
28
+ transpile,
29
+ )
30
+ from qiskit.algorithms.optimizers import COBYLA, L_BFGS_B
31
+ from qiskit.circuit.library import EfficientSU2, RealAmplitudes, ZZFeatureMap
32
+ from qiskit.providers.aer import AerSimulator
33
+ from qiskit.quantum_info import Statevector
34
+ QISKIT_AVAILABLE = True
35
+
36
+ # Try to import IBM Quantum provider
37
+ try:
38
+ from qiskit import IBMQ
39
+ from qiskit.providers.ibmq import IBMQBackend
40
+ IBMQ_AVAILABLE = True
41
+ except ImportError:
42
+ IBMQ_AVAILABLE = False
43
+ IBMQ = None
44
+ IBMQBackend = None
45
+
46
+ except ImportError:
47
+ QISKIT_AVAILABLE = False
48
+ QuantumCircuit = None
49
+ Aer = None
50
+ AerSimulator = None
51
+ Statevector = None
52
+
53
+ class QiskitBackend(BaseBackend):
54
+ """Qiskit backend for quantum computing operations.
55
+
56
+ This backend provides access to Qiskit simulators and IBM Quantum
57
+ hardware for quantum algorithm execution.
58
+
59
+ Args:
60
+ device: Qiskit backend name ('aer_simulator', 'ibmq_qasm_simulator', etc.)
61
+ provider: IBM Quantum provider (if using IBMQ)
62
+ shots: Number of measurement shots
63
+ **kwargs: Additional backend parameters
64
+
65
+ """
66
+
67
+ def __init__(self, device: str = 'aer_simulator', provider: Optional[str] = None,
68
+ shots: int = 1024, **kwargs):
69
+ if not QISKIT_AVAILABLE:
70
+ raise ImportError("Qiskit is required for QiskitBackend. Install with: pip install qiskit")
71
+
72
+ super().__init__(device=device, shots=shots, **kwargs)
73
+
74
+ self.provider = provider
75
+ self.backend = None
76
+ self.capabilities = {
77
+ 'supports_gradient': False,
78
+ 'supports_parameter_shift': True,
79
+ 'supports_finite_diff': True,
80
+ 'supports_hardware': IBMQ_AVAILABLE,
81
+ 'supports_noise_models': True,
82
+ }
83
+
84
+ def _initialize_backend(self) -> None:
85
+ """Initialize Qiskit backend."""
86
+ try:
87
+ if self.device == 'aer_simulator':
88
+ self.backend = AerSimulator()
89
+ logger.info("Initialized Qiskit AerSimulator")
90
+
91
+ elif self.device.startswith('ibmq_') or self.provider:
92
+ if not IBMQ_AVAILABLE:
93
+ raise ImportError("IBM Quantum provider not available")
94
+
95
+ # Load IBMQ account
96
+ if not IBMQ.active_account():
97
+ try:
98
+ IBMQ.load_account()
99
+ except Exception as e:
100
+ logger.error(f"Failed to load IBMQ account: {e}")
101
+ raise
102
+
103
+ # Get provider
104
+ if self.provider:
105
+ provider = IBMQ.get_provider(hub=self.provider.get('hub', 'ibm-q'),
106
+ group=self.provider.get('group', 'open'),
107
+ project=self.provider.get('project', 'main'))
108
+ else:
109
+ provider = IBMQ.get_provider()
110
+
111
+ # Get backend
112
+ self.backend = provider.get_backend(self.device)
113
+ logger.info(f"Initialized IBM Quantum backend: {self.device}")
114
+
115
+ else:
116
+ # Try to get backend from Aer
117
+ self.backend = Aer.get_backend(self.device)
118
+ logger.info(f"Initialized Aer backend: {self.device}")
119
+
120
+ except Exception as e:
121
+ logger.error(f"Failed to initialize Qiskit backend: {e}")
122
+ # Fallback to simulator
123
+ self.backend = AerSimulator()
124
+ logger.warning("Falling back to AerSimulator")
125
+
126
+ def create_circuit(self, n_qubits: int) -> Any:
127
+ """Create a quantum circuit with n qubits."""
128
+ qreg = QuantumRegister(n_qubits, 'q')
129
+ creg = ClassicalRegister(n_qubits, 'c')
130
+ circuit = QuantumCircuit(qreg, creg)
131
+ return circuit
132
+
133
+ def add_gate(self, circuit: Any, gate: str, qubits: Union[int, List[int]],
134
+ params: Optional[List[float]] = None) -> Any:
135
+ """Add a quantum gate to the circuit."""
136
+ if isinstance(qubits, int):
137
+ qubits = [qubits]
138
+
139
+ params = params or []
140
+
141
+ try:
142
+ if gate.upper() == 'H' or gate.upper() == 'HADAMARD':
143
+ circuit.h(qubits[0])
144
+ elif gate.upper() == 'X' or gate.upper() == 'PAULI_X':
145
+ circuit.x(qubits[0])
146
+ elif gate.upper() == 'Y' or gate.upper() == 'PAULI_Y':
147
+ circuit.y(qubits[0])
148
+ elif gate.upper() == 'Z' or gate.upper() == 'PAULI_Z':
149
+ circuit.z(qubits[0])
150
+ elif gate.upper() == 'RX':
151
+ circuit.rx(params[0] if params else 0, qubits[0])
152
+ elif gate.upper() == 'RY':
153
+ circuit.ry(params[0] if params else 0, qubits[0])
154
+ elif gate.upper() == 'RZ':
155
+ circuit.rz(params[0] if params else 0, qubits[0])
156
+ elif gate.upper() == 'CNOT' or gate.upper() == 'CX':
157
+ circuit.cx(qubits[0], qubits[1])
158
+ elif gate.upper() == 'CZ':
159
+ circuit.cz(qubits[0], qubits[1])
160
+ elif gate.upper() == 'SWAP':
161
+ circuit.swap(qubits[0], qubits[1])
162
+ elif gate.upper() == 'CCX' or gate.upper() == 'TOFFOLI':
163
+ circuit.ccx(qubits[0], qubits[1], qubits[2])
164
+ else:
165
+ logger.warning(f"Unknown gate: {gate}")
166
+
167
+ except Exception as e:
168
+ logger.error(f"Failed to add gate {gate}: {e}")
169
+
170
+ return circuit
171
+
172
+ def add_measurement(self, circuit: Any, qubits: Optional[List[int]] = None) -> Any:
173
+ """Add measurement operations to the circuit."""
174
+ if qubits is None:
175
+ qubits = list(range(circuit.num_qubits))
176
+
177
+ for i, qubit in enumerate(qubits):
178
+ if i < circuit.num_clbits:
179
+ circuit.measure(qubit, i)
180
+
181
+ return circuit
182
+
183
+ def execute_circuit(self, circuit: Any, shots: Optional[int] = None) -> Dict[str, Any]:
184
+ """Execute quantum circuit and return results."""
185
+ shots = shots or self.shots
186
+
187
+ try:
188
+ # Add measurements if not present
189
+ if circuit.num_clbits == 0 or not any(isinstance(instr.operation,
190
+ type(circuit.measure(0, 0).operation))
191
+ for instr in circuit):
192
+ circuit.add_register(ClassicalRegister(circuit.num_qubits, 'c'))
193
+ circuit.measure_all()
194
+
195
+ # Transpile circuit
196
+ transpiled = transpile(circuit, self.backend)
197
+
198
+ # Execute
199
+ job = execute(transpiled, self.backend, shots=shots)
200
+ result = job.result()
201
+
202
+ # Get counts
203
+ counts = result.get_counts()
204
+
205
+ return {
206
+ 'counts': counts,
207
+ 'shots': shots,
208
+ 'backend': self.device,
209
+ 'job_id': job.job_id(),
210
+ }
211
+
212
+ except Exception as e:
213
+ logger.error(f"Circuit execution failed: {e}")
214
+ raise
215
+
216
+ def get_statevector(self, circuit: Any) -> np.ndarray:
217
+ """Get the statevector from a quantum circuit."""
218
+ try:
219
+ # Use statevector simulator
220
+ backend = AerSimulator(method='statevector')
221
+
222
+ # Create circuit copy without measurements
223
+ circuit_copy = circuit.copy()
224
+ circuit_copy.remove_final_measurements()
225
+
226
+ # Execute
227
+ job = execute(circuit_copy, backend, shots=1)
228
+ result = job.result()
229
+
230
+ # Get statevector
231
+ statevector = result.get_statevector()
232
+ return np.array(statevector.data)
233
+
234
+ except Exception as e:
235
+ logger.error(f"Statevector computation failed: {e}")
236
+ return np.array([1.0] + [0.0] * (2**circuit.num_qubits - 1))
237
+
238
+ def _get_n_qubits(self, circuit: Any) -> int:
239
+ """Get number of qubits in circuit."""
240
+ return circuit.num_qubits
241
+
242
+ # ========================================================================
243
+ # Enhanced Qiskit-specific implementations
244
+ # ========================================================================
245
+
246
+ def create_feature_map(self, n_features: int, feature_map: str, reps: int = 1) -> Any:
247
+ """Create quantum feature map for data encoding."""
248
+ if feature_map == 'ZZFeatureMap':
249
+ return ZZFeatureMap(n_features, reps=reps)
250
+ elif feature_map == 'PauliFeatureMap':
251
+ return self._create_pauli_feature_map(n_features, reps)
252
+ elif feature_map == 'AmplitudeMap':
253
+ return self._create_amplitude_map(n_features)
254
+ else:
255
+ logger.warning(f"Unknown feature map '{feature_map}', using angle encoding")
256
+ return self._create_angle_encoding_map(n_features)
257
+
258
+ def _create_pauli_feature_map(self, n_features: int, reps: int) -> Any:
259
+ """Create Pauli feature map circuit."""
260
+ circuit = QuantumCircuit(n_features)
261
+
262
+ for r in range(reps):
263
+ # Pauli rotations
264
+ for i in range(n_features):
265
+ circuit.rx(circuit.parameters[0], i) # Placeholder parameter
266
+ circuit.ry(circuit.parameters[0], i)
267
+ circuit.rz(circuit.parameters[0], i)
268
+
269
+ # Entangling layer
270
+ for i in range(n_features - 1):
271
+ circuit.cx(i, i + 1)
272
+
273
+ return circuit
274
+
275
+ def _create_amplitude_map(self, n_features: int) -> Any:
276
+ """Create amplitude encoding map."""
277
+ n_qubits = int(np.ceil(np.log2(n_features)))
278
+ circuit = QuantumCircuit(n_qubits)
279
+
280
+ # Amplitude encoding would require state initialization
281
+ # This is a simplified placeholder
282
+ logger.warning("Amplitude encoding not fully implemented")
283
+
284
+ return circuit
285
+
286
+ def _create_angle_encoding_map(self, n_features: int) -> Any:
287
+ """Create angle encoding map."""
288
+ circuit = QuantumCircuit(n_features)
289
+
290
+ for i in range(n_features):
291
+ circuit.ry(circuit.parameters[0], i) # Placeholder parameter
292
+
293
+ return circuit
294
+
295
+ def compute_kernel_matrix(self, X1: np.ndarray, X2: np.ndarray,
296
+ feature_map: QuantumCircuit, shots: Optional[int] = None) -> np.ndarray:
297
+ """Compute quantum kernel matrix using Qiskit."""
298
+ n1, n2 = len(X1), len(X2)
299
+ kernel_matrix = np.zeros((n1, n2))
300
+
301
+ for i in range(n1):
302
+ for j in range(n2):
303
+ try:
304
+ # Create kernel evaluation circuit
305
+ circuit = QuantumCircuit(feature_map.num_qubits, feature_map.num_qubits)
306
+
307
+ # Encode first data point
308
+ circuit.compose(feature_map.bind_parameters(X1[i]), inplace=True)
309
+
310
+ # Encode second data point with inverse
311
+ inverse_map = feature_map.bind_parameters(-X2[j]).inverse()
312
+ circuit.compose(inverse_map, inplace=True)
313
+
314
+ # Measure
315
+ circuit.measure_all()
316
+
317
+ # Execute
318
+ result = self.execute_circuit(circuit, shots)
319
+ counts = result['counts']
320
+
321
+ # Kernel value is probability of measuring |00...0⟩
322
+ zero_state = '0' * feature_map.num_qubits
323
+ kernel_matrix[i, j] = counts.get(zero_state, 0) / sum(counts.values())
324
+
325
+ except Exception as e:
326
+ logger.warning(f"Kernel computation failed for ({i},{j}): {e}")
327
+ kernel_matrix[i, j] = 0.0
328
+
329
+ return kernel_matrix
330
+
331
+ def create_ansatz(self, ansatz_type: str, n_qubits: int, params: np.ndarray,
332
+ include_custom_gates: bool = False) -> Any:
333
+ """Create parameterized ansatz circuit."""
334
+ if ansatz_type == 'RealAmplitudes':
335
+ return RealAmplitudes(n_qubits, reps=len(params) // (n_qubits * 2))
336
+ elif ansatz_type == 'EfficientSU2':
337
+ return EfficientSU2(n_qubits, reps=len(params) // (n_qubits * 3))
338
+ elif ansatz_type == 'TwoLocal':
339
+ return self._create_two_local_ansatz(n_qubits, params)
340
+ elif ansatz_type == 'UCCSD':
341
+ return self._create_uccsd_ansatz(n_qubits, params)
342
+ else:
343
+ logger.warning(f"Unknown ansatz '{ansatz_type}', using RealAmplitudes")
344
+ return RealAmplitudes(n_qubits, reps=len(params) // (n_qubits * 2))
345
+
346
+ def _create_two_local_ansatz(self, n_qubits: int, params: np.ndarray) -> Any:
347
+ """Create TwoLocal ansatz."""
348
+ from qiskit.circuit.library import TwoLocal
349
+ return TwoLocal(n_qubits, 'ry', 'cx', 'linear', reps=len(params) // (n_qubits * 2))
350
+
351
+ def _create_uccsd_ansatz(self, n_qubits: int, params: np.ndarray) -> Any:
352
+ """Create UCCSD ansatz (simplified)."""
353
+ circuit = QuantumCircuit(n_qubits)
354
+
355
+ # Simplified UCCSD implementation
356
+ param_idx = 0
357
+
358
+ # Single excitations
359
+ for i in range(0, n_qubits, 2):
360
+ for j in range(1, n_qubits, 2):
361
+ if param_idx < len(params) and i != j:
362
+ circuit.cx(i, j)
363
+ circuit.ry(params[param_idx], j)
364
+ circuit.cx(i, j)
365
+ param_idx += 1
366
+
367
+ # Double excitations (simplified)
368
+ for i in range(0, n_qubits - 3, 2):
369
+ if param_idx < len(params):
370
+ circuit.cx(i, i + 1)
371
+ circuit.cx(i + 2, i + 3)
372
+ circuit.ry(params[param_idx], i + 1)
373
+ circuit.cx(i, i + 1)
374
+ circuit.cx(i + 2, i + 3)
375
+ param_idx += 1
376
+
377
+ return circuit
378
+
379
+ def compute_expectation(self, circuit: Any, hamiltonian: Any,
380
+ shots: Optional[int] = None) -> float:
381
+ """Compute expectation value of Hamiltonian."""
382
+ try:
383
+ # For Qiskit, we need to decompose Hamiltonian into Pauli terms
384
+ if isinstance(hamiltonian, np.ndarray):
385
+ # Compute expectation using statevector
386
+ statevector = self.get_statevector(circuit)
387
+ expectation = np.real(np.conj(statevector) @ hamiltonian @ statevector)
388
+ return float(expectation)
389
+ else:
390
+ logger.warning("Hamiltonian expectation not fully implemented")
391
+ return 0.0
392
+
393
+ except Exception as e:
394
+ logger.error(f"Expectation computation failed: {e}")
395
+ return 0.0
396
+
397
+ def create_qaoa_circuit(self, n_qubits: int, gammas: np.ndarray, betas: np.ndarray,
398
+ problem_hamiltonian: Any, mixer_hamiltonian: Any,
399
+ initial_state: Any, problem_instance: Any) -> Any:
400
+ """Create QAOA circuit with given parameters."""
401
+ circuit = QuantumCircuit(n_qubits)
402
+
403
+ # Initial state (uniform superposition)
404
+ for i in range(n_qubits):
405
+ circuit.h(i)
406
+
407
+ # QAOA layers
408
+ for gamma, beta in zip(gammas, betas):
409
+ # Problem Hamiltonian layer
410
+ self._apply_problem_hamiltonian(circuit, gamma, problem_instance)
411
+
412
+ # Mixer Hamiltonian layer
413
+ self._apply_mixer_hamiltonian(circuit, beta)
414
+
415
+ return circuit
416
+
417
+ def _apply_problem_hamiltonian(self, circuit: Any, gamma: float, problem_instance: Any) -> None:
418
+ """Apply problem Hamiltonian to circuit."""
419
+ # Simplified implementation for Max-Cut type problems
420
+ n_qubits = circuit.num_qubits
421
+
422
+ if hasattr(problem_instance, 'shape') and len(problem_instance.shape) == 2:
423
+ # Assume adjacency matrix
424
+ for i in range(n_qubits):
425
+ for j in range(i + 1, n_qubits):
426
+ if problem_instance[i, j] != 0:
427
+ circuit.cx(i, j)
428
+ circuit.rz(gamma * problem_instance[i, j], j)
429
+ circuit.cx(i, j)
430
+
431
+ def _apply_mixer_hamiltonian(self, circuit: Any, beta: float) -> None:
432
+ """Apply mixer Hamiltonian to circuit."""
433
+ # Standard X-mixer
434
+ for i in range(circuit.num_qubits):
435
+ circuit.rx(2 * beta, i)
436
+
437
+ def get_version_info(self) -> Dict[str, Any]:
438
+ """Get Qiskit version information."""
439
+ info = super().get_version_info()
440
+
441
+ try:
442
+ import qiskit
443
+ info.update({
444
+ 'qiskit_version': qiskit.__version__,
445
+ 'backend_name': self.backend.name() if self.backend else 'Unknown',
446
+ 'backend_version': getattr(self.backend, 'version', 'Unknown'),
447
+ })
448
+ except Exception as e:
449
+ info['version_error'] = str(e)
450
+
451
+ return info