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
superquantx/config.py ADDED
@@ -0,0 +1,326 @@
1
+ """Global configuration for SuperQuantX.
2
+
3
+ This module provides configuration management for the SuperQuantX package,
4
+ including backend settings, default parameters, and runtime options.
5
+ """
6
+
7
+ import json
8
+ import logging
9
+ import os
10
+ from pathlib import Path
11
+ from typing import Any, Dict, Optional, Union
12
+
13
+ import yaml
14
+
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ class Config:
19
+ """Global configuration class for SuperQuantX."""
20
+
21
+ def __init__(self) -> None:
22
+ """Initialize configuration with defaults."""
23
+ self._config: Dict[str, Any] = {
24
+ # Backend configuration
25
+ "backends": {
26
+ "default": "auto",
27
+ "auto_selection_strategy": "performance", # "performance", "cost", "speed", "accuracy"
28
+ "fallback_backend": "pennylane",
29
+ "timeout": 300, # seconds
30
+ "max_retries": 3,
31
+ },
32
+
33
+ # Algorithm defaults
34
+ "algorithms": {
35
+ "default_shots": 1024,
36
+ "optimization_level": 1,
37
+ "seed": None,
38
+ "max_iterations": 1000,
39
+ "convergence_tolerance": 1e-6,
40
+ },
41
+
42
+ # Visualization settings
43
+ "visualization": {
44
+ "backend": "matplotlib", # "matplotlib", "plotly", "both"
45
+ "style": "default",
46
+ "save_figures": False,
47
+ "figure_format": "png",
48
+ "dpi": 150,
49
+ },
50
+
51
+ # Benchmarking configuration
52
+ "benchmarks": {
53
+ "default_runs": 5,
54
+ "include_classical": True,
55
+ "save_results": True,
56
+ "results_dir": "benchmark_results",
57
+ },
58
+
59
+ # Logging configuration
60
+ "logging": {
61
+ "level": "INFO",
62
+ "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
63
+ "file": None, # Log file path, None for console only
64
+ },
65
+
66
+ # Cache settings
67
+ "cache": {
68
+ "enabled": True,
69
+ "directory": ".superquantx_cache",
70
+ "max_size_mb": 1000,
71
+ "ttl_hours": 24,
72
+ },
73
+
74
+ # Platform-specific settings
75
+ "platforms": {
76
+ "ibm": {
77
+ "token": None,
78
+ "hub": "ibm-q",
79
+ "group": "open",
80
+ "project": "main",
81
+ },
82
+ "braket": {
83
+ "s3_folder": None,
84
+ "device_arn": None,
85
+ },
86
+ "azure": {
87
+ "resource_id": None,
88
+ "location": None,
89
+ },
90
+ "dwave": {
91
+ "token": None,
92
+ "solver": None,
93
+ },
94
+ "rigetti": {
95
+ "api_key": None,
96
+ "user_id": None,
97
+ },
98
+ },
99
+
100
+ # Development settings
101
+ "development": {
102
+ "debug": False,
103
+ "profile": False,
104
+ "warnings": True,
105
+ },
106
+ }
107
+
108
+ # Load configuration from files
109
+ self._load_config_files()
110
+
111
+ # Override with environment variables
112
+ self._load_environment_variables()
113
+
114
+ def _load_config_files(self) -> None:
115
+ """Load configuration from YAML/JSON files."""
116
+ config_paths = [
117
+ Path.home() / ".superquantx" / "config.yaml",
118
+ Path.home() / ".superquantx" / "config.yml",
119
+ Path.home() / ".superquantx" / "config.json",
120
+ Path.cwd() / "superquantx_config.yaml",
121
+ Path.cwd() / "superquantx_config.yml",
122
+ Path.cwd() / "superquantx_config.json",
123
+ ]
124
+
125
+ for config_path in config_paths:
126
+ if config_path.exists():
127
+ try:
128
+ with open(config_path) as f:
129
+ if config_path.suffix.lower() in [".yaml", ".yml"]:
130
+ file_config = yaml.safe_load(f)
131
+ else:
132
+ file_config = json.load(f)
133
+
134
+ if file_config:
135
+ self._merge_config(file_config)
136
+ logger.info(f"Loaded configuration from {config_path}")
137
+
138
+ except Exception as e:
139
+ logger.warning(f"Failed to load config from {config_path}: {e}")
140
+
141
+ def _load_environment_variables(self) -> None:
142
+ """Load configuration from environment variables."""
143
+ env_mappings = {
144
+ "SUPERQUANTX_DEFAULT_BACKEND": ("backends", "default"),
145
+ "SUPERQUANTX_DEFAULT_SHOTS": ("algorithms", "default_shots"),
146
+ "SUPERQUANTX_LOG_LEVEL": ("logging", "level"),
147
+ "SUPERQUANTX_CACHE_ENABLED": ("cache", "enabled"),
148
+ "SUPERQUANTX_DEBUG": ("development", "debug"),
149
+
150
+ # Platform tokens
151
+ "IBM_QUANTUM_TOKEN": ("platforms", "ibm", "token"),
152
+ "AWS_BRAKET_S3_FOLDER": ("platforms", "braket", "s3_folder"),
153
+ "AZURE_QUANTUM_RESOURCE_ID": ("platforms", "azure", "resource_id"),
154
+ "DWAVE_API_TOKEN": ("platforms", "dwave", "token"),
155
+ "RIGETTI_API_KEY": ("platforms", "rigetti", "api_key"),
156
+ }
157
+
158
+ for env_var, config_path in env_mappings.items():
159
+ value = os.getenv(env_var)
160
+ if value is not None:
161
+ self._set_nested_value(config_path, value)
162
+
163
+ def _merge_config(self, new_config: Dict[str, Any]) -> None:
164
+ """Merge new configuration with existing configuration."""
165
+ def merge_dicts(base: Dict, update: Dict) -> Dict:
166
+ for key, value in update.items():
167
+ if key in base and isinstance(base[key], dict) and isinstance(value, dict):
168
+ base[key] = merge_dicts(base[key], value)
169
+ else:
170
+ base[key] = value
171
+ return base
172
+
173
+ self._config = merge_dicts(self._config, new_config)
174
+
175
+ def _set_nested_value(self, path: tuple, value: Any) -> None:
176
+ """Set a nested configuration value."""
177
+ current = self._config
178
+ for key in path[:-1]:
179
+ if key not in current:
180
+ current[key] = {}
181
+ current = current[key]
182
+
183
+ # Type conversion for common types
184
+ if isinstance(value, str):
185
+ if value.lower() in ["true", "false"]:
186
+ value = value.lower() == "true"
187
+ elif value.isdigit():
188
+ value = int(value)
189
+ elif "." in value and value.replace(".", "").isdigit():
190
+ value = float(value)
191
+
192
+ current[path[-1]] = value
193
+
194
+ def get(self, key: str, default: Any = None) -> Any:
195
+ """Get configuration value using dot notation."""
196
+ keys = key.split(".")
197
+ current = self._config
198
+
199
+ try:
200
+ for k in keys:
201
+ current = current[k]
202
+ return current
203
+ except (KeyError, TypeError):
204
+ return default
205
+
206
+ def set(self, key: str, value: Any) -> None:
207
+ """Set configuration value using dot notation."""
208
+ keys = key.split(".")
209
+ current = self._config
210
+
211
+ for k in keys[:-1]:
212
+ if k not in current:
213
+ current[k] = {}
214
+ current = current[k]
215
+
216
+ current[keys[-1]] = value
217
+
218
+ def update(self, updates: Dict[str, Any]) -> None:
219
+ """Update configuration with a dictionary of values."""
220
+ self._merge_config(updates)
221
+
222
+ def save(self, path: Optional[Union[str, Path]] = None) -> None:
223
+ """Save current configuration to file."""
224
+ if path is None:
225
+ path = Path.home() / ".superquantx" / "config.yaml"
226
+ else:
227
+ path = Path(path)
228
+
229
+ # Create directory if it doesn't exist
230
+ path.parent.mkdir(parents=True, exist_ok=True)
231
+
232
+ try:
233
+ with open(path, "w") as f:
234
+ yaml.dump(self._config, f, default_flow_style=False, indent=2)
235
+ logger.info(f"Configuration saved to {path}")
236
+ except Exception as e:
237
+ logger.error(f"Failed to save configuration to {path}: {e}")
238
+
239
+ def reset(self) -> None:
240
+ """Reset configuration to defaults."""
241
+ self.__init__()
242
+
243
+ def to_dict(self) -> Dict[str, Any]:
244
+ """Get configuration as dictionary."""
245
+ return self._config.copy()
246
+
247
+ def print_config(self) -> None:
248
+ """Print current configuration."""
249
+ import pprint
250
+ pprint.pprint(self._config, indent=2)
251
+
252
+ def validate(self) -> bool:
253
+ """Validate current configuration."""
254
+ # Add validation logic here
255
+ return True
256
+
257
+ # Global configuration instance
258
+ config = Config()
259
+
260
+ def configure(
261
+ backend: Optional[str] = None,
262
+ shots: Optional[int] = None,
263
+ debug: Optional[bool] = None,
264
+ **kwargs
265
+ ) -> None:
266
+ """Configure SuperQuantX settings.
267
+
268
+ Args:
269
+ backend: Default backend to use
270
+ shots: Default number of shots for quantum circuits
271
+ debug: Enable debug mode
272
+ **kwargs: Additional configuration parameters
273
+
274
+ """
275
+ updates = {}
276
+
277
+ if backend is not None:
278
+ updates["backends.default"] = backend
279
+
280
+ if shots is not None:
281
+ updates["algorithms.default_shots"] = shots
282
+
283
+ if debug is not None:
284
+ updates["development.debug"] = debug
285
+
286
+ # Handle additional keyword arguments
287
+ for key, value in kwargs.items():
288
+ updates[key] = value
289
+
290
+ # Apply updates
291
+ for key, value in updates.items():
292
+ config.set(key, value)
293
+
294
+ # Setup logging if level changed
295
+ if "logging.level" in updates:
296
+ setup_logging()
297
+
298
+ def setup_logging() -> None:
299
+ """Setup logging configuration."""
300
+ level = getattr(logging, config.get("logging.level", "INFO").upper())
301
+ format_str = config.get("logging.format")
302
+ log_file = config.get("logging.file")
303
+
304
+ # Configure root logger
305
+ logging.basicConfig(
306
+ level=level,
307
+ format=format_str,
308
+ filename=log_file,
309
+ filemode="a" if log_file else None,
310
+ force=True,
311
+ )
312
+
313
+ def get_platform_config(platform: str) -> Dict[str, Any]:
314
+ """Get configuration for a specific platform.
315
+
316
+ Args:
317
+ platform: Platform name (e.g., 'ibm', 'braket', 'azure')
318
+
319
+ Returns:
320
+ Platform configuration dictionary
321
+
322
+ """
323
+ return config.get(f"platforms.{platform}", {})
324
+
325
+ # Initialize logging on import
326
+ setup_logging()
@@ -0,0 +1,287 @@
1
+ """Custom exceptions for SuperQuantX.
2
+
3
+ This module defines custom exceptions used throughout the SuperQuantX library
4
+ to provide clear error messages and proper error handling for quantum-agentic
5
+ AI research workflows.
6
+ """
7
+
8
+ from typing import Any, Optional
9
+
10
+
11
+ class SuperQuantXError(Exception):
12
+ """Base exception for all SuperQuantX errors."""
13
+
14
+ def __init__(self, message: str, error_code: Optional[str] = None) -> None:
15
+ """Initialize SuperQuantX base exception.
16
+
17
+ Args:
18
+ message: Human-readable error message
19
+ error_code: Optional error code for programmatic handling
20
+
21
+ """
22
+ super().__init__(message)
23
+ self.message = message
24
+ self.error_code = error_code
25
+
26
+ def __str__(self) -> str:
27
+ """Return string representation of the error."""
28
+ if self.error_code:
29
+ return f"[{self.error_code}] {self.message}"
30
+ return self.message
31
+
32
+
33
+ class BackendError(SuperQuantXError):
34
+ """Raised when quantum backend operations fail."""
35
+
36
+ def __init__(
37
+ self,
38
+ message: str,
39
+ backend_name: Optional[str] = None,
40
+ original_error: Optional[Exception] = None,
41
+ ) -> None:
42
+ """Initialize backend error.
43
+
44
+ Args:
45
+ message: Error description
46
+ backend_name: Name of the backend that failed
47
+ original_error: Original exception that caused this error
48
+
49
+ """
50
+ if backend_name:
51
+ full_message = f"Backend '{backend_name}': {message}"
52
+ else:
53
+ full_message = message
54
+
55
+ super().__init__(full_message, error_code="BACKEND_ERROR")
56
+ self.backend_name = backend_name
57
+ self.original_error = original_error
58
+
59
+
60
+ class BackendNotAvailableError(BackendError):
61
+ """Raised when a required quantum backend is not available."""
62
+
63
+ def __init__(self, backend_name: str, missing_dependencies: Optional[list[str]] = None) -> None:
64
+ """Initialize backend not available error.
65
+
66
+ Args:
67
+ backend_name: Name of the unavailable backend
68
+ missing_dependencies: List of missing dependency packages
69
+
70
+ """
71
+ if missing_dependencies:
72
+ deps = ", ".join(missing_dependencies)
73
+ message = f"Backend not available. Missing dependencies: {deps}. Install with: pip install superquantx[{backend_name}]"
74
+ else:
75
+ message = f"Backend not available. Install with: pip install superquantx[{backend_name}]"
76
+
77
+ super().__init__(message, backend_name, error_code="BACKEND_NOT_AVAILABLE")
78
+ self.missing_dependencies = missing_dependencies or []
79
+
80
+
81
+ class AlgorithmError(SuperQuantXError):
82
+ """Raised when quantum algorithm operations fail."""
83
+
84
+ def __init__(
85
+ self,
86
+ message: str,
87
+ algorithm_name: Optional[str] = None,
88
+ step: Optional[str] = None,
89
+ ) -> None:
90
+ """Initialize algorithm error.
91
+
92
+ Args:
93
+ message: Error description
94
+ algorithm_name: Name of the algorithm that failed
95
+ step: Specific step where the error occurred (e.g., 'fit', 'predict')
96
+
97
+ """
98
+ if algorithm_name and step:
99
+ full_message = f"{algorithm_name}.{step}(): {message}"
100
+ elif algorithm_name:
101
+ full_message = f"{algorithm_name}: {message}"
102
+ else:
103
+ full_message = message
104
+
105
+ super().__init__(full_message, error_code="ALGORITHM_ERROR")
106
+ self.algorithm_name = algorithm_name
107
+ self.step = step
108
+
109
+
110
+ class NotFittedError(AlgorithmError):
111
+ """Raised when an algorithm is used before being fitted."""
112
+
113
+ def __init__(self, algorithm_name: str) -> None:
114
+ """Initialize not fitted error.
115
+
116
+ Args:
117
+ algorithm_name: Name of the algorithm that needs fitting
118
+
119
+ """
120
+ message = "This algorithm instance is not fitted yet. Call 'fit' with appropriate arguments before using this method."
121
+ super().__init__(message, algorithm_name, error_code="NOT_FITTED")
122
+
123
+
124
+ class InvalidParameterError(SuperQuantXError):
125
+ """Raised when invalid parameters are provided to algorithms or backends."""
126
+
127
+ def __init__(
128
+ self,
129
+ parameter_name: str,
130
+ parameter_value: Any,
131
+ expected_type: Optional[str] = None,
132
+ valid_values: Optional[list[Any]] = None,
133
+ ) -> None:
134
+ """Initialize invalid parameter error.
135
+
136
+ Args:
137
+ parameter_name: Name of the invalid parameter
138
+ parameter_value: The invalid value provided
139
+ expected_type: Expected type description
140
+ valid_values: List of valid values (for enumerated parameters)
141
+
142
+ """
143
+ if valid_values:
144
+ valid_str = ", ".join(map(str, valid_values))
145
+ message = f"Invalid value for parameter '{parameter_name}': {parameter_value}. Valid values are: {valid_str}"
146
+ elif expected_type:
147
+ message = f"Invalid type for parameter '{parameter_name}': got {type(parameter_value).__name__}, expected {expected_type}"
148
+ else:
149
+ message = f"Invalid value for parameter '{parameter_name}': {parameter_value}"
150
+
151
+ super().__init__(message, error_code="INVALID_PARAMETER")
152
+ self.parameter_name = parameter_name
153
+ self.parameter_value = parameter_value
154
+ self.expected_type = expected_type
155
+ self.valid_values = valid_values
156
+
157
+
158
+ class QuantumCircuitError(SuperQuantXError):
159
+ """Raised when quantum circuit operations fail."""
160
+
161
+ def __init__(
162
+ self,
163
+ message: str,
164
+ circuit_info: Optional[dict[str, Any]] = None,
165
+ ) -> None:
166
+ """Initialize quantum circuit error.
167
+
168
+ Args:
169
+ message: Error description
170
+ circuit_info: Dictionary with circuit information (qubits, gates, etc.)
171
+
172
+ """
173
+ super().__init__(message, error_code="CIRCUIT_ERROR")
174
+ self.circuit_info = circuit_info or {}
175
+
176
+
177
+ class ConfigurationError(SuperQuantXError):
178
+ """Raised when configuration issues are detected."""
179
+
180
+ def __init__(self, message: str, config_key: Optional[str] = None) -> None:
181
+ """Initialize configuration error.
182
+
183
+ Args:
184
+ message: Error description
185
+ config_key: The configuration key that caused the error
186
+
187
+ """
188
+ if config_key:
189
+ full_message = f"Configuration error for '{config_key}': {message}"
190
+ else:
191
+ full_message = f"Configuration error: {message}"
192
+
193
+ super().__init__(full_message, error_code="CONFIG_ERROR")
194
+ self.config_key = config_key
195
+
196
+
197
+ class ResearchModeError(SuperQuantXError):
198
+ """Raised when research-only features are used incorrectly."""
199
+
200
+ def __init__(self, message: str, feature_name: Optional[str] = None) -> None:
201
+ """Initialize research mode error.
202
+
203
+ Args:
204
+ message: Error description
205
+ feature_name: Name of the research feature
206
+
207
+ """
208
+ warning_prefix = "⚠️ RESEARCH SOFTWARE WARNING: "
209
+ if feature_name:
210
+ full_message = f"{warning_prefix}{feature_name}: {message}"
211
+ else:
212
+ full_message = f"{warning_prefix}{message}"
213
+
214
+ super().__init__(full_message, error_code="RESEARCH_MODE")
215
+ self.feature_name = feature_name
216
+
217
+
218
+ # Utility functions for error handling
219
+ def validate_backend_available(backend_name: str, backend_instance: Any) -> None:
220
+ """Validate that a backend is available and properly initialized.
221
+
222
+ Args:
223
+ backend_name: Name of the backend to validate
224
+ backend_instance: The backend instance to check
225
+
226
+ Raises:
227
+ BackendNotAvailableError: If backend is not available
228
+ BackendError: If backend is improperly initialized
229
+
230
+ """
231
+ if backend_instance is None:
232
+ raise BackendNotAvailableError(backend_name)
233
+
234
+ if hasattr(backend_instance, 'is_available') and not backend_instance.is_available():
235
+ raise BackendNotAvailableError(backend_name)
236
+
237
+
238
+ def validate_fitted(algorithm_instance: Any, algorithm_name: str) -> None:
239
+ """Validate that an algorithm has been fitted.
240
+
241
+ Args:
242
+ algorithm_instance: The algorithm instance to check
243
+ algorithm_name: Name of the algorithm
244
+
245
+ Raises:
246
+ NotFittedError: If algorithm is not fitted
247
+
248
+ """
249
+ if not getattr(algorithm_instance, 'is_fitted', False):
250
+ raise NotFittedError(algorithm_name)
251
+
252
+
253
+ def validate_parameter(
254
+ parameter_name: str,
255
+ parameter_value: Any,
256
+ expected_type: Optional[type] = None,
257
+ valid_values: Optional[list[Any]] = None,
258
+ allow_none: bool = False,
259
+ ) -> None:
260
+ """Validate a parameter value.
261
+
262
+ Args:
263
+ parameter_name: Name of the parameter
264
+ parameter_value: Value to validate
265
+ expected_type: Expected Python type
266
+ valid_values: List of valid values
267
+ allow_none: Whether None is an acceptable value
268
+
269
+ Raises:
270
+ InvalidParameterError: If parameter is invalid
271
+
272
+ """
273
+ if parameter_value is None and allow_none:
274
+ return
275
+
276
+ if parameter_value is None and not allow_none:
277
+ raise InvalidParameterError(parameter_name, parameter_value, "non-None value")
278
+
279
+ if expected_type and not isinstance(parameter_value, expected_type):
280
+ raise InvalidParameterError(
281
+ parameter_name,
282
+ parameter_value,
283
+ expected_type.__name__
284
+ )
285
+
286
+ if valid_values and parameter_value not in valid_values:
287
+ raise InvalidParameterError(parameter_name, parameter_value, valid_values=valid_values)