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/noise.py
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
"""
|
3
3
|
|
4
4
|
from abc import ABC, abstractmethod
|
5
|
-
from typing import Any
|
5
|
+
from typing import Any
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
from pydantic import BaseModel, Field
|
@@ -17,7 +17,7 @@ class NoiseChannel(ABC):
|
|
17
17
|
|
18
18
|
def __init__(self, probability: float):
|
19
19
|
"""Initialize noise channel
|
20
|
-
|
20
|
+
|
21
21
|
Args:
|
22
22
|
probability: Noise probability (0 <= p <= 1)
|
23
23
|
|
@@ -27,7 +27,7 @@ class NoiseChannel(ABC):
|
|
27
27
|
self.probability = probability
|
28
28
|
|
29
29
|
@abstractmethod
|
30
|
-
def kraus_operators(self) ->
|
30
|
+
def kraus_operators(self) -> list[np.ndarray]:
|
31
31
|
"""Return Kraus operators for the noise channel"""
|
32
32
|
pass
|
33
33
|
|
@@ -47,7 +47,7 @@ class BitFlipChannel(NoiseChannel):
|
|
47
47
|
"""Bit flip (X) noise channel
|
48
48
|
"""
|
49
49
|
|
50
|
-
def kraus_operators(self) ->
|
50
|
+
def kraus_operators(self) -> list[np.ndarray]:
|
51
51
|
"""Kraus operators for bit flip channel"""
|
52
52
|
sqrt_p = np.sqrt(self.probability)
|
53
53
|
sqrt_1_p = np.sqrt(1 - self.probability)
|
@@ -72,7 +72,7 @@ class PhaseFlipChannel(NoiseChannel):
|
|
72
72
|
"""Phase flip (Z) noise channel
|
73
73
|
"""
|
74
74
|
|
75
|
-
def kraus_operators(self) ->
|
75
|
+
def kraus_operators(self) -> list[np.ndarray]:
|
76
76
|
"""Kraus operators for phase flip channel"""
|
77
77
|
sqrt_p = np.sqrt(self.probability)
|
78
78
|
sqrt_1_p = np.sqrt(1 - self.probability)
|
@@ -97,7 +97,7 @@ class BitPhaseFlipChannel(NoiseChannel):
|
|
97
97
|
"""Bit-phase flip (Y) noise channel
|
98
98
|
"""
|
99
99
|
|
100
|
-
def kraus_operators(self) ->
|
100
|
+
def kraus_operators(self) -> list[np.ndarray]:
|
101
101
|
"""Kraus operators for bit-phase flip channel"""
|
102
102
|
sqrt_p = np.sqrt(self.probability)
|
103
103
|
sqrt_1_p = np.sqrt(1 - self.probability)
|
@@ -122,7 +122,7 @@ class DepolarizingChannel(NoiseChannel):
|
|
122
122
|
"""Depolarizing noise channel
|
123
123
|
"""
|
124
124
|
|
125
|
-
def kraus_operators(self) ->
|
125
|
+
def kraus_operators(self) -> list[np.ndarray]:
|
126
126
|
"""Kraus operators for depolarizing channel"""
|
127
127
|
p = self.probability
|
128
128
|
|
@@ -146,7 +146,7 @@ class AmplitudeDampingChannel(NoiseChannel):
|
|
146
146
|
"""Amplitude damping noise channel (T1 decay)
|
147
147
|
"""
|
148
148
|
|
149
|
-
def kraus_operators(self) ->
|
149
|
+
def kraus_operators(self) -> list[np.ndarray]:
|
150
150
|
"""Kraus operators for amplitude damping channel"""
|
151
151
|
gamma = self.probability
|
152
152
|
|
@@ -177,7 +177,7 @@ class PhaseDampingChannel(NoiseChannel):
|
|
177
177
|
"""Phase damping noise channel (T2 dephasing)
|
178
178
|
"""
|
179
179
|
|
180
|
-
def kraus_operators(self) ->
|
180
|
+
def kraus_operators(self) -> list[np.ndarray]:
|
181
181
|
"""Kraus operators for phase damping channel"""
|
182
182
|
gamma = self.probability
|
183
183
|
|
@@ -208,7 +208,7 @@ class TwoQubitDepolarizingChannel(NoiseChannel):
|
|
208
208
|
"""Two-qubit depolarizing noise channel
|
209
209
|
"""
|
210
210
|
|
211
|
-
def kraus_operators(self) ->
|
211
|
+
def kraus_operators(self) -> list[np.ndarray]:
|
212
212
|
"""Kraus operators for two-qubit depolarizing channel"""
|
213
213
|
p = self.probability
|
214
214
|
|
@@ -249,27 +249,27 @@ class NoiseModel(BaseModel):
|
|
249
249
|
|
250
250
|
model_config = {"arbitrary_types_allowed": True}
|
251
251
|
|
252
|
-
single_qubit_error_rates:
|
252
|
+
single_qubit_error_rates: dict[str, float] = Field(
|
253
253
|
default_factory=dict,
|
254
254
|
description="Error rates for single-qubit gates"
|
255
255
|
)
|
256
256
|
|
257
|
-
two_qubit_error_rates:
|
257
|
+
two_qubit_error_rates: dict[str, float] = Field(
|
258
258
|
default_factory=dict,
|
259
259
|
description="Error rates for two-qubit gates"
|
260
260
|
)
|
261
261
|
|
262
|
-
readout_error_rates:
|
262
|
+
readout_error_rates: dict[int, float] = Field(
|
263
263
|
default_factory=dict,
|
264
264
|
description="Readout error rates per qubit"
|
265
265
|
)
|
266
266
|
|
267
|
-
coherence_times:
|
267
|
+
coherence_times: dict[str, dict[int, float]] = Field(
|
268
268
|
default_factory=dict,
|
269
269
|
description="T1 and T2 times per qubit"
|
270
270
|
)
|
271
271
|
|
272
|
-
crosstalk_matrix:
|
272
|
+
crosstalk_matrix: np.ndarray | None = Field(
|
273
273
|
default=None,
|
274
274
|
description="Crosstalk coupling matrix"
|
275
275
|
)
|
@@ -298,10 +298,10 @@ class NoiseModel(BaseModel):
|
|
298
298
|
|
299
299
|
def apply_to_circuit(self, circuit: QuantumCircuit) -> QuantumCircuit:
|
300
300
|
"""Apply noise model to quantum circuit
|
301
|
-
|
301
|
+
|
302
302
|
Args:
|
303
303
|
circuit: Original circuit
|
304
|
-
|
304
|
+
|
305
305
|
Returns:
|
306
306
|
Noisy circuit with error channels
|
307
307
|
|
@@ -357,13 +357,13 @@ class NoiseModel(BaseModel):
|
|
357
357
|
@classmethod
|
358
358
|
def from_device_properties(
|
359
359
|
cls,
|
360
|
-
device_props:
|
360
|
+
device_props: dict[str, Any]
|
361
361
|
) -> "NoiseModel":
|
362
362
|
"""Create noise model from device properties
|
363
|
-
|
363
|
+
|
364
364
|
Args:
|
365
365
|
device_props: Device property dictionary
|
366
|
-
|
366
|
+
|
367
367
|
Returns:
|
368
368
|
Noise model based on device properties
|
369
369
|
|
@@ -392,7 +392,7 @@ class NoiseModel(BaseModel):
|
|
392
392
|
t1_times = device_props["coherence_times"].get("T1", [])
|
393
393
|
t2_times = device_props["coherence_times"].get("T2", [])
|
394
394
|
|
395
|
-
for qubit, (t1, t2) in enumerate(zip(t1_times, t2_times)):
|
395
|
+
for qubit, (t1, t2) in enumerate(zip(t1_times, t2_times, strict=False)):
|
396
396
|
noise_model.set_coherence_time(qubit, t1, t2)
|
397
397
|
|
398
398
|
return noise_model
|
@@ -410,12 +410,12 @@ class NoiseModel(BaseModel):
|
|
410
410
|
readout_error: float = 1e-2
|
411
411
|
) -> "NoiseModel":
|
412
412
|
"""Create basic device noise model
|
413
|
-
|
413
|
+
|
414
414
|
Args:
|
415
415
|
single_qubit_error: Single-qubit gate error rate
|
416
416
|
two_qubit_error: Two-qubit gate error rate
|
417
417
|
readout_error: Readout error rate
|
418
|
-
|
418
|
+
|
419
419
|
Returns:
|
420
420
|
Basic noise model
|
421
421
|
|
@@ -438,9 +438,9 @@ class QuantumErrorCorrection:
|
|
438
438
|
"""
|
439
439
|
|
440
440
|
@staticmethod
|
441
|
-
def three_qubit_bit_flip_code() ->
|
441
|
+
def three_qubit_bit_flip_code() -> dict[str, Any]:
|
442
442
|
"""Three-qubit repetition code for bit flip errors
|
443
|
-
|
443
|
+
|
444
444
|
Returns:
|
445
445
|
Code properties and circuits
|
446
446
|
|
@@ -477,9 +477,9 @@ class QuantumErrorCorrection:
|
|
477
477
|
}
|
478
478
|
|
479
479
|
@staticmethod
|
480
|
-
def three_qubit_phase_flip_code() ->
|
480
|
+
def three_qubit_phase_flip_code() -> dict[str, Any]:
|
481
481
|
"""Three-qubit code for phase flip errors
|
482
|
-
|
482
|
+
|
483
483
|
Returns:
|
484
484
|
Code properties and circuits
|
485
485
|
|
@@ -525,9 +525,9 @@ class QuantumErrorCorrection:
|
|
525
525
|
}
|
526
526
|
|
527
527
|
@staticmethod
|
528
|
-
def nine_qubit_shor_code() ->
|
528
|
+
def nine_qubit_shor_code() -> dict[str, Any]:
|
529
529
|
"""Nine-qubit Shor code (corrects arbitrary single-qubit errors)
|
530
|
-
|
530
|
+
|
531
531
|
Returns:
|
532
532
|
Code properties and circuits
|
533
533
|
|
@@ -566,9 +566,9 @@ class QuantumErrorCorrection:
|
|
566
566
|
}
|
567
567
|
|
568
568
|
@staticmethod
|
569
|
-
def steane_code() ->
|
569
|
+
def steane_code() -> dict[str, Any]:
|
570
570
|
"""7-qubit Steane code
|
571
|
-
|
571
|
+
|
572
572
|
Returns:
|
573
573
|
Code properties
|
574
574
|
|
@@ -598,13 +598,13 @@ class QuantumErrorCorrection:
|
|
598
598
|
}
|
599
599
|
|
600
600
|
@staticmethod
|
601
|
-
def decode_syndrome(syndrome: str, correction_table:
|
601
|
+
def decode_syndrome(syndrome: str, correction_table: dict[str, str]) -> str | None:
|
602
602
|
"""Decode error syndrome to determine correction
|
603
|
-
|
603
|
+
|
604
604
|
Args:
|
605
605
|
syndrome: Measured syndrome bitstring
|
606
606
|
correction_table: Syndrome to correction mapping
|
607
|
-
|
607
|
+
|
608
608
|
Returns:
|
609
609
|
Correction operation or None if no error
|
610
610
|
|
@@ -617,11 +617,11 @@ class QuantumErrorCorrection:
|
|
617
617
|
correction: str
|
618
618
|
) -> QuantumCircuit:
|
619
619
|
"""Apply error correction to circuit
|
620
|
-
|
620
|
+
|
621
621
|
Args:
|
622
622
|
circuit: Circuit to correct
|
623
623
|
correction: Correction operation (e.g., "X0", "Z2")
|
624
|
-
|
624
|
+
|
625
625
|
Returns:
|
626
626
|
Corrected circuit
|
627
627
|
|
@@ -653,15 +653,15 @@ class ErrorMitigation:
|
|
653
653
|
def randomized_compiling(
|
654
654
|
circuit: QuantumCircuit,
|
655
655
|
num_random_circuits: int = 10,
|
656
|
-
random_seed:
|
657
|
-
) ->
|
656
|
+
random_seed: int | None = None
|
657
|
+
) -> list[QuantumCircuit]:
|
658
658
|
"""Generate randomly compiled circuits for error mitigation
|
659
|
-
|
659
|
+
|
660
660
|
Args:
|
661
661
|
circuit: Original circuit
|
662
662
|
num_random_circuits: Number of random compilations
|
663
663
|
random_seed: Random seed for reproducibility
|
664
|
-
|
664
|
+
|
665
665
|
Returns:
|
666
666
|
List of randomly compiled circuits
|
667
667
|
|
@@ -679,7 +679,7 @@ class ErrorMitigation:
|
|
679
679
|
for gate in random_circuit.gates:
|
680
680
|
if len(gate.qubits) == 1:
|
681
681
|
# Add random Pauli before and after
|
682
|
-
|
682
|
+
gate.qubits[0]
|
683
683
|
|
684
684
|
# Random Pauli group element
|
685
685
|
pauli_choice = np.random.choice(['I', 'X', 'Y', 'Z'])
|
@@ -698,15 +698,15 @@ class ErrorMitigation:
|
|
698
698
|
|
699
699
|
@staticmethod
|
700
700
|
def clifford_data_regression(
|
701
|
-
noisy_results:
|
702
|
-
clifford_expectation_values:
|
701
|
+
noisy_results: list[float],
|
702
|
+
clifford_expectation_values: list[float]
|
703
703
|
) -> float:
|
704
704
|
"""Perform Clifford data regression for error mitigation
|
705
|
-
|
705
|
+
|
706
706
|
Args:
|
707
707
|
noisy_results: Noisy measurement results
|
708
708
|
clifford_expectation_values: Expected values from Clifford simulation
|
709
|
-
|
709
|
+
|
710
710
|
Returns:
|
711
711
|
Error-mitigated expectation value
|
712
712
|
|
@@ -734,14 +734,14 @@ class ErrorMitigation:
|
|
734
734
|
@staticmethod
|
735
735
|
def symmetry_verification(
|
736
736
|
circuit: QuantumCircuit,
|
737
|
-
symmetry_generators:
|
738
|
-
) ->
|
737
|
+
symmetry_generators: list[PauliString]
|
738
|
+
) -> dict[str, Any]:
|
739
739
|
"""Verify circuit preserves expected symmetries
|
740
|
-
|
740
|
+
|
741
741
|
Args:
|
742
742
|
circuit: Quantum circuit
|
743
743
|
symmetry_generators: List of Pauli symmetries to check
|
744
|
-
|
744
|
+
|
745
745
|
Returns:
|
746
746
|
Symmetry verification results
|
747
747
|
|
@@ -6,9 +6,10 @@ compare performance, and generate comprehensive performance reports.
|
|
6
6
|
|
7
7
|
import json
|
8
8
|
import time
|
9
|
+
from collections.abc import Callable
|
9
10
|
from dataclasses import dataclass
|
10
11
|
from pathlib import Path
|
11
|
-
from typing import Any
|
12
|
+
from typing import Any
|
12
13
|
|
13
14
|
import numpy as np
|
14
15
|
|
@@ -28,33 +29,33 @@ class BenchmarkResult:
|
|
28
29
|
backend_name: str
|
29
30
|
dataset_name: str
|
30
31
|
execution_time: float
|
31
|
-
memory_usage:
|
32
|
-
accuracy:
|
33
|
-
loss:
|
34
|
-
n_parameters:
|
35
|
-
n_qubits:
|
36
|
-
n_iterations:
|
32
|
+
memory_usage: float | None
|
33
|
+
accuracy: float | None
|
34
|
+
loss: float | None
|
35
|
+
n_parameters: int | None
|
36
|
+
n_qubits: int | None
|
37
|
+
n_iterations: int | None
|
37
38
|
success: bool
|
38
|
-
error_message:
|
39
|
-
metadata:
|
39
|
+
error_message: str | None
|
40
|
+
metadata: dict[str, Any]
|
40
41
|
|
41
42
|
|
42
43
|
def benchmark_algorithm(
|
43
44
|
algorithm: Any,
|
44
|
-
datasets:
|
45
|
-
metrics:
|
45
|
+
datasets: list[tuple[str, Any]],
|
46
|
+
metrics: list[str] | None = None,
|
46
47
|
n_runs: int = 1,
|
47
48
|
verbose: bool = True
|
48
|
-
) ->
|
49
|
+
) -> list[BenchmarkResult]:
|
49
50
|
"""Benchmark quantum algorithm performance across multiple datasets.
|
50
|
-
|
51
|
+
|
51
52
|
Args:
|
52
53
|
algorithm: Quantum algorithm instance
|
53
54
|
datasets: List of (name, dataset) tuples
|
54
55
|
metrics: List of metrics to compute
|
55
56
|
n_runs: Number of runs for averaging
|
56
57
|
verbose: Whether to print progress
|
57
|
-
|
58
|
+
|
58
59
|
Returns:
|
59
60
|
List of benchmark results
|
60
61
|
|
@@ -90,25 +91,27 @@ def benchmark_algorithm(
|
|
90
91
|
|
91
92
|
|
92
93
|
def benchmark_backend(
|
93
|
-
backends:
|
94
|
+
backends: list[Any],
|
94
95
|
test_circuit: Callable,
|
95
|
-
n_qubits_range:
|
96
|
+
n_qubits_range: list[int] = None,
|
96
97
|
n_shots: int = 1024,
|
97
98
|
verbose: bool = True
|
98
|
-
) ->
|
99
|
+
) -> dict[str, list[BenchmarkResult]]:
|
99
100
|
"""Benchmark different quantum backends.
|
100
|
-
|
101
|
+
|
101
102
|
Args:
|
102
103
|
backends: List of backend instances
|
103
104
|
test_circuit: Function that creates test circuit
|
104
105
|
n_qubits_range: Range of qubit numbers to test
|
105
106
|
n_shots: Number of shots for each measurement
|
106
107
|
verbose: Whether to print progress
|
107
|
-
|
108
|
+
|
108
109
|
Returns:
|
109
110
|
Dictionary mapping backend names to benchmark results
|
110
111
|
|
111
112
|
"""
|
113
|
+
if n_qubits_range is None:
|
114
|
+
n_qubits_range = [2, 4, 6, 8]
|
112
115
|
results = {}
|
113
116
|
|
114
117
|
for backend in backends:
|
@@ -180,14 +183,14 @@ def performance_metrics(
|
|
180
183
|
y_true: np.ndarray,
|
181
184
|
y_pred: np.ndarray,
|
182
185
|
task_type: str = 'classification'
|
183
|
-
) ->
|
186
|
+
) -> dict[str, float]:
|
184
187
|
"""Compute performance metrics for predictions.
|
185
|
-
|
188
|
+
|
186
189
|
Args:
|
187
190
|
y_true: True labels/values
|
188
191
|
y_pred: Predicted labels/values
|
189
192
|
task_type: Type of task ('classification' or 'regression')
|
190
|
-
|
193
|
+
|
191
194
|
Returns:
|
192
195
|
Dictionary of computed metrics
|
193
196
|
|
@@ -244,25 +247,27 @@ def performance_metrics(
|
|
244
247
|
|
245
248
|
|
246
249
|
def compare_algorithms(
|
247
|
-
algorithms:
|
250
|
+
algorithms: list[Any],
|
248
251
|
dataset: Any,
|
249
|
-
metrics:
|
252
|
+
metrics: list[str] = None,
|
250
253
|
n_runs: int = 3,
|
251
254
|
verbose: bool = True
|
252
|
-
) ->
|
255
|
+
) -> dict[str, Any]:
|
253
256
|
"""Compare multiple algorithms on the same dataset.
|
254
|
-
|
257
|
+
|
255
258
|
Args:
|
256
259
|
algorithms: List of algorithm instances
|
257
260
|
dataset: Dataset to use for comparison
|
258
261
|
metrics: Metrics to compare
|
259
262
|
n_runs: Number of runs for averaging
|
260
263
|
verbose: Whether to print progress
|
261
|
-
|
264
|
+
|
262
265
|
Returns:
|
263
266
|
Comparison results dictionary
|
264
267
|
|
265
268
|
"""
|
269
|
+
if metrics is None:
|
270
|
+
metrics = ['accuracy', 'execution_time']
|
266
271
|
comparison_results = {
|
267
272
|
'algorithms': [],
|
268
273
|
'metrics': metrics,
|
@@ -322,15 +327,15 @@ def compare_algorithms(
|
|
322
327
|
|
323
328
|
|
324
329
|
def generate_benchmark_report(
|
325
|
-
results:
|
326
|
-
output_path:
|
327
|
-
) ->
|
330
|
+
results: list[BenchmarkResult],
|
331
|
+
output_path: str | None = None
|
332
|
+
) -> dict[str, Any]:
|
328
333
|
"""Generate comprehensive benchmark report.
|
329
|
-
|
334
|
+
|
330
335
|
Args:
|
331
336
|
results: List of benchmark results
|
332
337
|
output_path: Optional path to save report
|
333
|
-
|
338
|
+
|
334
339
|
Returns:
|
335
340
|
Report dictionary
|
336
341
|
|
@@ -409,7 +414,7 @@ def _run_single_benchmark(
|
|
409
414
|
algorithm: Any,
|
410
415
|
dataset_name: str,
|
411
416
|
dataset: Any,
|
412
|
-
metrics:
|
417
|
+
metrics: list[str]
|
413
418
|
) -> BenchmarkResult:
|
414
419
|
"""Run single benchmark iteration."""
|
415
420
|
try:
|
@@ -483,7 +488,7 @@ def _run_single_benchmark(
|
|
483
488
|
return result
|
484
489
|
|
485
490
|
|
486
|
-
def _average_benchmark_results(results:
|
491
|
+
def _average_benchmark_results(results: list[BenchmarkResult]) -> BenchmarkResult:
|
487
492
|
"""Average multiple benchmark results."""
|
488
493
|
# Take the first result as template
|
489
494
|
template = results[0]
|
@@ -511,7 +516,7 @@ def _average_benchmark_results(results: List[BenchmarkResult]) -> BenchmarkResul
|
|
511
516
|
)
|
512
517
|
|
513
518
|
|
514
|
-
def _get_memory_usage() ->
|
519
|
+
def _get_memory_usage() -> float | None:
|
515
520
|
"""Get current memory usage in MB."""
|
516
521
|
if not HAS_PSUTIL:
|
517
522
|
return None
|
@@ -519,5 +524,5 @@ def _get_memory_usage() -> Optional[float]:
|
|
519
524
|
try:
|
520
525
|
process = psutil.Process()
|
521
526
|
return process.memory_info().rss / 1024 / 1024 # Convert to MB
|
522
|
-
except:
|
527
|
+
except (ImportError, AttributeError, Exception):
|
523
528
|
return None
|