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.
- superquantx/__init__.py +24 -12
- superquantx/algorithms/__init__.py +1 -1
- superquantx/algorithms/base_algorithm.py +36 -36
- superquantx/algorithms/hybrid_classifier.py +22 -22
- superquantx/algorithms/qaoa.py +29 -28
- superquantx/algorithms/quantum_agents.py +57 -56
- superquantx/algorithms/quantum_kmeans.py +17 -17
- superquantx/algorithms/quantum_nn.py +18 -18
- superquantx/algorithms/quantum_pca.py +26 -26
- superquantx/algorithms/quantum_svm.py +26 -25
- superquantx/algorithms/vqe.py +40 -39
- superquantx/algorithms.py +56 -55
- superquantx/backends/__init__.py +12 -12
- superquantx/backends/base_backend.py +25 -24
- superquantx/backends/braket_backend.py +21 -21
- superquantx/backends/cirq_backend.py +26 -26
- superquantx/backends/ocean_backend.py +38 -38
- superquantx/backends/pennylane_backend.py +12 -11
- superquantx/backends/qiskit_backend.py +12 -12
- superquantx/backends/simulator_backend.py +31 -17
- superquantx/backends/tket_backend.py +23 -23
- superquantx/circuits.py +25 -25
- superquantx/cli/commands.py +6 -7
- superquantx/cli/main.py +5 -6
- superquantx/client.py +42 -42
- superquantx/config.py +14 -14
- superquantx/datasets/__init__.py +58 -0
- superquantx/datasets/molecular.py +307 -0
- superquantx/datasets/preprocessing.py +279 -0
- superquantx/datasets/quantum_datasets.py +277 -0
- superquantx/datasets/synthetic.py +300 -0
- superquantx/exceptions.py +29 -29
- superquantx/gates.py +26 -26
- superquantx/logging_config.py +29 -29
- superquantx/measurements.py +53 -54
- superquantx/ml.py +51 -52
- superquantx/noise.py +49 -49
- superquantx/utils/benchmarking.py +41 -36
- superquantx/utils/classical_utils.py +32 -32
- superquantx/utils/feature_mapping.py +40 -35
- superquantx/utils/optimization.py +28 -26
- superquantx/utils/quantum_utils.py +47 -48
- superquantx/utils/visualization.py +49 -49
- superquantx/version.py +3 -3
- {superquantx-0.1.0.dist-info → superquantx-0.1.1.dist-info}/METADATA +18 -16
- superquantx-0.1.1.dist-info/RECORD +51 -0
- superquantx-0.1.1.dist-info/licenses/LICENSE +180 -0
- superquantx-0.1.0.dist-info/RECORD +0 -46
- superquantx-0.1.0.dist-info/licenses/LICENSE +0 -21
- {superquantx-0.1.0.dist-info → superquantx-0.1.1.dist-info}/WHEEL +0 -0
- {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
|
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:
|
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:
|
40
|
-
original_error:
|
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:
|
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:
|
88
|
-
step:
|
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:
|
132
|
-
valid_values:
|
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:
|
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:
|
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:
|
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:
|
257
|
-
valid_values:
|
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
|
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
|
-
|
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:
|
203
|
-
description:
|
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) ->
|
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) ->
|
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() ->
|
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() ->
|
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.
|
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,
|
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:
|
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:
|
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 = []
|
superquantx/logging_config.py
CHANGED
@@ -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
|
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:
|
32
|
-
self._experiment_id:
|
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:
|
37
|
-
log_file:
|
38
|
-
experiment_id:
|
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:
|
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:
|
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:
|
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:
|
228
|
-
metadata:
|
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) ->
|
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) ->
|
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:
|
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:
|
284
|
-
log_file:
|
285
|
-
experiment_id:
|
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
|