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
superquantx/exceptions.py CHANGED
@@ -5,15 +5,15 @@ to provide clear error messages and proper error handling for quantum-agentic
5
5
  AI research workflows.
6
6
  """
7
7
 
8
- from typing import Any, Optional
8
+ from typing import Any
9
9
 
10
10
 
11
11
  class SuperQuantXError(Exception):
12
12
  """Base exception for all SuperQuantX errors."""
13
13
 
14
- def __init__(self, message: str, error_code: Optional[str] = None) -> None:
14
+ def __init__(self, message: str, error_code: str | None = None) -> None:
15
15
  """Initialize SuperQuantX base exception.
16
-
16
+
17
17
  Args:
18
18
  message: Human-readable error message
19
19
  error_code: Optional error code for programmatic handling
@@ -36,11 +36,11 @@ class BackendError(SuperQuantXError):
36
36
  def __init__(
37
37
  self,
38
38
  message: str,
39
- backend_name: Optional[str] = None,
40
- original_error: Optional[Exception] = None,
39
+ backend_name: str | None = None,
40
+ original_error: Exception | None = None,
41
41
  ) -> None:
42
42
  """Initialize backend error.
43
-
43
+
44
44
  Args:
45
45
  message: Error description
46
46
  backend_name: Name of the backend that failed
@@ -60,9 +60,9 @@ class BackendError(SuperQuantXError):
60
60
  class BackendNotAvailableError(BackendError):
61
61
  """Raised when a required quantum backend is not available."""
62
62
 
63
- def __init__(self, backend_name: str, missing_dependencies: Optional[list[str]] = None) -> None:
63
+ def __init__(self, backend_name: str, missing_dependencies: list[str] | None = None) -> None:
64
64
  """Initialize backend not available error.
65
-
65
+
66
66
  Args:
67
67
  backend_name: Name of the unavailable backend
68
68
  missing_dependencies: List of missing dependency packages
@@ -84,11 +84,11 @@ class AlgorithmError(SuperQuantXError):
84
84
  def __init__(
85
85
  self,
86
86
  message: str,
87
- algorithm_name: Optional[str] = None,
88
- step: Optional[str] = None,
87
+ algorithm_name: str | None = None,
88
+ step: str | None = None,
89
89
  ) -> None:
90
90
  """Initialize algorithm error.
91
-
91
+
92
92
  Args:
93
93
  message: Error description
94
94
  algorithm_name: Name of the algorithm that failed
@@ -112,7 +112,7 @@ class NotFittedError(AlgorithmError):
112
112
 
113
113
  def __init__(self, algorithm_name: str) -> None:
114
114
  """Initialize not fitted error.
115
-
115
+
116
116
  Args:
117
117
  algorithm_name: Name of the algorithm that needs fitting
118
118
 
@@ -128,11 +128,11 @@ class InvalidParameterError(SuperQuantXError):
128
128
  self,
129
129
  parameter_name: str,
130
130
  parameter_value: Any,
131
- expected_type: Optional[str] = None,
132
- valid_values: Optional[list[Any]] = None,
131
+ expected_type: str | None = None,
132
+ valid_values: list[Any] | None = None,
133
133
  ) -> None:
134
134
  """Initialize invalid parameter error.
135
-
135
+
136
136
  Args:
137
137
  parameter_name: Name of the invalid parameter
138
138
  parameter_value: The invalid value provided
@@ -161,10 +161,10 @@ class QuantumCircuitError(SuperQuantXError):
161
161
  def __init__(
162
162
  self,
163
163
  message: str,
164
- circuit_info: Optional[dict[str, Any]] = None,
164
+ circuit_info: dict[str, Any] | None = None,
165
165
  ) -> None:
166
166
  """Initialize quantum circuit error.
167
-
167
+
168
168
  Args:
169
169
  message: Error description
170
170
  circuit_info: Dictionary with circuit information (qubits, gates, etc.)
@@ -177,9 +177,9 @@ class QuantumCircuitError(SuperQuantXError):
177
177
  class ConfigurationError(SuperQuantXError):
178
178
  """Raised when configuration issues are detected."""
179
179
 
180
- def __init__(self, message: str, config_key: Optional[str] = None) -> None:
180
+ def __init__(self, message: str, config_key: str | None = None) -> None:
181
181
  """Initialize configuration error.
182
-
182
+
183
183
  Args:
184
184
  message: Error description
185
185
  config_key: The configuration key that caused the error
@@ -197,9 +197,9 @@ class ConfigurationError(SuperQuantXError):
197
197
  class ResearchModeError(SuperQuantXError):
198
198
  """Raised when research-only features are used incorrectly."""
199
199
 
200
- def __init__(self, message: str, feature_name: Optional[str] = None) -> None:
200
+ def __init__(self, message: str, feature_name: str | None = None) -> None:
201
201
  """Initialize research mode error.
202
-
202
+
203
203
  Args:
204
204
  message: Error description
205
205
  feature_name: Name of the research feature
@@ -218,11 +218,11 @@ class ResearchModeError(SuperQuantXError):
218
218
  # Utility functions for error handling
219
219
  def validate_backend_available(backend_name: str, backend_instance: Any) -> None:
220
220
  """Validate that a backend is available and properly initialized.
221
-
221
+
222
222
  Args:
223
223
  backend_name: Name of the backend to validate
224
224
  backend_instance: The backend instance to check
225
-
225
+
226
226
  Raises:
227
227
  BackendNotAvailableError: If backend is not available
228
228
  BackendError: If backend is improperly initialized
@@ -237,11 +237,11 @@ def validate_backend_available(backend_name: str, backend_instance: Any) -> None
237
237
 
238
238
  def validate_fitted(algorithm_instance: Any, algorithm_name: str) -> None:
239
239
  """Validate that an algorithm has been fitted.
240
-
240
+
241
241
  Args:
242
242
  algorithm_instance: The algorithm instance to check
243
243
  algorithm_name: Name of the algorithm
244
-
244
+
245
245
  Raises:
246
246
  NotFittedError: If algorithm is not fitted
247
247
 
@@ -253,19 +253,19 @@ def validate_fitted(algorithm_instance: Any, algorithm_name: str) -> None:
253
253
  def validate_parameter(
254
254
  parameter_name: str,
255
255
  parameter_value: Any,
256
- expected_type: Optional[type] = None,
257
- valid_values: Optional[list[Any]] = None,
256
+ expected_type: type | None = None,
257
+ valid_values: list[Any] | None = None,
258
258
  allow_none: bool = False,
259
259
  ) -> None:
260
260
  """Validate a parameter value.
261
-
261
+
262
262
  Args:
263
263
  parameter_name: Name of the parameter
264
264
  parameter_value: Value to validate
265
265
  expected_type: Expected Python type
266
266
  valid_values: List of valid values
267
267
  allow_none: Whether None is an acceptable value
268
-
268
+
269
269
  Raises:
270
270
  InvalidParameterError: If parameter is invalid
271
271
 
superquantx/gates.py CHANGED
@@ -2,7 +2,7 @@
2
2
  """
3
3
 
4
4
  import math
5
- from typing import Dict, List, Optional, Tuple, Union
5
+ from typing import Union
6
6
 
7
7
  import numpy as np
8
8
  from scipy.linalg import expm
@@ -13,7 +13,7 @@ class GateMatrix:
13
13
  """
14
14
 
15
15
  # Pauli matrices
16
- I = np.array([[1, 0], [0, 1]], dtype=complex)
16
+ identity = np.array([[1, 0], [0, 1]], dtype=complex)
17
17
  X = np.array([[0, 1], [1, 0]], dtype=complex)
18
18
  Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
19
19
  Z = np.array([[1, 0], [0, -1]], dtype=complex)
@@ -199,11 +199,11 @@ class ParametricGate:
199
199
  name: str,
200
200
  num_qubits: int,
201
201
  matrix_func: callable,
202
- parameters: List[str],
203
- description: Optional[str] = None
202
+ parameters: list[str],
203
+ description: str | None = None
204
204
  ):
205
205
  """Initialize parametric gate
206
-
206
+
207
207
  Args:
208
208
  name: Gate name
209
209
  num_qubits: Number of qubits the gate acts on
@@ -238,12 +238,12 @@ class GateDecomposer:
238
238
  """
239
239
 
240
240
  @staticmethod
241
- def decompose_arbitrary_single_qubit(matrix: np.ndarray) -> List[Tuple[str, List[float]]]:
241
+ def decompose_arbitrary_single_qubit(matrix: np.ndarray) -> list[tuple[str, list[float]]]:
242
242
  """Decompose arbitrary single-qubit unitary into U3 gates
243
-
243
+
244
244
  Args:
245
245
  matrix: 2x2 unitary matrix
246
-
246
+
247
247
  Returns:
248
248
  List of (gate_name, parameters) tuples
249
249
 
@@ -279,9 +279,9 @@ class GateDecomposer:
279
279
  return decomposition
280
280
 
281
281
  @staticmethod
282
- def decompose_cnot_to_cz(control: int, target: int) -> List[Tuple[str, List[int], List[float]]]:
282
+ def decompose_cnot_to_cz(control: int, target: int) -> list[tuple[str, list[int], list[float]]]:
283
283
  """Decompose CNOT to CZ using Hadamard gates
284
-
284
+
285
285
  Returns:
286
286
  List of (gate_name, qubits, parameters) tuples
287
287
 
@@ -293,9 +293,9 @@ class GateDecomposer:
293
293
  ]
294
294
 
295
295
  @staticmethod
296
- def decompose_toffoli() -> List[Tuple[str, List[int], List[float]]]:
296
+ def decompose_toffoli() -> list[tuple[str, list[int], list[float]]]:
297
297
  """Decompose Toffoli gate into CNOT and single-qubit gates
298
-
298
+
299
299
  Returns:
300
300
  List of (gate_name, qubits, parameters) for qubits [0, 1, 2]
301
301
 
@@ -319,9 +319,9 @@ class GateDecomposer:
319
319
  ]
320
320
 
321
321
  @staticmethod
322
- def decompose_fredkin() -> List[Tuple[str, List[int], List[float]]]:
322
+ def decompose_fredkin() -> list[tuple[str, list[int], list[float]]]:
323
323
  """Decompose Fredkin gate into CNOT and Toffoli gates
324
-
324
+
325
325
  Returns:
326
326
  List of (gate_name, qubits, parameters) for qubits [0, 1, 2]
327
327
 
@@ -339,7 +339,7 @@ class PauliString:
339
339
 
340
340
  def __init__(self, pauli_ops: str, coefficient: complex = 1.0):
341
341
  """Initialize Pauli string
342
-
342
+
343
343
  Args:
344
344
  pauli_ops: String of Pauli operators (e.g., "IXZY")
345
345
  coefficient: Complex coefficient
@@ -357,7 +357,7 @@ class PauliString:
357
357
  def matrix(self) -> np.ndarray:
358
358
  """Get the matrix representation of the Pauli string"""
359
359
  matrices = {
360
- 'I': GateMatrix.I,
360
+ 'I': GateMatrix.identity,
361
361
  'X': GateMatrix.X,
362
362
  'Y': GateMatrix.Y,
363
363
  'Z': GateMatrix.Z
@@ -377,7 +377,7 @@ class PauliString:
377
377
  anti_commuting_pairs = {('X', 'Y'), ('Y', 'X'), ('X', 'Z'), ('Z', 'X'), ('Y', 'Z'), ('Z', 'Y')}
378
378
  anti_commutations = 0
379
379
 
380
- for op1, op2 in zip(self.pauli_ops, other.pauli_ops):
380
+ for op1, op2 in zip(self.pauli_ops, other.pauli_ops, strict=False):
381
381
  if (op1, op2) in anti_commuting_pairs:
382
382
  anti_commutations += 1
383
383
 
@@ -385,7 +385,7 @@ class PauliString:
385
385
 
386
386
  def __mul__(self, other: Union[complex, "PauliString"]) -> "PauliString":
387
387
  """Multiply with scalar or another Pauli string"""
388
- if isinstance(other, (int, float, complex)):
388
+ if isinstance(other, int | float | complex):
389
389
  return PauliString(self.pauli_ops, self.coefficient * other)
390
390
  elif isinstance(other, PauliString):
391
391
  if len(self.pauli_ops) != len(other.pauli_ops):
@@ -395,7 +395,7 @@ class PauliString:
395
395
  result_ops = []
396
396
  phase = 1
397
397
 
398
- for op1, op2 in zip(self.pauli_ops, other.pauli_ops):
398
+ for op1, op2 in zip(self.pauli_ops, other.pauli_ops, strict=False):
399
399
  if op1 == 'I':
400
400
  result_ops.append(op2)
401
401
  elif op2 == 'I':
@@ -441,9 +441,9 @@ class Hamiltonian:
441
441
  """Quantum Hamiltonian represented as sum of Pauli strings
442
442
  """
443
443
 
444
- def __init__(self, pauli_strings: List[PauliString]):
444
+ def __init__(self, pauli_strings: list[PauliString]):
445
445
  """Initialize Hamiltonian
446
-
446
+
447
447
  Args:
448
448
  pauli_strings: List of Pauli strings that sum to form the Hamiltonian
449
449
 
@@ -498,12 +498,12 @@ class Hamiltonian:
498
498
  return self * scalar
499
499
 
500
500
  @classmethod
501
- def from_dict(cls, hamiltonian_dict: Dict[str, complex]) -> "Hamiltonian":
501
+ def from_dict(cls, hamiltonian_dict: dict[str, complex]) -> "Hamiltonian":
502
502
  """Create Hamiltonian from dictionary
503
-
503
+
504
504
  Args:
505
505
  hamiltonian_dict: Dictionary mapping Pauli strings to coefficients
506
-
506
+
507
507
  Example:
508
508
  {"IXZI": 0.5, "YZII": -0.3, "ZXYX": 1.2j}
509
509
 
@@ -522,7 +522,7 @@ class Hamiltonian:
522
522
  periodic: bool = False
523
523
  ) -> "Hamiltonian":
524
524
  """Create Heisenberg model Hamiltonian
525
-
525
+
526
526
  H = Σᵢ (Jₓ XᵢXᵢ₊₁ + Jᵧ YᵢYᵢ₊₁ + Jᵤ ZᵢZᵢ₊₁)
527
527
  """
528
528
  pauli_strings = []
@@ -560,7 +560,7 @@ class Hamiltonian:
560
560
  periodic: bool = False
561
561
  ) -> "Hamiltonian":
562
562
  """Create transverse field Ising model Hamiltonian
563
-
563
+
564
564
  H = -J Σᵢ ZᵢZᵢ₊₁ - h Σᵢ Xᵢ
565
565
  """
566
566
  pauli_strings = []
@@ -8,14 +8,14 @@ import logging
8
8
  import sys
9
9
  import warnings
10
10
  from pathlib import Path
11
- from typing import Any, Dict, Optional, Union
11
+ from typing import Any
12
12
 
13
13
  from loguru import logger
14
14
 
15
15
 
16
16
  class SuperQuantXLogger:
17
17
  """Centralized logger for SuperQuantX with research-focused features.
18
-
18
+
19
19
  This logger provides:
20
20
  - Structured logging for research experiments
21
21
  - Performance tracking and benchmarking
@@ -28,19 +28,19 @@ class SuperQuantXLogger:
28
28
  """Initialize SuperQuantX logger."""
29
29
  self._configured = False
30
30
  self._log_level = "INFO"
31
- self._log_file: Optional[Path] = None
32
- self._experiment_id: Optional[str] = None
31
+ self._log_file: Path | None = None
32
+ self._experiment_id: str | None = None
33
33
 
34
34
  def configure(
35
35
  self,
36
- level: Union[str, int] = "INFO",
37
- log_file: Optional[Union[str, Path]] = None,
38
- experiment_id: Optional[str] = None,
36
+ level: str | int = "INFO",
37
+ log_file: str | Path | None = None,
38
+ experiment_id: str | None = None,
39
39
  enable_research_mode: bool = True,
40
40
  silence_warnings: bool = True,
41
41
  ) -> None:
42
42
  """Configure SuperQuantX logging.
43
-
43
+
44
44
  Args:
45
45
  level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
46
46
  log_file: Optional file path for log output
@@ -103,7 +103,7 @@ class SuperQuantXLogger:
103
103
  self._configured = True
104
104
  logger.info("SuperQuantX logging configured", extra={"component": "logging"})
105
105
 
106
- def _get_log_format(self, enable_research_mode: bool, experiment_id: Optional[str]) -> str:
106
+ def _get_log_format(self, enable_research_mode: bool, experiment_id: str | None) -> str:
107
107
  """Get logging format string based on configuration."""
108
108
  base_format = "{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{line} | {message}"
109
109
 
@@ -114,7 +114,7 @@ class SuperQuantXLogger:
114
114
 
115
115
  return base_format
116
116
 
117
- def _configure_stdlib_logging(self, level: Union[str, int]) -> None:
117
+ def _configure_stdlib_logging(self, level: str | int) -> None:
118
118
  """Configure standard library logging to work with loguru."""
119
119
  class InterceptHandler(logging.Handler):
120
120
  def emit(self, record: logging.LogRecord) -> None:
@@ -162,10 +162,10 @@ class SuperQuantXLogger:
162
162
 
163
163
  def get_experiment_logger(self, experiment_name: str) -> "loguru.Logger":
164
164
  """Get a logger for a specific research experiment.
165
-
165
+
166
166
  Args:
167
167
  experiment_name: Name of the experiment
168
-
168
+
169
169
  Returns:
170
170
  Configured logger instance with experiment context
171
171
 
@@ -174,10 +174,10 @@ class SuperQuantXLogger:
174
174
 
175
175
  def get_algorithm_logger(self, algorithm_name: str) -> "loguru.Logger":
176
176
  """Get a logger for a specific quantum algorithm.
177
-
177
+
178
178
  Args:
179
179
  algorithm_name: Name of the algorithm
180
-
180
+
181
181
  Returns:
182
182
  Configured logger instance with algorithm context
183
183
 
@@ -186,10 +186,10 @@ class SuperQuantXLogger:
186
186
 
187
187
  def get_backend_logger(self, backend_name: str) -> "loguru.Logger":
188
188
  """Get a logger for a specific quantum backend.
189
-
189
+
190
190
  Args:
191
191
  backend_name: Name of the backend
192
-
192
+
193
193
  Returns:
194
194
  Configured logger instance with backend context
195
195
 
@@ -200,10 +200,10 @@ class SuperQuantXLogger:
200
200
  self,
201
201
  operation: str,
202
202
  duration: float,
203
- metadata: Optional[Dict[str, Any]] = None,
203
+ metadata: dict[str, Any] | None = None,
204
204
  ) -> None:
205
205
  """Log performance metrics for research analysis.
206
-
206
+
207
207
  Args:
208
208
  operation: Name of the operation being measured
209
209
  duration: Duration in seconds
@@ -224,11 +224,11 @@ class SuperQuantXLogger:
224
224
  def log_experiment_result(
225
225
  self,
226
226
  experiment_name: str,
227
- results: Dict[str, Any],
228
- metadata: Optional[Dict[str, Any]] = None,
227
+ results: dict[str, Any],
228
+ metadata: dict[str, Any] | None = None,
229
229
  ) -> None:
230
230
  """Log experiment results for research tracking.
231
-
231
+
232
232
  Args:
233
233
  experiment_name: Name of the experiment
234
234
  results: Experiment results dictionary
@@ -252,23 +252,23 @@ class SuperQuantXLogger:
252
252
  return self._configured
253
253
 
254
254
  @property
255
- def log_file(self) -> Optional[Path]:
255
+ def log_file(self) -> Path | None:
256
256
  """Get the current log file path."""
257
257
  return self._log_file
258
258
 
259
259
  @property
260
- def experiment_id(self) -> Optional[str]:
260
+ def experiment_id(self) -> str | None:
261
261
  """Get the current experiment ID."""
262
262
  return self._experiment_id
263
263
 
264
264
 
265
265
  # Global logger instance
266
- _logger_instance: Optional[SuperQuantXLogger] = None
266
+ _logger_instance: SuperQuantXLogger | None = None
267
267
 
268
268
 
269
269
  def get_logger() -> SuperQuantXLogger:
270
270
  """Get the global SuperQuantX logger instance.
271
-
271
+
272
272
  Returns:
273
273
  Global logger instance
274
274
 
@@ -280,14 +280,14 @@ def get_logger() -> SuperQuantXLogger:
280
280
 
281
281
 
282
282
  def configure_logging(
283
- level: Union[str, int] = "INFO",
284
- log_file: Optional[Union[str, Path]] = None,
285
- experiment_id: Optional[str] = None,
283
+ level: str | int = "INFO",
284
+ log_file: str | Path | None = None,
285
+ experiment_id: str | None = None,
286
286
  enable_research_mode: bool = True,
287
287
  silence_warnings: bool = True,
288
288
  ) -> None:
289
289
  """Configure SuperQuantX logging (convenience function).
290
-
290
+
291
291
  Args:
292
292
  level: Logging level
293
293
  log_file: Optional log file path