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 //auto circ = std::static_pointer_cast<Circuits::Circuit<Time>>(dcirc->Clone());
94 //circ->ConvertForCutting();
95 optSim->SetUpcomingGates(dcirc->GetOperations());
96 }
97 }
98 } else if (method == Simulators::SimulationType::kMatrixProductState && network->GetMPSOptimizeSwaps()) {
99 auto circ =
100 std::static_pointer_cast<Circuits::Circuit<Time>>(dcirc->Clone());
101 circ->ConvertForCutting();
102 optSim->SetUpcomingGates(circ->GetOperations());
103 }
104
105 std::shared_ptr<Circuits::MeasurementOperation<Time>> measurementsOp;
106
107 const std::vector<bool> executed = std::move(executedGates);
108
109 if (optimiseMultipleShots && hasMeasurementsOnlyAtEnd) {
110 bool isQiskitAer = false;
111#ifndef NO_QISKIT_AER
113 isQiskitAer = true;
114 }
115#endif
116 measurementsOp = dcirc->GetLastMeasurements(executed, isQiskitAer);
117 const auto &qbits = measurementsOp->GetQubits();
118 if (qbits.empty()) {
119 auto bits = state.GetAllBits();
120 bits.resize(nrResultCbits, false);
121
122 const std::lock_guard lock(resultsMutex);
123 res[bits] += curCnt;
124
125 return;
126 }
127 }
128
129 ExecuteResults localRes;
130
131 if (optimiseMultipleShots &&
132 (specialOptimizationForStatevector || hasMeasurementsOnlyAtEnd)) {
133 const auto &qbits = measurementsOp->GetQubits();
134
135 const auto sampleres = optSim->SampleCountsMany(qbits, curCnt);
136
137 for (const auto &[mstate, cnt] : sampleres) {
138 measurementsOp->SetStateFromSample(mstate, state);
139
140 auto bits = state.GetAllBits();
141 bits.resize(nrResultCbits, false);
142
143 localRes[bits] += cnt;
144
145 state.Reset();
146 }
147
148 const std::lock_guard lock(resultsMutex);
149 for (const auto &r : localRes) res[r.first] += r.second;
150
151 return;
152 }
153
154 const auto curCnt1 = curCnt > 0 ? curCnt - 1 : 0;
155 for (size_t i = 0; i < curCnt; ++i) {
156 if (optimiseMultipleShots) {
157 if (i > 0) {
158 optSim->RestoreState();
159 optSim->SetGatesCounter(0);
160 }
161 dcirc->ExecuteMeasurements(optSim, state, executed);
162 } else {
163 dcirc->Execute(optSim, state);
164 if (i < curCnt1) {
165 optSim->Reset();
166 optSim->SetGatesCounter(0);
167 }
168 }
169
170 auto bits = state.GetAllBits();
171 bits.resize(nrResultCbits, false);
172
173 ++localRes[bits];
174
175 state.Reset();
176 }
177
178 const std::lock_guard lock(resultsMutex);
179 for (const auto &r : localRes) res[r.first] += r.second;
180 }
181
183 if (curCnt == 0) return;
184
186 state.AllocateBits(nrCbits);
187
188 const bool hasMeasurementsOnlyAtEnd = !dcirc->HasOpsAfterMeasurements();
189 const bool optimiseMultipleShots = optimiseMultipleShotsExecution;
190 const bool specialOptimizationForStatevector =
191 optimiseMultipleShots &&
193 hasMeasurementsOnlyAtEnd;
194 const bool specialOptimizationForMPS =
195 optimiseMultipleShots &&
197 hasMeasurementsOnlyAtEnd;
198
199
200 if (optSim) {
201 optSim->SetMultithreading(true);
202
203 if (optSim->GetNumberOfQubits() != nrQubits) {
204 optSim->Clear();
205
206 if (!maxBondDim.empty())
207 optSim->Configure("matrix_product_state_max_bond_dimension",
208 maxBondDim.c_str());
209 if (!singularValueThreshold.empty())
210 optSim->Configure("matrix_product_state_truncation_threshold",
211 singularValueThreshold.c_str());
212 if (!mpsSample.empty())
213 optSim->Configure("mps_sample_measure_algorithm", mpsSample.c_str());
214
215 optSim->AllocateQubits(nrQubits);
216 optSim->Initialize();
217
218 OptimizeMPSInitialQubitsMap(optSim, dcirc, nrQubits);
219
220 if (optimiseMultipleShots) {
221 executedGates = dcirc->ExecuteNonMeasurements(optSim, state);
222
223 if (!specialOptimizationForStatevector &&
224 !specialOptimizationForMPS && curCnt > 1)
225 optSim->SaveState();
226 dcirc = dcirc->RemoveExecutedOperations(executedGates);
228 network->GetMPSOptimizeSwaps()) {
229 //auto circ = std::static_pointer_cast<Circuits::Circuit<Time>>(dcirc->Clone());
230 //circ->ConvertForCutting();
231 optSim->SetUpcomingGates(dcirc->GetOperations());
232 }
233 }
234 } else if (executedGates.size() == dcirc->size()) {
235 // special case for when the simulator is passed from the network
236 // and no gates were executed yet
237 bool needToExecuteGates = true;
238 for (const bool val : executedGates) {
239 if (val) {
240 needToExecuteGates = false;
241 break;
242 }
243 }
244 if (needToExecuteGates && optimiseMultipleShots) {
245 executedGates = dcirc->ExecuteNonMeasurements(optSim, state);
246 if (!specialOptimizationForStatevector &&
247 !specialOptimizationForMPS && curCnt > 1)
248 optSim->SaveState();
249 dcirc = dcirc->RemoveExecutedOperations(executedGates);
251 network->GetMPSOptimizeSwaps()) {
252 //auto circ = std::static_pointer_cast<Circuits::Circuit<Time>>(dcirc->Clone());
253 //circ->ConvertForCutting();
254 optSim->SetUpcomingGates(dcirc->GetOperations());
255 }
256 } else {
257 dcirc = dcirc->RemoveExecutedOperations(executedGates);
259 network->GetMPSOptimizeSwaps()) {
260 //auto circ = std::static_pointer_cast<Circuits::Circuit<Time>>(dcirc->Clone());
261 //circ->ConvertForCutting();
262 optSim->SetUpcomingGates(dcirc->GetOperations());
263 }
264 }
265 } else {
266 dcirc = dcirc->RemoveExecutedOperations(executedGates);
268 network->GetMPSOptimizeSwaps()) {
269 auto circ =
270 std::static_pointer_cast<Circuits::Circuit<Time>>(dcirc->Clone());
271 circ->ConvertForCutting();
272 optSim->SetUpcomingGates(circ->GetOperations());
273 }
274 }
275 } else {
277 if (!optSim) return;
278
279 optSim->SetMultithreading(true);
280
281 if (!maxBondDim.empty())
282 optSim->Configure("matrix_product_state_max_bond_dimension",
283 maxBondDim.c_str());
284 if (!singularValueThreshold.empty())
285 optSim->Configure("matrix_product_state_truncation_threshold",
286 singularValueThreshold.c_str());
287 if (!mpsSample.empty())
288 optSim->Configure("mps_sample_measure_algorithm", mpsSample.c_str());
289
290 optSim->AllocateQubits(nrQubits);
291 optSim->Initialize();
292
293 OptimizeMPSInitialQubitsMap(optSim, dcirc, nrQubits);
294
295 if (optimiseMultipleShots) {
296 executedGates = dcirc->ExecuteNonMeasurements(optSim, state);
297
298 if (!specialOptimizationForStatevector && !specialOptimizationForMPS &&
299 curCnt > 1)
300 optSim->SaveState();
301
302 dcirc = dcirc->RemoveExecutedOperations(executedGates);
303 if (method == Simulators::SimulationType::kMatrixProductState && network->GetMPSOptimizeSwaps()) {
304 //auto circ = std::static_pointer_cast<Circuits::Circuit<Time>>(dcirc->Clone());
305 //circ->ConvertForCutting();
306 optSim->SetUpcomingGates(dcirc->GetOperations());
307 }
308 }
309 }
310
311 std::shared_ptr<Circuits::MeasurementOperation<Time>> measurementsOp;
312
313 const std::vector<bool> executed = std::move(executedGates);
314
315 if (optimiseMultipleShots && hasMeasurementsOnlyAtEnd) {
316 bool isQiskitAer = false;
317#ifndef NO_QISKIT_AER
319 isQiskitAer = true;
320 }
321#endif
322 measurementsOp = dcirc->GetLastMeasurements(executed, isQiskitAer);
323 const auto &qbits = measurementsOp->GetQubits();
324 if (qbits.empty()) {
325 auto bits = state.GetAllBits();
326 bits.resize(nrResultCbits, false);
327
328 res[bits] += curCnt;
329
330 return;
331 }
332 }
333
334 if (optimiseMultipleShots &&
335 (specialOptimizationForStatevector || hasMeasurementsOnlyAtEnd)) {
336 const auto &qbits = measurementsOp->GetQubits();
337
338 const auto sampleres = optSim->SampleCountsMany(qbits, curCnt);
339
340 for (const auto &[mstate, cnt] : sampleres) {
341 measurementsOp->SetStateFromSample(mstate, state);
342
343 auto bits = state.GetAllBits();
344 bits.resize(nrResultCbits, false);
345
346 res[bits] += cnt;
347
348 state.Reset();
349 }
350
351 return;
352 }
353
354 const auto curCnt1 = curCnt > 0 ? curCnt - 1 : 0;
355 for (size_t i = 0; i < curCnt; ++i) {
356 if (optimiseMultipleShots) {
357 if (i > 0) {
358 optSim->RestoreState();
359 optSim->SetGatesCounter(0);
360 }
361 dcirc->ExecuteMeasurements(optSim, state, executed);
362 } else {
363 dcirc->Execute(optSim, state);
364 if (i < curCnt1) {
365 optSim->Reset(); // leave the simulator state for the last iteration
366 optSim->SetGatesCounter(0);
367 }
368 }
369
370 auto bits = state.GetAllBits();
371 bits.resize(nrResultCbits, false);
372
373 ++res[bits];
374
375 state.Reset();
376 }
377 }
378
380 size_t curCnt) {
381 return curCnt > 1;
382 }
383
384 size_t GetJobCount() const { return curCnt; }
385
386private:
387 void OptimizeMPSInitialQubitsMap(
388 std::shared_ptr<Simulators::ISimulator> &sim,
389 std::shared_ptr<Circuits::Circuit<Time>> &dcirc, size_t nrQubits) const {
390 if (sim->GetSimulationType() ==
392 (network->GetInitialQubitsMapOptimization() ||
393 network->GetMPSOptimizeSwaps()) &&
394 sim->SupportsMPSSwapOptimization()) {
395 if (network->GetMPSOptimizationQubitsNumberThreshold() <= nrQubits) {
396 const auto bondDimThreshold =
397 network->GetMPSOptimizationBondDimensionThreshold();
398 const auto maxBondDimValue =
399 maxBondDim.empty() ? 0 : std::stoi(maxBondDim);
400
401 if (maxBondDim.empty() || static_cast<int>(bondDimThreshold) <= maxBondDimValue) {
402 // need to be sure the circuit is correctly converted
403 dcirc->ConvertForCutting(); // convert the three qubit gates
404 auto layers = dcirc->ToMultipleQubitsLayersNoClone();
405
407 dummySim.setGrowthFactorGate(network->getGrowthFactorGate());
408 dummySim.setGrowthFactorSwap(network->getGrowthFactorSwap());
409 if (!maxBondDim.empty())
410 dummySim.SetMaxBondDimension(maxBondDimValue);
411
412 if (network->GetInitialQubitsMapOptimization()) {
413 const auto optimalMap = dummySim.ComputeOptimalQubitsMap(layers);
414 sim->SetInitialQubitsMap(optimalMap);
415 }
416
418
419 if (network->GetMPSOptimizeSwaps()) {
420 // TODO: come up with something better!
421 int lookaheadDepthLocal = network->GetLookaheadDepth();
422
423 if (lookaheadDepthLocal == std::numeric_limits<int>::max()) {
424 double avgTwoQubitGatesPerLayer = 0.0;
425 for (const auto &layer : layers) {
426 int twoQubitGates = 0;
427 for (const auto &op : layer->GetOperations()) {
428 if (op->AffectedQubits().size() >= 2) {
429 ++twoQubitGates;
430 }
431 }
432 avgTwoQubitGatesPerLayer += twoQubitGates;
433 }
434 avgTwoQubitGatesPerLayer /= layers.size();
435
436 int lookaheadVal =
437 static_cast<int>(4. * avgTwoQubitGatesPerLayer);
438 if (lookaheadVal > 15) lookaheadVal = 15;
439
440 lookaheadDepthLocal =
441 layers.size() < 8 || nrQubits <= 10 ? 0
442 : layers.size() < 15 ? static_cast<int>(lookaheadVal)
443 : layers.size() < 25 ? static_cast<int>(1.5 * lookaheadVal)
444 : 2 * lookaheadVal;
445 }
446
447 int lookaheadHeuristicDepthLocal =
448 network->GetLookaheadDepthWithHeuristic();
449
450 if (lookaheadHeuristicDepthLocal == std::numeric_limits<int>::max())
451 lookaheadHeuristicDepthLocal =
452 layers.size() < 10 || nrQubits <= 10 ? 0
453 : layers.size() < 20
454 ? lookaheadDepthLocal - 1
455 : lookaheadDepthLocal - 2;
456
457 if (lookaheadHeuristicDepthLocal < 0)
458 lookaheadHeuristicDepthLocal = 0;
459
460 sim->SetUseOptimalMeetingPosition(true);
461 sim->SetLookaheadDepth(lookaheadDepthLocal);
462 sim->SetLookaheadDepthWithHeuristic(lookaheadHeuristicDepthLocal);
463 sim->setGrowthFactorGate(network->getGrowthFactorGate());
464 sim->setGrowthFactorSwap(network->getGrowthFactorSwap());
465 sim->SetUpcomingGates(dcirc->GetOperations());
466 }
467 }
468 }
469 }
470 }
471
472public:
473 std::shared_ptr<Circuits::Circuit<Time>> dcirc;
475 const size_t curCnt;
476 const size_t nrQubits;
477 const size_t nrCbits;
478 const size_t nrResultCbits;
479
482 std::mutex &resultsMutex;
483
485 std::shared_ptr<Simulators::ISimulator> optSim;
486 std::vector<bool> executedGates;
487
488 // only fill them if passing null simulator
489 std::string maxBondDim;
491 std::string mpsSample;
492
493 std::shared_ptr<Network::INetwork<Time>> network;
494};
495
496} // namespace Network
497
498#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:474
bool optimiseMultipleShotsExecution
Definition NetworkJob.h:484
static bool IsOptimisableForMultipleShots(Simulators::SimulatorType t, size_t curCnt)
Definition NetworkJob.h:379
const Simulators::SimulatorType simType
Definition NetworkJob.h:480
std::string maxBondDim
Definition NetworkJob.h:489
const size_t curCnt
Definition NetworkJob.h:475
std::vector< bool > executedGates
Definition NetworkJob.h:486
typename Circuits::Circuit< Time >::ExecuteResults ExecuteResults
Definition NetworkJob.h:28
std::shared_ptr< Network::INetwork< Time > > network
Definition NetworkJob.h:493
const size_t nrResultCbits
Definition NetworkJob.h:478
const size_t nrCbits
Definition NetworkJob.h:477
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:485
std::shared_ptr< Circuits::Circuit< Time > > dcirc
Definition NetworkJob.h:473
std::mutex & resultsMutex
Definition NetworkJob.h:482
const size_t nrQubits
Definition NetworkJob.h:476
std::string mpsSample
Definition NetworkJob.h:491
const Simulators::SimulationType method
Definition NetworkJob.h:481
std::string singularValueThreshold
Definition NetworkJob.h:490
size_t GetJobCount() const
Definition NetworkJob.h:384
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