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,491 @@
1
+ """D-Wave Ocean backend implementation for SuperQuantX.
2
+
3
+ This module provides integration with D-Wave Ocean SDK for quantum annealing
4
+ and optimization problems using D-Wave quantum annealing processors.
5
+
6
+ Note: This backend focuses on QUBO/Ising model problems rather than
7
+ gate-model quantum circuits.
8
+ """
9
+
10
+ import logging
11
+ from typing import Any, Dict, List, Optional, Tuple, Union
12
+
13
+ import numpy as np
14
+
15
+ from .base_backend import BaseBackend
16
+
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+ # Try to import D-Wave Ocean
21
+ try:
22
+ import dimod
23
+ import networkx as nx
24
+ from dwave.embedding import embed_ising, unembed_sampleset
25
+ from dwave.samplers import SimulatedAnnealingSampler
26
+ from dwave.system import DWaveSampler, EmbeddingComposite, LeapHybridSampler
27
+ OCEAN_AVAILABLE = True
28
+ except ImportError:
29
+ OCEAN_AVAILABLE = False
30
+ dimod = None
31
+ DWaveSampler = None
32
+ LeapHybridSampler = None
33
+ SimulatedAnnealingSampler = None
34
+ nx = None
35
+
36
+ class OceanBackend(BaseBackend):
37
+ """D-Wave Ocean backend for quantum annealing operations.
38
+
39
+ This backend provides access to D-Wave's quantum annealing systems
40
+ for solving optimization problems formulated as QUBO or Ising models.
41
+
42
+ Note: Unlike gate-model quantum computers, D-Wave systems solve optimization
43
+ problems rather than running quantum circuits.
44
+
45
+ Args:
46
+ device: Sampler type ('DWave', 'hybrid', 'simulator', 'advantage')
47
+ solver: Specific solver name (optional)
48
+ token: D-Wave API token (required for hardware)
49
+ endpoint: D-Wave API endpoint
50
+ shots: Number of samples (reads)
51
+ **kwargs: Additional sampler configuration
52
+
53
+ Example:
54
+ >>> # Simulated annealing (no hardware required)
55
+ >>> backend = OceanBackend(device='simulator')
56
+ >>>
57
+ >>> # D-Wave hardware (requires API token)
58
+ >>> backend = OceanBackend(
59
+ ... device='advantage',
60
+ ... token='your-dwave-token'
61
+ ... )
62
+
63
+ """
64
+
65
+ def __init__(
66
+ self,
67
+ device: str = 'simulator',
68
+ solver: Optional[str] = None,
69
+ token: Optional[str] = None,
70
+ endpoint: Optional[str] = None,
71
+ shots: int = 1000, # Called "num_reads" in D-Wave
72
+ **kwargs
73
+ ) -> None:
74
+ if not OCEAN_AVAILABLE:
75
+ raise ImportError(
76
+ "D-Wave Ocean not available. Install with: pip install dwave-ocean-sdk"
77
+ )
78
+
79
+ self.device_name = device
80
+ self.solver_name = solver
81
+ self.token = token
82
+ self.endpoint = endpoint
83
+ self.num_reads = shots
84
+ self._sampler = None
85
+ self._is_quantum_annealing = True # This backend is for annealing, not gates
86
+
87
+ super().__init__(device=device, shots=shots, **kwargs)
88
+
89
+ def _initialize_backend(self) -> None:
90
+ """Initialize D-Wave Ocean backend and sampler."""
91
+ try:
92
+ if self.device_name == 'simulator':
93
+ # Simulated annealing sampler (classical simulation)
94
+ self._sampler = SimulatedAnnealingSampler()
95
+ logger.info("Initialized D-Wave simulated annealing sampler")
96
+
97
+ elif self.device_name in ['dwave', 'advantage', 'advantage2']:
98
+ # D-Wave quantum annealer
99
+ if not self.token:
100
+ logger.warning("No D-Wave token provided, attempting to use environment/config")
101
+
102
+ # Create base sampler
103
+ base_sampler = DWaveSampler(
104
+ solver=self.solver_name,
105
+ token=self.token,
106
+ endpoint=self.endpoint
107
+ )
108
+
109
+ # Wrap with embedding for automatic minor-embedding
110
+ self._sampler = EmbeddingComposite(base_sampler)
111
+ logger.info(f"Initialized D-Wave hardware sampler: {base_sampler.solver.name}")
112
+
113
+ elif self.device_name == 'hybrid':
114
+ # D-Wave Leap Hybrid solver
115
+ self._sampler = LeapHybridSampler(
116
+ token=self.token,
117
+ endpoint=self.endpoint
118
+ )
119
+ logger.info("Initialized D-Wave Leap Hybrid sampler")
120
+
121
+ else:
122
+ raise ValueError(f"Unknown D-Wave device: {self.device_name}")
123
+
124
+ self.capabilities = {
125
+ 'supports_measurements': False, # Not applicable for annealing
126
+ 'supports_parameterized_circuits': False, # Not applicable
127
+ 'supports_classical_control': False,
128
+ 'supports_optimization': True, # Main capability
129
+ 'supports_qubo': True,
130
+ 'supports_ising': True,
131
+ 'max_variables': self._get_max_variables(),
132
+ 'annealing_backend': True,
133
+ }
134
+
135
+ except Exception as e:
136
+ logger.error(f"Failed to initialize D-Wave Ocean backend: {e}")
137
+ raise
138
+
139
+ def _get_max_variables(self) -> int:
140
+ """Get maximum number of variables for the sampler."""
141
+ if hasattr(self._sampler, 'properties'):
142
+ try:
143
+ return len(self._sampler.properties['qubits'])
144
+ except:
145
+ pass
146
+
147
+ # Default estimates
148
+ if self.device_name == 'simulator':
149
+ return 10000 # Simulated annealer can handle large problems
150
+ elif self.device_name in ['advantage', 'advantage2']:
151
+ return 5000 # Advantage systems have ~5000 qubits
152
+ else:
153
+ return 2000 # Conservative estimate
154
+
155
+ # ========================================================================
156
+ # Optimization Problem Interface (replaces circuit operations)
157
+ # ========================================================================
158
+
159
+ def solve_qubo(self, Q: Dict[Tuple[int, int], float], **kwargs) -> Dict[str, Any]:
160
+ """Solve a Quadratic Unconstrained Binary Optimization (QUBO) problem.
161
+
162
+ Args:
163
+ Q: QUBO dictionary where keys are (i, j) variable pairs and values are coefficients
164
+ **kwargs: Additional solving parameters
165
+
166
+ Returns:
167
+ Solution results with energies and samples
168
+
169
+ """
170
+ try:
171
+ num_reads = kwargs.get('num_reads', self.num_reads)
172
+
173
+ # Create BQM from QUBO
174
+ bqm = dimod.BinaryQuadraticModel.from_qubo(Q)
175
+
176
+ # Sample from the BQM
177
+ sampleset = self._sampler.sample(bqm, num_reads=num_reads, **kwargs)
178
+
179
+ # Convert results to standard format
180
+ results = {
181
+ 'samples': [],
182
+ 'energies': [],
183
+ 'num_occurrences': [],
184
+ 'success': True,
185
+ 'num_reads': len(sampleset),
186
+ 'timing': getattr(sampleset, 'info', {}).get('timing', {}),
187
+ 'problem_type': 'QUBO'
188
+ }
189
+
190
+ for sample, energy, num_occur in sampleset.data(['sample', 'energy', 'num_occurrences']):
191
+ results['samples'].append(dict(sample))
192
+ results['energies'].append(energy)
193
+ results['num_occurrences'].append(num_occur)
194
+
195
+ return results
196
+
197
+ except Exception as e:
198
+ logger.error(f"QUBO solving failed: {e}")
199
+ return {
200
+ 'samples': [],
201
+ 'energies': [],
202
+ 'success': False,
203
+ 'error': str(e),
204
+ 'problem_type': 'QUBO'
205
+ }
206
+
207
+ def solve_ising(self, h: Dict[int, float], J: Dict[Tuple[int, int], float], **kwargs) -> Dict[str, Any]:
208
+ """Solve an Ising model problem.
209
+
210
+ Args:
211
+ h: Linear coefficients (bias terms) for each variable
212
+ J: Quadratic coefficients (coupling terms) between variables
213
+ **kwargs: Additional solving parameters
214
+
215
+ Returns:
216
+ Solution results with energies and samples
217
+
218
+ """
219
+ try:
220
+ num_reads = kwargs.get('num_reads', self.num_reads)
221
+
222
+ # Create BQM from Ising model
223
+ bqm = dimod.BinaryQuadraticModel.from_ising(h, J)
224
+
225
+ # Sample from the BQM
226
+ sampleset = self._sampler.sample(bqm, num_reads=num_reads, **kwargs)
227
+
228
+ # Convert results to standard format
229
+ results = {
230
+ 'samples': [],
231
+ 'energies': [],
232
+ 'num_occurrences': [],
233
+ 'success': True,
234
+ 'num_reads': len(sampleset),
235
+ 'timing': getattr(sampleset, 'info', {}).get('timing', {}),
236
+ 'problem_type': 'Ising'
237
+ }
238
+
239
+ for sample, energy, num_occur in sampleset.data(['sample', 'energy', 'num_occurrences']):
240
+ results['samples'].append(dict(sample))
241
+ results['energies'].append(energy)
242
+ results['num_occurrences'].append(num_occur)
243
+
244
+ return results
245
+
246
+ except Exception as e:
247
+ logger.error(f"Ising model solving failed: {e}")
248
+ return {
249
+ 'samples': [],
250
+ 'energies': [],
251
+ 'success': False,
252
+ 'error': str(e),
253
+ 'problem_type': 'Ising'
254
+ }
255
+
256
+ def solve_optimization_problem(self, problem: Union[Dict, Any], problem_type: str = 'auto') -> Dict[str, Any]:
257
+ """Generic optimization problem solver.
258
+
259
+ Args:
260
+ problem: Problem specification (QUBO dict, Ising model, or BQM)
261
+ problem_type: Type of problem ('qubo', 'ising', 'bqm', 'auto')
262
+
263
+ Returns:
264
+ Solution results
265
+
266
+ """
267
+ try:
268
+ if problem_type == 'auto':
269
+ # Try to detect problem type
270
+ if isinstance(problem, dict) and all(len(k) == 2 for k in problem.keys()):
271
+ problem_type = 'qubo'
272
+ elif hasattr(problem, 'linear') and hasattr(problem, 'quadratic'):
273
+ problem_type = 'bqm'
274
+ else:
275
+ raise ValueError("Cannot auto-detect problem type")
276
+
277
+ if problem_type == 'qubo':
278
+ return self.solve_qubo(problem)
279
+ elif problem_type == 'ising':
280
+ h, J = problem # Expecting tuple (h, J)
281
+ return self.solve_ising(h, J)
282
+ elif problem_type == 'bqm':
283
+ # Direct BQM solving
284
+ sampleset = self._sampler.sample(problem, num_reads=self.num_reads)
285
+ return self._convert_sampleset(sampleset, problem_type)
286
+ else:
287
+ raise ValueError(f"Unknown problem type: {problem_type}")
288
+
289
+ except Exception as e:
290
+ logger.error(f"Optimization problem solving failed: {e}")
291
+ return {
292
+ 'samples': [],
293
+ 'energies': [],
294
+ 'success': False,
295
+ 'error': str(e),
296
+ 'problem_type': problem_type
297
+ }
298
+
299
+ def _convert_sampleset(self, sampleset, problem_type: str) -> Dict[str, Any]:
300
+ """Convert D-Wave sampleset to standard format."""
301
+ results = {
302
+ 'samples': [],
303
+ 'energies': [],
304
+ 'num_occurrences': [],
305
+ 'success': True,
306
+ 'num_reads': len(sampleset),
307
+ 'timing': getattr(sampleset, 'info', {}).get('timing', {}),
308
+ 'problem_type': problem_type
309
+ }
310
+
311
+ for sample, energy, num_occur in sampleset.data(['sample', 'energy', 'num_occurrences']):
312
+ results['samples'].append(dict(sample))
313
+ results['energies'].append(energy)
314
+ results['num_occurrences'].append(num_occur)
315
+
316
+ return results
317
+
318
+ # ========================================================================
319
+ # Gate Model Compatibility (Limited Support)
320
+ # ========================================================================
321
+
322
+ def create_circuit(self, n_qubits: int) -> Dict[str, Any]:
323
+ """Limited circuit support for compatibility.
324
+
325
+ Note: D-Wave is not a gate-model quantum computer.
326
+ This returns a placeholder for optimization problems.
327
+ """
328
+ logger.warning("D-Wave Ocean backend does not support gate-model circuits")
329
+ return {
330
+ 'type': 'optimization_placeholder',
331
+ 'n_variables': n_qubits,
332
+ 'backend': 'ocean',
333
+ 'problem': None
334
+ }
335
+
336
+ def add_gate(self, circuit: Dict, gate: str, qubits: Union[int, List[int]],
337
+ params: Optional[List[float]] = None) -> Dict:
338
+ """Limited gate support - not applicable for annealing."""
339
+ logger.warning("Gate operations not supported on D-Wave annealing backend")
340
+ return circuit
341
+
342
+ def add_measurement(self, circuit: Dict, qubits: Union[int, List[int]]) -> Dict:
343
+ """Limited measurement support - not applicable for annealing."""
344
+ logger.warning("Measurements not applicable for D-Wave annealing backend")
345
+ return circuit
346
+
347
+ def execute_circuit(self, circuit: Dict, shots: Optional[int] = None) -> Dict[str, Any]:
348
+ """Limited circuit execution - redirects to optimization solving."""
349
+ logger.warning("Circuit execution not supported - use solve_qubo() or solve_ising() instead")
350
+ return {
351
+ 'counts': {},
352
+ 'shots': shots or self.shots,
353
+ 'success': False,
354
+ 'error': 'Use optimization problem methods instead of circuit execution',
355
+ 'backend': 'ocean'
356
+ }
357
+
358
+ # ========================================================================
359
+ # Backend Information
360
+ # ========================================================================
361
+
362
+ def get_backend_info(self) -> Dict[str, Any]:
363
+ """Get information about the D-Wave Ocean backend."""
364
+ info = {
365
+ 'backend_name': 'ocean',
366
+ 'device': self.device_name,
367
+ 'provider': 'D-Wave Systems',
368
+ 'num_reads': self.num_reads,
369
+ 'capabilities': self.capabilities,
370
+ 'quantum_annealing': True,
371
+ 'gate_model': False,
372
+ }
373
+
374
+ if self._sampler and hasattr(self._sampler, 'properties'):
375
+ try:
376
+ props = self._sampler.properties
377
+ info.update({
378
+ 'solver_name': getattr(self._sampler, 'solver', {}).get('name', 'unknown'),
379
+ 'num_qubits': len(props.get('qubits', [])),
380
+ 'connectivity': 'Chimera/Pegasus/Zephyr', # D-Wave topologies
381
+ })
382
+ except:
383
+ pass
384
+
385
+ return info
386
+
387
+ def get_version_info(self) -> Dict[str, str]:
388
+ """Get version information for Ocean dependencies."""
389
+ version_info = {'backend_version': '1.0.0'}
390
+
391
+ try:
392
+ version_info['dimod'] = dimod.__version__
393
+ except:
394
+ pass
395
+
396
+ try:
397
+ import dwave.system
398
+ version_info['dwave_system'] = dwave.system.__version__
399
+ except:
400
+ pass
401
+
402
+ try:
403
+ import dwave.samplers
404
+ version_info['dwave_samplers'] = dwave.samplers.__version__
405
+ except:
406
+ pass
407
+
408
+ return version_info
409
+
410
+ def is_available(self) -> bool:
411
+ """Check if the backend is available and properly configured."""
412
+ return OCEAN_AVAILABLE and self._sampler is not None
413
+
414
+ def get_circuit_info(self) -> Dict[str, Any]:
415
+ """Get circuit capabilities (limited for annealing backend)."""
416
+ return {
417
+ 'max_qubits': 0, # Not applicable
418
+ 'max_variables': self._get_max_variables(),
419
+ 'native_gates': [], # Not applicable
420
+ 'supports_mid_circuit_measurement': False,
421
+ 'supports_reset': False,
422
+ 'supports_conditional': False,
423
+ 'supports_optimization': True,
424
+ 'quantum_annealing': True,
425
+ }
426
+
427
+ def _get_n_qubits(self, circuit: Dict) -> int:
428
+ """Get number of qubits/variables (not applicable for annealing)."""
429
+ if isinstance(circuit, dict):
430
+ return circuit.get('n_variables', 0)
431
+ return 0
432
+
433
+ def get_statevector(self, circuit: Dict) -> np.ndarray:
434
+ """Get statevector (not applicable for annealing backend)."""
435
+ logger.warning("Statevector not applicable for quantum annealing backend")
436
+ return np.array([1.0 + 0j]) # Dummy statevector
437
+
438
+ # ========================================================================
439
+ # Convenience Methods for Common Optimization Problems
440
+ # ========================================================================
441
+
442
+ def solve_max_cut(self, graph: Union[Any, List[Tuple]], **kwargs) -> Dict[str, Any]:
443
+ """Solve Maximum Cut problem on a graph."""
444
+ try:
445
+ if not nx:
446
+ raise ImportError("NetworkX not available for graph operations")
447
+
448
+ if isinstance(graph, list):
449
+ # Convert edge list to networkx graph
450
+ G = nx.Graph()
451
+ G.add_edges_from(graph)
452
+ else:
453
+ G = graph
454
+
455
+ # Convert to QUBO formulation
456
+ Q = {}
457
+ for i, j in G.edges():
458
+ Q[(i, i)] = Q.get((i, i), 0) + 1
459
+ Q[(j, j)] = Q.get((j, j), 0) + 1
460
+ Q[(i, j)] = Q.get((i, j), 0) - 2
461
+
462
+ return self.solve_qubo(Q, **kwargs)
463
+
464
+ except Exception as e:
465
+ logger.error(f"Max Cut solving failed: {e}")
466
+ return {'success': False, 'error': str(e)}
467
+
468
+ def solve_tsp(self, distance_matrix: np.ndarray, **kwargs) -> Dict[str, Any]:
469
+ """Solve Traveling Salesman Problem (simplified formulation)."""
470
+ try:
471
+ n_cities = len(distance_matrix)
472
+
473
+ # This is a simplified TSP formulation
474
+ # Full TSP requires more complex constraints
475
+ logger.warning("TSP formulation is simplified - may not give valid tours")
476
+
477
+ Q = {}
478
+ # Add distance costs
479
+ for i in range(n_cities):
480
+ for j in range(i+1, n_cities):
481
+ for t in range(n_cities):
482
+ # Variable x_it means city i is visited at time t
483
+ var_i = i * n_cities + t
484
+ var_j = j * n_cities + ((t + 1) % n_cities)
485
+ Q[(var_i, var_j)] = distance_matrix[i, j]
486
+
487
+ return self.solve_qubo(Q, **kwargs)
488
+
489
+ except Exception as e:
490
+ logger.error(f"TSP solving failed: {e}")
491
+ return {'success': False, 'error': str(e)}