qoro-divi 0.3.4__tar.gz → 0.3.5__tar.gz
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.
Potentially problematic release.
This version of qoro-divi might be problematic. Click here for more details.
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/PKG-INFO +2 -1
- qoro_divi-0.3.5/divi/backends/_circuit_runner.py +46 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/backends/_parallel_simulator.py +132 -50
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/backends/_qoro_service.py +239 -132
- qoro_divi-0.3.5/divi/circuits/_core.py +226 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/circuits/qasm.py +19 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/qprog/algorithms/_ansatze.py +96 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/qprog/algorithms/_qaoa.py +68 -40
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/qprog/algorithms/_vqe.py +51 -8
- qoro_divi-0.3.5/divi/qprog/batch.py +474 -0
- qoro_divi-0.3.5/divi/qprog/exceptions.py +9 -0
- qoro_divi-0.3.5/divi/qprog/optimizers.py +402 -0
- qoro_divi-0.3.5/divi/qprog/quantum_program.py +759 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/qprog/workflows/_graph_partitioning.py +1 -32
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/qprog/workflows/_qubo_partitioning.py +40 -23
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/qprog/workflows/_vqe_sweep.py +30 -9
- qoro_divi-0.3.5/divi/reporting/_pbar.py +112 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/reporting/_qlogger.py +35 -1
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/reporting/_reporter.py +8 -14
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/utils.py +35 -4
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/pyproject.toml +2 -1
- qoro_divi-0.3.4/divi/backends/_circuit_runner.py +0 -25
- qoro_divi-0.3.4/divi/circuits/_core.py +0 -125
- qoro_divi-0.3.4/divi/qprog/batch.py +0 -288
- qoro_divi-0.3.4/divi/qprog/optimizers.py +0 -200
- qoro_divi-0.3.4/divi/qprog/quantum_program.py +0 -434
- qoro_divi-0.3.4/divi/reporting/_pbar.py +0 -70
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/LICENSE +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/LICENSES/.license-header +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/LICENSES/Apache-2.0.txt +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/README.md +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/__init__.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/backends/__init__.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/backends/_qpu_system.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/circuits/__init__.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/circuits/qem.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/cirq/__init__.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/cirq/_lexer.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/cirq/_parser.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/cirq/_qasm_export.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/cirq/_qasm_import.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/cirq/_validator.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/cirq/exception.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/_cobyla.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/LICENCE.txt +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/__init__.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/cobyla/__init__.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/cobyla/cobyla.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/cobyla/cobylb.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/cobyla/geometry.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/cobyla/initialize.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/cobyla/trustregion.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/cobyla/update.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/__init__.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/_bounds.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/_linear_constraints.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/_nonlinear_constraints.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/_project.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/checkbreak.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/consts.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/evaluate.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/history.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/infos.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/linalg.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/message.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/powalg.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/preproc.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/present.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/ratio.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/redrho.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/extern/scipy/pyprima/common/selectx.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/qprog/__init__.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/qprog/algorithms/__init__.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/qprog/workflows/__init__.py +0 -0
- {qoro_divi-0.3.4 → qoro_divi-0.3.5}/divi/reporting/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: qoro-divi
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.5
|
|
4
4
|
Summary: A Python library to automate generating, parallelizing, and executing quantum programs.
|
|
5
5
|
Author: Ahmed Darwish
|
|
6
6
|
Author-email: ahmed@qoroquantum.de
|
|
@@ -17,6 +17,7 @@ Requires-Dist: networkx (>=3.5,<4.0)
|
|
|
17
17
|
Requires-Dist: pennylane (>=0.42.3,<0.43.0)
|
|
18
18
|
Requires-Dist: ply (>=3.11,<4.0)
|
|
19
19
|
Requires-Dist: pymetis (>=2025.1.1,<2026.0.0)
|
|
20
|
+
Requires-Dist: pymoo (>=0.6.1.5,<0.7.0.0)
|
|
20
21
|
Requires-Dist: python-dotenv (>=1.1.1,<2.0.0)
|
|
21
22
|
Requires-Dist: qiskit (<2.0)
|
|
22
23
|
Requires-Dist: qiskit-aer (>=0.17.1,<0.18.0)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2025 Qoro Quantum Ltd <divi@qoroquantum.de>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CircuitRunner(ABC):
|
|
9
|
+
"""
|
|
10
|
+
A generic interface for anything that can "run" quantum circuits.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, shots: int):
|
|
14
|
+
if shots <= 0:
|
|
15
|
+
raise ValueError(f"Shots must be a positive integer. Got {shots}.")
|
|
16
|
+
|
|
17
|
+
self._shots = shots
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def shots(self):
|
|
21
|
+
"""
|
|
22
|
+
Get the number of measurement shots for circuit execution.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
int: Number of shots configured for this runner.
|
|
26
|
+
"""
|
|
27
|
+
return self._shots
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def submit_circuits(self, circuits: dict[str, str], **kwargs):
|
|
31
|
+
"""
|
|
32
|
+
Submit quantum circuits for execution.
|
|
33
|
+
|
|
34
|
+
This abstract method must be implemented by subclasses to define how
|
|
35
|
+
circuits are executed on their respective backends (simulator, hardware, etc.).
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
circuits (dict[str, str]): Dictionary mapping circuit labels to their
|
|
39
|
+
OpenQASM string representations.
|
|
40
|
+
**kwargs: Additional backend-specific parameters for circuit execution.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
The return type depends on the backend implementation. Typically returns
|
|
44
|
+
measurement results or a job identifier.
|
|
45
|
+
"""
|
|
46
|
+
pass
|
|
@@ -66,12 +66,15 @@ class ParallelSimulator(CircuitRunner):
|
|
|
66
66
|
simulation_seed: int | None = None,
|
|
67
67
|
qiskit_backend: Backend | Literal["auto"] | None = None,
|
|
68
68
|
noise_model: NoiseModel | None = None,
|
|
69
|
+
_deterministic_execution: bool = False,
|
|
69
70
|
):
|
|
70
71
|
"""
|
|
71
|
-
A
|
|
72
|
+
A parallel wrapper around Qiskit's AerSimulator using Qiskit's built-in parallelism.
|
|
72
73
|
|
|
73
74
|
Args:
|
|
74
|
-
n_processes (int, optional): Number of parallel processes to use for
|
|
75
|
+
n_processes (int, optional): Number of parallel processes to use for transpilation and
|
|
76
|
+
simulation. Defaults to 2. This sets both the transpile num_processes and
|
|
77
|
+
AerSimulator's max_parallel_experiments.
|
|
75
78
|
shots (int, optional): Number of shots to perform. Defaults to 5000.
|
|
76
79
|
simulation_seed (int, optional): Seed for the random number generator to ensure reproducibility. Defaults to None.
|
|
77
80
|
qiskit_backend (Backend | Literal["auto"] | None, optional): A Qiskit backend to initiate the simulator from.
|
|
@@ -92,62 +95,138 @@ class ParallelSimulator(CircuitRunner):
|
|
|
92
95
|
self.simulation_seed = simulation_seed
|
|
93
96
|
self.qiskit_backend = qiskit_backend
|
|
94
97
|
self.noise_model = noise_model
|
|
98
|
+
self._deterministic_execution = _deterministic_execution
|
|
95
99
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
shots: int,
|
|
100
|
-
simulation_seed: int | None = None,
|
|
101
|
-
qiskit_backend: Backend | None = None,
|
|
102
|
-
noise_model: NoiseModel | None = None,
|
|
103
|
-
):
|
|
104
|
-
circuit_label, circuit = circuit_data
|
|
105
|
-
|
|
106
|
-
qiskit_circuit = QuantumCircuit.from_qasm_str(circuit)
|
|
100
|
+
def set_seed(self, seed: int):
|
|
101
|
+
"""
|
|
102
|
+
Set the random seed for circuit simulation.
|
|
107
103
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
)
|
|
104
|
+
Args:
|
|
105
|
+
seed (int): Seed value for the random number generator used in simulation.
|
|
106
|
+
"""
|
|
107
|
+
self.simulation_seed = seed
|
|
113
108
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
transpiled_circuit = transpile(qiskit_circuit, aer_simulator)
|
|
109
|
+
def _execute_circuits_deterministically(
|
|
110
|
+
self, circuit_labels: list[str], transpiled_circuits: list, resolved_backend
|
|
111
|
+
) -> list[dict]:
|
|
112
|
+
"""
|
|
113
|
+
Execute circuits individually for debugging purposes.
|
|
120
114
|
|
|
121
|
-
|
|
122
|
-
|
|
115
|
+
This method ensures deterministic results by running each circuit with its own
|
|
116
|
+
simulator instance and the same seed. Used internally for debugging non-deterministic
|
|
117
|
+
behavior in batch execution.
|
|
123
118
|
|
|
124
|
-
|
|
125
|
-
|
|
119
|
+
Args:
|
|
120
|
+
circuit_labels: List of circuit labels
|
|
121
|
+
transpiled_circuits: List of transpiled QuantumCircuit objects
|
|
122
|
+
resolved_backend: Resolved backend for simulator creation
|
|
126
123
|
|
|
127
|
-
|
|
124
|
+
Returns:
|
|
125
|
+
List of result dictionaries
|
|
126
|
+
"""
|
|
127
|
+
results = []
|
|
128
|
+
for i, (label, transpiled_circuit) in enumerate(
|
|
129
|
+
zip(circuit_labels, transpiled_circuits)
|
|
130
|
+
):
|
|
131
|
+
# Create a new simulator instance for each circuit with the same seed
|
|
132
|
+
if resolved_backend is not None:
|
|
133
|
+
circuit_simulator = AerSimulator.from_backend(resolved_backend)
|
|
134
|
+
else:
|
|
135
|
+
circuit_simulator = AerSimulator(noise_model=self.noise_model)
|
|
136
|
+
|
|
137
|
+
if self.simulation_seed is not None:
|
|
138
|
+
circuit_simulator.set_option("seed_simulator", self.simulation_seed)
|
|
139
|
+
|
|
140
|
+
# Run the single circuit
|
|
141
|
+
job = circuit_simulator.run(transpiled_circuit, shots=self.shots)
|
|
142
|
+
circuit_result = job.result()
|
|
143
|
+
counts = circuit_result.get_counts(0)
|
|
144
|
+
results.append({"label": label, "results": dict(counts)})
|
|
128
145
|
|
|
129
|
-
|
|
130
|
-
self.simulation_seed = seed
|
|
146
|
+
return results
|
|
131
147
|
|
|
132
148
|
def submit_circuits(self, circuits: dict[str, str]):
|
|
149
|
+
"""
|
|
150
|
+
Submit multiple circuits for parallel simulation using Qiskit's built-in parallelism.
|
|
151
|
+
|
|
152
|
+
Uses Qiskit's native batch transpilation and execution, which handles parallelism
|
|
153
|
+
internally.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
circuits (dict[str, str]): Dictionary mapping circuit labels to OpenQASM
|
|
157
|
+
string representations.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
list[dict]: List of result dictionaries, each containing:
|
|
161
|
+
- 'label' (str): Circuit identifier
|
|
162
|
+
- 'results' (dict): Measurement counts as {bitstring: count}
|
|
163
|
+
"""
|
|
133
164
|
logger.debug(
|
|
134
165
|
f"Simulating {len(circuits)} circuits with {self.n_processes} processes"
|
|
135
166
|
)
|
|
136
167
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
168
|
+
# Convert QASM strings to QuantumCircuit objects
|
|
169
|
+
circuit_labels = list(circuits.keys())
|
|
170
|
+
qiskit_circuits = [
|
|
171
|
+
QuantumCircuit.from_qasm_str(qasm) for qasm in circuits.values()
|
|
172
|
+
]
|
|
173
|
+
|
|
174
|
+
# Determine backend for transpilation
|
|
175
|
+
if self.qiskit_backend == "auto":
|
|
176
|
+
# For "auto", find the maximum number of qubits across all circuits to determine backend
|
|
177
|
+
max_qubits_circ = max(qiskit_circuits, key=lambda x: x.num_qubits)
|
|
178
|
+
resolved_backend = _find_best_fake_backend(max_qubits_circ)[-1]()
|
|
179
|
+
elif self.qiskit_backend is not None:
|
|
180
|
+
resolved_backend = self.qiskit_backend
|
|
181
|
+
else:
|
|
182
|
+
resolved_backend = None
|
|
183
|
+
|
|
184
|
+
# Create simulator
|
|
185
|
+
if resolved_backend is not None:
|
|
186
|
+
aer_simulator = AerSimulator.from_backend(resolved_backend)
|
|
187
|
+
else:
|
|
188
|
+
aer_simulator = AerSimulator(noise_model=self.noise_model)
|
|
189
|
+
|
|
190
|
+
# Set simulator options for parallelism
|
|
191
|
+
# Note: We don't set seed_simulator here because we need different seeds for each circuit
|
|
192
|
+
# to ensure deterministic results when running multiple circuits in parallel
|
|
193
|
+
aer_simulator.set_options(max_parallel_experiments=self.n_processes)
|
|
194
|
+
|
|
195
|
+
# Batch transpile all circuits (Qiskit handles parallelism internally)
|
|
196
|
+
transpiled_circuits = transpile(
|
|
197
|
+
qiskit_circuits, aer_simulator, num_processes=self.n_processes
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Use deterministic execution for debugging if enabled
|
|
201
|
+
if self._deterministic_execution:
|
|
202
|
+
return self._execute_circuits_deterministically(
|
|
203
|
+
circuit_labels, transpiled_circuits, resolved_backend
|
|
150
204
|
)
|
|
205
|
+
|
|
206
|
+
# Batch execution with metadata checking for non-deterministic behavior
|
|
207
|
+
job = aer_simulator.run(transpiled_circuits, shots=self.shots)
|
|
208
|
+
batch_result = job.result()
|
|
209
|
+
|
|
210
|
+
# Check metadata to detect non-deterministic behavior
|
|
211
|
+
metadata = batch_result.metadata
|
|
212
|
+
parallel_experiments = metadata.get("parallel_experiments", 1)
|
|
213
|
+
omp_nested = metadata.get("omp_nested", False)
|
|
214
|
+
|
|
215
|
+
# If parallel execution is detected and we have a seed, warn about potential non-determinism
|
|
216
|
+
if parallel_experiments > 1 and self.simulation_seed is not None:
|
|
217
|
+
logger.warning(
|
|
218
|
+
f"Parallel execution detected (parallel_experiments={parallel_experiments}, "
|
|
219
|
+
f"omp_nested={omp_nested}). Results may not be deterministic across different "
|
|
220
|
+
"grouping strategies. Consider enabling deterministic mode for "
|
|
221
|
+
"deterministic results."
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
# Extract results and match with labels
|
|
225
|
+
results = []
|
|
226
|
+
for i, label in enumerate(circuit_labels):
|
|
227
|
+
counts = batch_result.get_counts(i)
|
|
228
|
+
results.append({"label": label, "results": dict(counts)})
|
|
229
|
+
|
|
151
230
|
return results
|
|
152
231
|
|
|
153
232
|
@staticmethod
|
|
@@ -187,15 +266,18 @@ class ParallelSimulator(CircuitRunner):
|
|
|
187
266
|
|
|
188
267
|
op_name = node.name
|
|
189
268
|
|
|
269
|
+
# Determine qubit indices for the operation
|
|
190
270
|
if node.num_clbits == 1:
|
|
191
271
|
idx = (node.cargs[0]._index,)
|
|
192
|
-
|
|
193
|
-
if op_name != "measure" and node.num_qubits > 0:
|
|
272
|
+
elif op_name != "measure" and node.num_qubits > 0:
|
|
194
273
|
idx = tuple(qarg._index for qarg in node.qargs)
|
|
274
|
+
else:
|
|
275
|
+
# Skip operations without qubits or measurements without classical bits
|
|
276
|
+
continue
|
|
195
277
|
|
|
196
278
|
try:
|
|
197
279
|
total_run_time_s += (
|
|
198
|
-
|
|
280
|
+
resolved_backend.instruction_durations.duration_by_name_qubits[
|
|
199
281
|
(op_name, idx)
|
|
200
282
|
][0]
|
|
201
283
|
)
|
|
@@ -209,7 +291,7 @@ class ParallelSimulator(CircuitRunner):
|
|
|
209
291
|
@staticmethod
|
|
210
292
|
def estimate_run_time_batch(
|
|
211
293
|
circuits: list[str] | None = None,
|
|
212
|
-
|
|
294
|
+
precomputed_durations: list[float] | None = None,
|
|
213
295
|
n_qpus: int = 5,
|
|
214
296
|
**transpilation_kwargs,
|
|
215
297
|
) -> float:
|
|
@@ -226,7 +308,7 @@ class ParallelSimulator(CircuitRunner):
|
|
|
226
308
|
"""
|
|
227
309
|
|
|
228
310
|
# Compute the run time estimates for each given circuit, in descending order
|
|
229
|
-
if
|
|
311
|
+
if precomputed_durations is None:
|
|
230
312
|
with Pool() as p:
|
|
231
313
|
estimated_run_times = p.map(
|
|
232
314
|
partial(
|
|
@@ -238,7 +320,7 @@ class ParallelSimulator(CircuitRunner):
|
|
|
238
320
|
)
|
|
239
321
|
estimated_run_times_sorted = sorted(estimated_run_times, reverse=True)
|
|
240
322
|
else:
|
|
241
|
-
estimated_run_times_sorted = sorted(
|
|
323
|
+
estimated_run_times_sorted = sorted(precomputed_durations, reverse=True)
|
|
242
324
|
|
|
243
325
|
# Just return the longest run time if there are enough QPUs
|
|
244
326
|
if n_qpus >= len(estimated_run_times_sorted):
|