Maestro 0.2.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
NetworkJob.h
Go to the documentation of this file.
1
10
11#pragma once
12
13#ifndef _NETWORK_JOB_H
14#define _NETWORK_JOB_H
15
16#include "../Types.h"
18
20
21#include "Network.h"
22
23namespace Network {
24
25template <typename Time = Types::time_type>
27 public:
29
30 ExecuteJob() = delete;
31
32 explicit ExecuteJob(const std::shared_ptr<Circuits::Circuit<Time>> &c,
33 ExecuteResults &r, size_t cnt, size_t nq, size_t nc,
34 size_t ncr, Simulators::SimulatorType t,
35 Simulators::SimulationType m, std::mutex &mut)
36 : dcirc(c),
37 res(r),
38 curCnt(cnt),
39 nrQubits(nq),
40 nrCbits(nc),
41 nrResultCbits(ncr),
42 simType(t),
43 method(m),
44 resultsMutex(mut) {}
45
46 void DoWork() {
47 if (curCnt == 0) return;
48
50 state.AllocateBits(nrCbits);
51
52 const bool hasMeasurementsOnlyAtEnd = !dcirc->HasOpsAfterMeasurements();
53 const bool optimiseMultipleShots = optimiseMultipleShotsExecution;
54 const bool specialOptimizationForStatevector =
55 optimiseMultipleShots &&
57 hasMeasurementsOnlyAtEnd;
58 const bool specialOptimizationForMPS =
59 optimiseMultipleShots &&
61 hasMeasurementsOnlyAtEnd;
62
63 dcirc = dcirc->RemoveExecutedOperations(executedGates);
64
65 if (!optSim) {
67 if (!optSim) return;
68
69 if (!maxBondDim.empty())
70 optSim->Configure("matrix_product_state_max_bond_dimension",
71 maxBondDim.c_str());
72 if (!singularValueThreshold.empty())
73 optSim->Configure("matrix_product_state_truncation_threshold",
75 if (!mpsSample.empty())
76 optSim->Configure("mps_sample_measure_algorithm", mpsSample.c_str());
77
78 optSim->AllocateQubits(nrQubits);
79 optSim->Initialize();
80
81 OptimizeMPSInitialQubitsMap(optSim, dcirc, nrQubits);
82
83 if (optimiseMultipleShots) {
84 executedGates = dcirc->ExecuteNonMeasurements(optSim, state);
85
86 if (!specialOptimizationForStatevector && !specialOptimizationForMPS &&
87 curCnt > 1)
88 optSim->SaveState();
89
90 dcirc = dcirc->RemoveExecutedOperations(executedGates);
92 network->GetMPSOptimizeSwaps())
93 optSim->SetUpcomingGates(dcirc->GetOperations());
94 }
95 } else if (method == Simulators::SimulationType::kMatrixProductState && network->GetMPSOptimizeSwaps())
96 optSim->SetUpcomingGates(dcirc->GetOperations());
97
98 std::shared_ptr<Circuits::MeasurementOperation<Time>> measurementsOp;
99
100 const std::vector<bool> executed = std::move(executedGates);
101
102 if (optimiseMultipleShots && hasMeasurementsOnlyAtEnd) {
103 bool isQiskitAer = false;
104#ifndef NO_QISKIT_AER
106 isQiskitAer = true;
107 }
108#endif
109 measurementsOp = dcirc->GetLastMeasurements(executed, isQiskitAer);
110 const auto &qbits = measurementsOp->GetQubits();
111 if (qbits.empty()) {
112 auto bits = state.GetAllBits();
113 bits.resize(nrResultCbits, false);
114
115 const std::lock_guard lock(resultsMutex);
116 res[bits] += curCnt;
117
118 return;
119 }
120 }
121
122 ExecuteResults localRes;
123
124 if (optimiseMultipleShots &&
125 (specialOptimizationForStatevector || hasMeasurementsOnlyAtEnd)) {
126 const auto &qbits = measurementsOp->GetQubits();
127
128 const auto sampleres = optSim->SampleCountsMany(qbits, curCnt);
129
130 for (const auto &[mstate, cnt] : sampleres) {
131 measurementsOp->SetStateFromSample(mstate, state);
132
133 auto bits = state.GetAllBits();
134 bits.resize(nrResultCbits, false);
135
136 localRes[bits] += cnt;
137
138 state.Reset();
139 }
140
141 const std::lock_guard lock(resultsMutex);
142 for (const auto &r : localRes) res[r.first] += r.second;
143
144 return;
145 }
146
147 const auto curCnt1 = curCnt > 0 ? curCnt - 1 : 0;
148 for (size_t i = 0; i < curCnt; ++i) {
149 if (optimiseMultipleShots) {
150 if (i > 0) {
151 optSim->RestoreState();
152 optSim->SetGatesCounter(0);
153 }
154 dcirc->ExecuteMeasurements(optSim, state, executed);
155 } else {
156 dcirc->Execute(optSim, state);
157 if (i < curCnt1) {
158 optSim->Reset();
159 optSim->SetGatesCounter(0);
160 }
161 }
162
163 auto bits = state.GetAllBits();
164 bits.resize(nrResultCbits, false);
165
166 ++localRes[bits];
167
168 state.Reset();
169 }
170
171 const std::lock_guard lock(resultsMutex);
172 for (const auto &r : localRes) res[r.first] += r.second;
173 }
174
176 if (curCnt == 0) return;
177
179 state.AllocateBits(nrCbits);
180
181 const bool hasMeasurementsOnlyAtEnd = !dcirc->HasOpsAfterMeasurements();
182 const bool optimiseMultipleShots = optimiseMultipleShotsExecution;
183 const bool specialOptimizationForStatevector =
184 optimiseMultipleShots &&
186 hasMeasurementsOnlyAtEnd;
187 const bool specialOptimizationForMPS =
188 optimiseMultipleShots &&
190 hasMeasurementsOnlyAtEnd;
191
192
193 if (optSim) {
194 optSim->SetMultithreading(true);
195
196 if (optSim->GetNumberOfQubits() != nrQubits) {
197 optSim->Clear();
198
199 if (!maxBondDim.empty())
200 optSim->Configure("matrix_product_state_max_bond_dimension",
201 maxBondDim.c_str());
202 if (!singularValueThreshold.empty())
203 optSim->Configure("matrix_product_state_truncation_threshold",
204 singularValueThreshold.c_str());
205 if (!mpsSample.empty())
206 optSim->Configure("mps_sample_measure_algorithm", mpsSample.c_str());
207
208 optSim->AllocateQubits(nrQubits);
209 optSim->Initialize();
210
211 OptimizeMPSInitialQubitsMap(optSim, dcirc, nrQubits);
212
213 if (optimiseMultipleShots) {
214 executedGates = dcirc->ExecuteNonMeasurements(optSim, state);
215
216 if (!specialOptimizationForStatevector &&
217 !specialOptimizationForMPS && curCnt > 1)
218 optSim->SaveState();
219 dcirc = dcirc->RemoveExecutedOperations(executedGates);
221 network->GetMPSOptimizeSwaps())
222 optSim->SetUpcomingGates(dcirc->GetOperations());
223 }
224 } else if (executedGates.size() == dcirc->size()) {
225 // special case for when the simulator is passed from the network
226 // and no gates were executed yet
227 bool needToExecuteGates = true;
228 for (const bool val : executedGates) {
229 if (val) {
230 needToExecuteGates = false;
231 break;
232 }
233 }
234 if (needToExecuteGates && optimiseMultipleShots) {
235 executedGates = dcirc->ExecuteNonMeasurements(optSim, state);
236 if (!specialOptimizationForStatevector &&
237 !specialOptimizationForMPS && curCnt > 1)
238 optSim->SaveState();
239 dcirc = dcirc->RemoveExecutedOperations(executedGates);
241 network->GetMPSOptimizeSwaps())
242 optSim->SetUpcomingGates(dcirc->GetOperations());
243 } else {
244 dcirc = dcirc->RemoveExecutedOperations(executedGates);
246 network->GetMPSOptimizeSwaps())
247 optSim->SetUpcomingGates(dcirc->GetOperations());
248 }
249 } else {
250 dcirc = dcirc->RemoveExecutedOperations(executedGates);
252 network->GetMPSOptimizeSwaps())
253 optSim->SetUpcomingGates(dcirc->GetOperations());
254 }
255 } else {
257 if (!optSim) return;
258
259 optSim->SetMultithreading(true);
260
261 if (!maxBondDim.empty())
262 optSim->Configure("matrix_product_state_max_bond_dimension",
263 maxBondDim.c_str());
264 if (!singularValueThreshold.empty())
265 optSim->Configure("matrix_product_state_truncation_threshold",
266 singularValueThreshold.c_str());
267 if (!mpsSample.empty())
268 optSim->Configure("mps_sample_measure_algorithm", mpsSample.c_str());
269
270 optSim->AllocateQubits(nrQubits);
271 optSim->Initialize();
272
273 OptimizeMPSInitialQubitsMap(optSim, dcirc, nrQubits);
274
275 if (optimiseMultipleShots) {
276 executedGates = dcirc->ExecuteNonMeasurements(optSim, state);
277
278 if (!specialOptimizationForStatevector && !specialOptimizationForMPS &&
279 curCnt > 1)
280 optSim->SaveState();
281
282 dcirc = dcirc->RemoveExecutedOperations(executedGates);
283 if (method == Simulators::SimulationType::kMatrixProductState && network->GetMPSOptimizeSwaps())
284 optSim->SetUpcomingGates(dcirc->GetOperations());
285 }
286 }
287
288 std::shared_ptr<Circuits::MeasurementOperation<Time>> measurementsOp;
289
290 const std::vector<bool> executed = std::move(executedGates);
291
292 if (optimiseMultipleShots && hasMeasurementsOnlyAtEnd) {
293 bool isQiskitAer = false;
294#ifndef NO_QISKIT_AER
296 isQiskitAer = true;
297 }
298#endif
299 measurementsOp = dcirc->GetLastMeasurements(executed, isQiskitAer);
300 const auto &qbits = measurementsOp->GetQubits();
301 if (qbits.empty()) {
302 auto bits = state.GetAllBits();
303 bits.resize(nrResultCbits, false);
304
305 res[bits] += curCnt;
306
307 return;
308 }
309 }
310
311 if (optimiseMultipleShots &&
312 (specialOptimizationForStatevector || hasMeasurementsOnlyAtEnd)) {
313 const auto &qbits = measurementsOp->GetQubits();
314
315 const auto sampleres = optSim->SampleCountsMany(qbits, curCnt);
316
317 for (const auto &[mstate, cnt] : sampleres) {
318 measurementsOp->SetStateFromSample(mstate, state);
319
320 auto bits = state.GetAllBits();
321 bits.resize(nrResultCbits, false);
322
323 res[bits] += cnt;
324
325 state.Reset();
326 }
327
328 return;
329 }
330
331 const auto curCnt1 = curCnt > 0 ? curCnt - 1 : 0;
332 for (size_t i = 0; i < curCnt; ++i) {
333 if (optimiseMultipleShots) {
334 if (i > 0) {
335 optSim->RestoreState();
336 optSim->SetGatesCounter(0);
337 }
338 dcirc->ExecuteMeasurements(optSim, state, executed);
339 } else {
340 dcirc->Execute(optSim, state);
341 if (i < curCnt1) {
342 optSim->Reset(); // leave the simulator state for the last iteration
343 optSim->SetGatesCounter(0);
344 }
345 }
346
347 auto bits = state.GetAllBits();
348 bits.resize(nrResultCbits, false);
349
350 ++res[bits];
351
352 state.Reset();
353 }
354 }
355
357 size_t curCnt) {
358 return curCnt > 1;
359 }
360
361 size_t GetJobCount() const { return curCnt; }
362
363private:
364 void OptimizeMPSInitialQubitsMap(
365 std::shared_ptr<Simulators::ISimulator> &sim,
366 std::shared_ptr<Circuits::Circuit<Time>> &dcirc, size_t nrQubits) const {
367 if (sim->GetSimulationType() ==
369 (network->GetInitialQubitsMapOptimization() ||
370 network->GetMPSOptimizeSwaps()) &&
371 sim->SupportsMPSSwapOptimization()) {
372 if (network->GetMPSOptimizationQubitsNumberThreshold() <= nrQubits) {
373 const auto bondDimThreshold =
374 network->GetMPSOptimizationBondDimensionThreshold();
375 const auto maxBondDimValue =
376 maxBondDim.empty() ? 0 : std::stoi(maxBondDim);
377
378 if (maxBondDim.empty() || static_cast<int>(bondDimThreshold) <= maxBondDimValue) {
379 // need to be sure the circuit is correctly converted
380 dcirc->ConvertForCutting(); // convert the three qubit gates
381 auto layers = dcirc->ToMultipleQubitsLayersNoClone();
382
384 dummySim.setGrowthFactorGate(network->getGrowthFactorGate());
385 dummySim.setGrowthFactorSwap(network->getGrowthFactorSwap());
386 if (!maxBondDim.empty())
387 dummySim.SetMaxBondDimension(maxBondDimValue);
388
389 if (network->GetInitialQubitsMapOptimization()) {
390 const auto optimalMap = dummySim.ComputeOptimalQubitsMap(layers);
391 sim->SetInitialQubitsMap(optimalMap);
392 }
393
395
396 if (network->GetMPSOptimizeSwaps()) {
397 // TODO: come up with something better!
398 int lookaheadDepthLocal = network->GetLookaheadDepth();
399
400 if (lookaheadDepthLocal == std::numeric_limits<int>::max()) {
401 double avgTwoQubitGatesPerLayer = 0.0;
402 for (const auto &layer : layers) {
403 int twoQubitGates = 0;
404 for (const auto &op : layer->GetOperations()) {
405 if (op->AffectedQubits().size() >= 2) {
406 ++twoQubitGates;
407 }
408 }
409 avgTwoQubitGatesPerLayer += twoQubitGates;
410 }
411 avgTwoQubitGatesPerLayer /= layers.size();
412
413 int lookaheadVal =
414 static_cast<int>(4. * avgTwoQubitGatesPerLayer);
415 if (lookaheadVal > 15) lookaheadVal = 15;
416
417 lookaheadDepthLocal = layers.size() < 10 || nrQubits <= 10 ? 0
418 : layers.size() < 20
419 ? static_cast<int>(lookaheadVal)
420 : layers.size() < 35 ? 1.5 * lookaheadVal
421 : 2 * lookaheadVal;
422 }
423
424 int lookaheadHeuristicDepthLocal =
425 network->GetLookaheadDepthWithHeuristic();
426
427 if (lookaheadHeuristicDepthLocal == std::numeric_limits<int>::max())
428 lookaheadHeuristicDepthLocal =
429 layers.size() < 10 || nrQubits <= 10 ? 0
430 : layers.size() < 20
431 ? lookaheadDepthLocal - 1
432 : lookaheadDepthLocal - 2;
433
434 sim->SetUseOptimalMeetingPosition(true);
435 sim->SetLookaheadDepth(lookaheadDepthLocal);
436 sim->SetLookaheadDepthWithHeuristic(lookaheadHeuristicDepthLocal);
437 sim->setGrowthFactorGate(network->getGrowthFactorGate());
438 sim->setGrowthFactorSwap(network->getGrowthFactorSwap());
439 sim->SetUpcomingGates(dcirc->GetOperations());
440 }
441 }
442 }
443 }
444 }
445
446public:
447 std::shared_ptr<Circuits::Circuit<Time>> dcirc;
449 const size_t curCnt;
450 const size_t nrQubits;
451 const size_t nrCbits;
452 const size_t nrResultCbits;
453
456 std::mutex &resultsMutex;
457
459 std::shared_ptr<Simulators::ISimulator> optSim;
460 std::vector<bool> executedGates;
461
462 // only fill them if passing null simulator
463 std::string maxBondDim;
465 std::string mpsSample;
466
467 std::shared_ptr<Network::INetwork<Time>> network;
468};
469
470} // namespace Network
471
472#endif // ! _NETWORK_JOB_H
Circuit class for holding the sequence of operations.
Definition Circuit.h:46
std::unordered_map< std::vector< bool >, size_t > ExecuteResults
The results of the execution of the circuit.
Definition Circuit.h:48
static std::shared_ptr< Circuits::Circuit< Time > > LayersToCircuit(const std::vector< std::shared_ptr< Circuits::Circuit< Time > > > &layers)
Converts the layers back to a circuit.
Definition Circuit.h:2417
The state class that stores the classical state of a quantum circuit execution.
Definition Operations.h:63
void Reset(bool value=false)
Set the classical bits with the specified value.
Definition Operations.h:244
const std::vector< bool > & GetAllBits() const
Get the classical bits.
Definition Operations.h:214
void AllocateBits(size_t numBits)
Allocate more bits.
Definition Operations.h:160
ExecuteResults & res
Definition NetworkJob.h:448
bool optimiseMultipleShotsExecution
Definition NetworkJob.h:458
static bool IsOptimisableForMultipleShots(Simulators::SimulatorType t, size_t curCnt)
Definition NetworkJob.h:356
const Simulators::SimulatorType simType
Definition NetworkJob.h:454
std::string maxBondDim
Definition NetworkJob.h:463
const size_t curCnt
Definition NetworkJob.h:449
std::vector< bool > executedGates
Definition NetworkJob.h:460
typename Circuits::Circuit< Time >::ExecuteResults ExecuteResults
Definition NetworkJob.h:28
std::shared_ptr< Network::INetwork< Time > > network
Definition NetworkJob.h:467
const size_t nrResultCbits
Definition NetworkJob.h:452
const size_t nrCbits
Definition NetworkJob.h:451
ExecuteJob(const std::shared_ptr< Circuits::Circuit< Time > > &c, ExecuteResults &r, size_t cnt, size_t nq, size_t nc, size_t ncr, Simulators::SimulatorType t, Simulators::SimulationType m, std::mutex &mut)
Definition NetworkJob.h:32
std::shared_ptr< Simulators::ISimulator > optSim
Definition NetworkJob.h:459
std::shared_ptr< Circuits::Circuit< Time > > dcirc
Definition NetworkJob.h:447
std::mutex & resultsMutex
Definition NetworkJob.h:456
const size_t nrQubits
Definition NetworkJob.h:450
std::string mpsSample
Definition NetworkJob.h:465
const Simulators::SimulationType method
Definition NetworkJob.h:455
std::string singularValueThreshold
Definition NetworkJob.h:464
size_t GetJobCount() const
Definition NetworkJob.h:361
static std::shared_ptr< ISimulator > CreateSimulator(SimulatorType t=SimulatorType::kQCSim, SimulationType method=SimulationType::kMatrixProductState)
Create a quantum computing simulator.
Definition Factory.cpp:101
SimulationType
The type of simulation.
Definition State.h:85
@ kStatevector
statevector simulation type
Definition State.h:86
@ kMatrixProductState
matrix product state simulation type
Definition State.h:87
SimulatorType
The type of simulator.
Definition State.h:68
@ kQiskitAer
qiskit aer simulator type
Definition State.h:70