Maestro 0.3.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
21
22#include "Network.h"
23
24#include "Configuration.h"
25#include <algorithm>
26#include <functional>
27#ifdef _OPENMP
28#include <omp.h>
29#endif
30
31namespace Network
32{
33
34template <typename Time = Types::time_type> class ExecuteJob
35{
36 public:
38 std::function<void(const Simulators::ISimulator &)> onSimulatorReady;
39
40 ExecuteJob() = delete;
41
42 explicit ExecuteJob(const std::shared_ptr<Circuits::Circuit<Time>> &c, ExecuteResults &r, size_t cnt, size_t nq, size_t nc, size_t ncr,
44 : dcirc(c), res(r), curCnt(cnt), nrQubits(nq), nrCbits(nc), nrResultCbits(ncr), simType(t), method(m), resultsMutex(mut)
45 {
46 }
47
48 void DoWork()
49 {
50 if (curCnt == 0)
51 return;
52 ScopedInternalThreads threadBudget(internalThreads);
53 if (cloneSource)
54 {
55 // Clone only when a worker starts, so queued logical blocks do not
56 // each retain another statevector/density matrix. Fusion flushes
57 // during cloning, hence the short lock around the source.
58 const std::lock_guard lock(*cloneMutex);
59 optSim = cloneSource->CloneForExecution(std::stoull(config.GetConfiguration("seed")));
60 }
61 // The dispatcher assigns this job a share of the internal thread budget.
62 ConfigureTrajectoryArithmetic();
63 if (optSim && optSim->GetType() == Simulators::SimulatorType::kQCSim &&
64 (method == Simulators::SimulationType::kPauliPropagator || optSim->GetConfiguration("sampling_policy") == "reproducible_v1"))
65 optSim->SetMultithreading(allowInternalMultithreading);
66 // Multithreading off has to hold for what the simulator calls on this thread too, not only for
67 // its own loops: a BLAS built on OpenMP would otherwise start a thread team for each shot worker.
68 threadBudget.Limit(SimulatorThreadLimit());
69
70 // Per-shot streams must clone the original instruction seeds, not a
71 // job-seeded copy (which would make classical RNGs depend on batching).
73 PrepareCircuitForExecution();
74
76 state.AllocateBits(nrCbits);
77
78 const bool hasMeasurementsOnlyAtEnd = !dcirc->HasOpsAfterMeasurements();
79 const bool optimiseMultipleShots = optimiseMultipleShotsExecution;
80 const bool specialOptimizationForStatevector = optimiseMultipleShots && method == Simulators::SimulationType::kStatevector && hasMeasurementsOnlyAtEnd;
81
82 size_t curMaxBondDimLocal = 0;
83
84 // A retained simulator may contain the caller's input state rather than
85 // an executed prefix. Prepare the same suffix as a newly created worker
86 // so per-shot classical RNG positions do not depend on simulator reuse.
87 if (optSim && optimiseMultipleShots && executedGates.size() == dcirc->size() &&
88 std::none_of(executedGates.begin(), executedGates.end(), [](bool executed) { return executed; }))
89 {
90 executedGates = dcirc->ExecuteNonMeasurements(optSim, state, &curMaxBondDimLocal);
91 if (!hasMeasurementsOnlyAtEnd && curCnt > 1)
92 optSim->SaveState();
93 }
94
95 dcirc = dcirc->RemoveExecutedOperations(executedGates);
96
97 if (!optSim)
98 {
100 if (!optSim)
101 return;
102 config.ApplyConfigurationToSimulator(optSim);
104 optSim->GetConfiguration("sampling_policy") == "reproducible_v1")
105 optSim->SetMultithreading(allowInternalMultithreading);
106 threadBudget.Limit(SimulatorThreadLimit());
107 optSim->AllocateQubits(nrQubits);
108 optSim->Initialize();
109
110 OptimizeMPSInitialQubitsMap(optSim, dcirc, nrQubits);
111
112 if (optimiseMultipleShots)
113 {
114 executedGates = dcirc->ExecuteNonMeasurements(optSim, state, &curMaxBondDimLocal);
115
116 dcirc = dcirc->RemoveExecutedOperations(executedGates);
118 network->GetMPSOptimizeSwaps())
119 {
120 // auto circ =
121 // std::static_pointer_cast<Circuits::Circuit<Time>>(dcirc->Clone());
122 // circ->ConvertForCutting();
123 optSim->SetUpcomingGates(dcirc->GetOperations());
124 }
125 // The snapshot must describe the suffix executed by every shot.
126 if (!hasMeasurementsOnlyAtEnd && curCnt > 1)
127 optSim->SaveState();
128 }
129 }
131 network->GetMPSOptimizeSwaps())
132 {
133 auto circ = std::static_pointer_cast<Circuits::Circuit<Time>>(dcirc->Clone());
134 circ->ConvertForCutting();
135 optSim->SetUpcomingGates(circ->GetOperations());
136 }
137
140 std::shared_ptr<Circuits::MeasurementOperation<Time>> measurementsOp;
141
142 const std::vector<bool> executed = std::move(executedGates);
143
144 if (optimiseMultipleShots && hasMeasurementsOnlyAtEnd)
145 {
146 bool isQiskitAer = false;
147#ifndef NO_QISKIT_AER
149 {
150 isQiskitAer = true;
151 }
152#endif
153 measurementsOp = dcirc->GetLastMeasurements(executed, isQiskitAer);
154 const auto &qbits = measurementsOp->GetQubits();
155 if (qbits.empty())
156 {
157 auto bits = state.GetAllBits();
158 bits.resize(nrResultCbits, false);
159
160 const std::lock_guard lock(resultsMutex);
161 res[bits] += curCnt;
162
163 if (curMaxBondDim && curMaxBondDimLocal > *curMaxBondDim)
164 *curMaxBondDim = curMaxBondDimLocal;
165
166 return;
167 }
168 }
169
170 ExecuteResults localRes;
171
172 if (optimiseMultipleShots && (specialOptimizationForStatevector || hasMeasurementsOnlyAtEnd))
173 {
174 const auto &qbits = measurementsOp->GetQubits();
175
176 const auto sampleres = optSim->SampleCountsMany(qbits, curCnt);
177
178 AccumulateSamples(*measurementsOp, sampleres, state, localRes);
179
180 const std::lock_guard lock(resultsMutex);
181 for (const auto &r : localRes)
182 res[r.first] += r.second;
183
184 if (curMaxBondDim && curMaxBondDimLocal > *curMaxBondDim)
185 *curMaxBondDim = curMaxBondDimLocal;
186
187 return;
188 }
189
190 const auto curCnt1 = curCnt > 0 ? curCnt - 1 : 0;
191 const auto shotCircuit = dcirc;
192 for (size_t i = 0; i < curCnt; ++i)
193 {
195 {
196 const uint64_t seed = Simulators::IState::DeriveSeed(trajectorySeed, firstShot + i);
197 optSim->SetSeed(seed); // Backend and readout have separate streams.
198 dcirc = shotCircuit->CloneForExecution(Simulators::IState::DeriveSeed(seed, 0x434c415353494341ULL));
199 }
200 if (optimiseMultipleShots)
201 {
202 if (i > 0)
203 {
204 optSim->RestoreState();
205 optSim->SetGatesCounter(0);
206 }
207 dcirc->ExecuteMeasurements(optSim, state, executed, &curMaxBondDimLocal);
208 }
209 else
210 {
211 dcirc->ExecuteBD(optSim, state, &curMaxBondDimLocal);
212 if (i < curCnt1)
213 {
214 optSim->Reset();
215 optSim->SetGatesCounter(0);
216 }
217 }
218
219 auto bits = state.GetAllBits();
220 bits.resize(nrResultCbits, false);
221
222 ++localRes[bits];
223
224 state.Reset();
225 }
226
227 const std::lock_guard lock(resultsMutex);
228 for (const auto &r : localRes)
229 res[r.first] += r.second;
230
231 if (curMaxBondDim && curMaxBondDimLocal > *curMaxBondDim)
232 *curMaxBondDim = curMaxBondDimLocal;
233 }
234
236 {
237 if (curCnt == 0)
238 return;
239
240 ConfigureTrajectoryArithmetic();
241 PrepareCircuitForExecution();
242
244 state.AllocateBits(nrCbits);
245
246 const bool hasMeasurementsOnlyAtEnd = !dcirc->HasOpsAfterMeasurements();
247 const bool optimiseMultipleShots = optimiseMultipleShotsExecution;
248 const bool specialOptimizationForStatevector = optimiseMultipleShots && method == Simulators::SimulationType::kStatevector && hasMeasurementsOnlyAtEnd;
249
250 if (optSim)
251 {
252 optSim->SetMultithreading(true);
253
254 if (optSim->GetNumberOfQubits() != nrQubits)
255 {
256 optSim->Clear();
257 config.ApplyConfigurationToSimulator(optSim);
258
259 optSim->AllocateQubits(nrQubits);
260 optSim->Initialize();
261
262 OptimizeMPSInitialQubitsMap(optSim, dcirc, nrQubits);
263
264 if (optimiseMultipleShots)
265 {
266 executedGates = dcirc->ExecuteNonMeasurements(optSim, state, curMaxBondDim);
267
268 dcirc = dcirc->RemoveExecutedOperations(executedGates);
270 network->GetMPSOptimizeSwaps())
271 {
272 // auto circ =
273 // std::static_pointer_cast<Circuits::Circuit<Time>>(dcirc->Clone());
274 // circ->ConvertForCutting();
275 optSim->SetUpcomingGates(dcirc->GetOperations());
276 }
277 if (!hasMeasurementsOnlyAtEnd && curCnt > 1)
278 optSim->SaveState();
279 }
280 }
281 else if (executedGates.size() == dcirc->size())
282 {
283 // special case for when the simulator is passed from the network
284 // and no gates were executed yet
285 bool needToExecuteGates = true;
286 for (const bool val : executedGates)
287 {
288 if (val)
289 {
290 needToExecuteGates = false;
291 break;
292 }
293 }
294 if (needToExecuteGates && optimiseMultipleShots)
295 {
296 executedGates = dcirc->ExecuteNonMeasurements(optSim, state, curMaxBondDim);
297 dcirc = dcirc->RemoveExecutedOperations(executedGates);
299 network->GetMPSOptimizeSwaps())
300 {
301 // auto circ =
302 // std::static_pointer_cast<Circuits::Circuit<Time>>(dcirc->Clone());
303 // circ->ConvertForCutting();
304 optSim->SetUpcomingGates(dcirc->GetOperations());
305 }
306 if (!hasMeasurementsOnlyAtEnd && curCnt > 1)
307 optSim->SaveState();
308 }
309 else
310 {
311 dcirc = dcirc->RemoveExecutedOperations(executedGates);
313 network->GetMPSOptimizeSwaps())
314 {
315 // auto circ =
316 // std::static_pointer_cast<Circuits::Circuit<Time>>(dcirc->Clone());
317 // circ->ConvertForCutting();
318 optSim->SetUpcomingGates(dcirc->GetOperations());
319 }
320 }
321 }
322 else
323 {
324 dcirc = dcirc->RemoveExecutedOperations(executedGates);
326 network->GetMPSOptimizeSwaps())
327 {
328 auto circ = std::static_pointer_cast<Circuits::Circuit<Time>>(dcirc->Clone());
329 circ->ConvertForCutting();
330 optSim->SetUpcomingGates(circ->GetOperations());
331 }
332 }
333 }
334 else
335 {
337 if (!optSim)
338 return;
339
340 optSim->SetMultithreading(true);
341 config.ApplyConfigurationToSimulator(optSim);
342
343 optSim->AllocateQubits(nrQubits);
344 optSim->Initialize();
345
346 OptimizeMPSInitialQubitsMap(optSim, dcirc, nrQubits);
347
348 if (optimiseMultipleShots)
349 {
350 executedGates = dcirc->ExecuteNonMeasurements(optSim, state, curMaxBondDim);
351 dcirc = dcirc->RemoveExecutedOperations(executedGates);
353 network->GetMPSOptimizeSwaps())
354 {
355 // auto circ =
356 // std::static_pointer_cast<Circuits::Circuit<Time>>(dcirc->Clone());
357 // circ->ConvertForCutting();
358 optSim->SetUpcomingGates(dcirc->GetOperations());
359 }
360 if (!hasMeasurementsOnlyAtEnd && curCnt > 1)
361 optSim->SaveState();
362 }
363 }
364
367 std::shared_ptr<Circuits::MeasurementOperation<Time>> measurementsOp;
368
369 const std::vector<bool> executed = std::move(executedGates);
370
371 if (optimiseMultipleShots && hasMeasurementsOnlyAtEnd)
372 {
373 bool isQiskitAer = false;
374#ifndef NO_QISKIT_AER
376 {
377 isQiskitAer = true;
378 }
379#endif
380 measurementsOp = dcirc->GetLastMeasurements(executed, isQiskitAer);
381 const auto &qbits = measurementsOp->GetQubits();
382 if (qbits.empty())
383 {
384 auto bits = state.GetAllBits();
385 bits.resize(nrResultCbits, false);
386
387 res[bits] += curCnt;
388
389 return;
390 }
391 }
392
393 if (optimiseMultipleShots && (specialOptimizationForStatevector || hasMeasurementsOnlyAtEnd))
394 {
395 const auto &qbits = measurementsOp->GetQubits();
396
397 const auto sampleres = optSim->SampleCountsMany(qbits, curCnt);
398
399 AccumulateSamples(*measurementsOp, sampleres, state, res);
400
401 return;
402 }
403
404 const auto curCnt1 = curCnt > 0 ? curCnt - 1 : 0;
405 for (size_t i = 0; i < curCnt; ++i)
406 {
407 if (optimiseMultipleShots)
408 {
409 if (i > 0)
410 {
411 optSim->RestoreState();
412 optSim->SetGatesCounter(0);
413 }
414 dcirc->ExecuteMeasurements(optSim, state, executed, curMaxBondDim);
415 }
416 else
417 {
418 dcirc->ExecuteBD(optSim, state, curMaxBondDim);
419 if (i < curCnt1)
420 {
421 optSim->Reset(); // leave the simulator state for the last iteration
422 optSim->SetGatesCounter(0);
423 }
424 }
425
426 auto bits = state.GetAllBits();
427 bits.resize(nrResultCbits, false);
428
429 ++res[bits];
430
431 state.Reset();
432 }
433 }
434
436 {
437 return curCnt > 1;
438 }
439
440 size_t GetJobCount() const
441 {
442 return curCnt;
443 }
444
445 private:
446 void ConfigureTrajectoryArithmetic()
447 {
448 // Existing and prepared simulators need the current execution mode too:
449 // a terminal batch following trajectories must not retain this mode.
450 if (optSim && optSim->GetType() == Simulators::SimulatorType::kQCSim && config.IsSet("reproducible_trajectory"))
451 optSim->Configure("reproducible_trajectory", config.GetConfiguration("reproducible_trajectory").c_str());
452 }
453
454 class ScopedInternalThreads
455 {
456 public:
457 explicit ScopedInternalThreads(int threads)
458 {
459 Limit(threads);
460 }
461
462 void Limit(int threads)
463 {
464#ifdef _OPENMP
465 if (threads > 0)
466 {
467 if (previous == 0)
468 previous = omp_get_max_threads();
469 omp_set_num_threads(threads);
470 }
471#else
472 (void)threads;
473#endif
474 }
475
476 ~ScopedInternalThreads()
477 {
478#ifdef _OPENMP
479 if (previous > 0)
480 omp_set_num_threads(previous);
481#endif
482 }
483
484 private:
485#ifdef _OPENMP
486 int previous = 0;
487#endif
488 };
489
490 int SimulatorThreadLimit() const
491 {
492#if defined(_OPENMP) && defined(_MSC_VER) && !defined(__clang__) && !defined(_OPENMP_LLVM_RUNTIME)
493 // Legacy MSVC OpenMP keeps this setting process-wide, per-worker save/restore would race.
494 return 0;
495#else
496 return optSim && !optSim->GetMultithreading() ? 1 : 0;
497#endif
498 }
499
500 template <class Samples>
501 void AccumulateSamples(Circuits::MeasurementOperation<Time> &measurement, const Samples &samples, Circuits::OperationState &state, ExecuteResults &target)
502 {
503 auto add = [&](const auto &sample) {
504 const auto &[bits, count] = sample;
505 const size_t draws = measurement.HasReadout() ? count : 1;
506 for (size_t i = 0; i < draws; ++i)
507 {
508 measurement.SetStateFromSample(bits, state, measurement.HasReadout() ? optSim.get() : nullptr);
509 auto output = state.GetAllBits();
510 output.resize(nrResultCbits, false);
511 target[output] += measurement.HasReadout() ? 1 : count;
512 state.Reset();
513 }
514 };
515 if (measurement.HasReadout() && optSim->GetConfiguration("sampling_policy") == "reproducible_v1")
516 {
517 // Histogram insertion order can change with the execution kernel.
518 // Apply auxiliary readout draws in lexicographic outcome order.
519 std::vector<const typename Samples::value_type *> ordered;
520 ordered.reserve(samples.size());
521 for (const auto &sample : samples)
522 ordered.push_back(&sample);
523 std::sort(ordered.begin(), ordered.end(), [](auto a, auto b) { return a->first < b->first; });
524 for (const auto *sample : ordered)
525 add(*sample);
526 }
527 else
528 for (const auto &sample : samples)
529 add(sample);
530 }
531
532 void PrepareCircuitForExecution()
533 {
534 const uint64_t stream = config.IsSet("seed") ? std::stoull(config.GetConfiguration("seed")) : randomStream;
535 // Only unseeded instructions need fresh entropy. For MPI the helper shares
536 // it across ranks, so classical controls follow the same execution path.
537 const uint64_t defaultSeed =
538 !config.IsSet("seed") && dcirc->HasUnseededRandomOperations() ? Simulators::GenerateRandomSeed(simType, config.GetConfigMap()) : 0;
539 dcirc = dcirc->CloneForExecution(stream, defaultSeed);
540 }
541
542 void OptimizeMPSInitialQubitsMap(std::shared_ptr<Simulators::ISimulator> &sim, std::shared_ptr<Circuits::Circuit<Time>> &dcirc, size_t nrQubits) const
543 {
544 if ((sim->GetSimulationType() == Simulators::SimulationType::kMatrixProductState ||
545 sim->GetSimulationType() == Simulators::SimulationType::kMatrixProductOperator) &&
546 (network->GetInitialQubitsMapOptimization() || network->GetMPSOptimizeSwaps()) && sim->SupportsMPSSwapOptimization() &&
547 !dcirc->HasCompositeOperations())
548 {
549 // an MPO site carries a two-qubit (operator) physical index, so its
550 // bonds grow like those of an MPS twice as long
551 const size_t routedQubits = sim->GetSimulationType() == Simulators::SimulationType::kMatrixProductOperator ? 2 * nrQubits : nrQubits;
552 if (network->GetMPSOptimizationQubitsNumberThreshold() <= routedQubits)
553 {
554 const auto bondDimThreshold = network->GetMPSOptimizationBondDimensionThreshold();
555 const auto maxBondDimValue = config.GetConfigurationAsInt(sim->GetSimulationType() == Simulators::SimulationType::kMatrixProductOperator &&
556 config.IsSet("matrix_product_operator_max_bond_dimension")
557 ? "matrix_product_operator_max_bond_dimension"
558 : "matrix_product_state_max_bond_dimension");
559
560 if (maxBondDimValue == 0 || static_cast<int>(bondDimThreshold) <= maxBondDimValue)
561 {
562 // need to be sure the circuit is correctly converted
563 dcirc->ConvertForCutting(); // convert the three qubit gates
564 auto layers = dcirc->ToMultipleQubitsLayersNoClone();
565 // Finalize source ordering before preparing fusion. Routing layers
566 // are only a cost model and must never replace executable operations.
567 auto ordered = Circuits::Circuit<Time>::LayersToCircuit(layers);
568 dcirc->SetOperations(ordered->GetOperations());
569 sim->SetUpcomingGates(dcirc->GetOperations());
570 if (sim->IsGateFusionEnabled() && !sim->GetUpcomingRoutingOperations().empty())
571 {
572 Circuits::Circuit<Time> routingCircuit;
573 for (const auto &op : sim->GetUpcomingRoutingOperations())
574 if (op->GetType() == Circuits::OperationType::kGate)
575 routingCircuit.AddOperation(op);
576 layers = routingCircuit.ToMultipleQubitsLayersNoClone();
577 }
578
579 Simulators::MPSDummySimulator dummySim(nrQubits, sim->GetSimulationType() == Simulators::SimulationType::kMatrixProductOperator);
580 dummySim.SetSwapGatesRelabelQubits(sim->SwapGatesRelabelQubits());
581 dummySim.setGrowthFactorGate(network->getGrowthFactorGate());
582 dummySim.setGrowthFactorSwap(network->getGrowthFactorSwap());
583 if (maxBondDimValue != 0)
584 {
586 dummySim.SetMaxBondDimension(
588 nrQubits, sim->GetSimulationType() == Simulators::SimulationType::kMatrixProductOperator, maxBondDimValue)
589 : maxBondDimValue);
590 dummySim.SetRoutingCostModel(virtualBonds ? maxBondDimValue : 0, Simulators::RoutingConfig::TruncationWeight(config));
591 }
592
593 if (network->GetInitialQubitsMapOptimization())
594 {
595 const auto optimalMap = dummySim.ComputeOptimalQubitsMap(layers);
596 sim->SetInitialQubitsMap(optimalMap);
597 }
598
599 if (network->GetMPSOptimizeSwaps())
600 {
601 int lookaheadDepthLocal = network->GetLookaheadDepth();
602
603 if (lookaheadDepthLocal == std::numeric_limits<int>::max())
604 {
605 double avgTwoQubitGatesPerLayer = 0.0;
606 for (const auto &layer : layers)
607 {
608 int twoQubitGates = 0;
609 for (const auto &op : layer->GetOperations())
610 {
611 if (op->AffectedQubits().size() >= 2)
612 {
613 ++twoQubitGates;
614 }
615 }
616 avgTwoQubitGatesPerLayer += twoQubitGates;
617 }
618 if (!layers.empty())
619 avgTwoQubitGatesPerLayer /= layers.size();
620
621 int lookaheadVal = static_cast<int>(4. * avgTwoQubitGatesPerLayer);
622 if (lookaheadVal > 15)
623 lookaheadVal = 15;
624
625 lookaheadDepthLocal = layers.size() < 8 || routedQubits <= 10 ? 0
626 : layers.size() < 15 ? static_cast<int>(lookaheadVal)
627 : layers.size() < 25 ? static_cast<int>(1.5 * lookaheadVal)
628 : 2 * lookaheadVal;
629 }
630
631 int lookaheadHeuristicDepthLocal = network->GetLookaheadDepthWithHeuristic();
632
633 if (lookaheadHeuristicDepthLocal == std::numeric_limits<int>::max())
634 lookaheadHeuristicDepthLocal = layers.size() < 8 || routedQubits <= 10 ? 0 : lookaheadDepthLocal - 1;
635
636 if (lookaheadHeuristicDepthLocal < 0)
637 lookaheadHeuristicDepthLocal = 0;
638
639 sim->SetUseOptimalMeetingPosition(true);
640 if (network->GetLookaheadDepth() == std::numeric_limits<int>::max())
641 sim->SetAutomaticLookaheadDepth(lookaheadDepthLocal);
642 else
643 sim->SetLookaheadDepth(lookaheadDepthLocal);
644 sim->SetLookaheadDepthWithHeuristic(lookaheadHeuristicDepthLocal);
645 sim->setGrowthFactorGate(network->getGrowthFactorGate());
646 sim->setGrowthFactorSwap(network->getGrowthFactorSwap());
647 // CPU routing already owns this unchanged, ordered window
648 // from before layout planning. Its setters refresh callbacks
649 // and fusion plans; reinstalling it repeats that preparation.
650 if (sim->GetType() != Simulators::SimulatorType::kQCSim)
651 sim->SetUpcomingGates(dcirc->GetOperations());
652 }
653 }
654 }
655 }
656 }
657
658 public:
659 std::shared_ptr<Circuits::Circuit<Time>> dcirc;
661 const size_t curCnt;
662 const size_t nrQubits;
663 const size_t nrCbits;
664 const size_t nrResultCbits;
665
668 std::mutex &resultsMutex;
669
672 // Zero leaves the caller's OpenMP settings untouched (ordinary jobs).
674 // Distinguishes jobs even when the caller did not configure a simulator seed.
675 uint64_t randomStream = 0;
677 uint64_t trajectorySeed = 0;
678 size_t firstShot = 0;
679 std::shared_ptr<Simulators::ISimulator> optSim;
680 std::shared_ptr<Simulators::ISimulator> cloneSource;
681 std::shared_ptr<std::mutex> cloneMutex;
682 std::vector<bool> executedGates;
683
684 // relevant only if the simulator is not passed or the simulator doesn't have
685 // the proper number of qubits, otherwise the simulator is already configured
687
688 std::shared_ptr<Network::INetwork<Time>> network;
689 size_t *curMaxBondDim = nullptr;
690};
691
692} // namespace Network
693
694#endif // ! _NETWORK_JOB_H
Circuit class for holding the sequence of operations.
Definition Circuit.h:51
void AddOperation(const OperationPtr &op)
Adds an operation to the circuit.
Definition Circuit.h:146
std::vector< std::shared_ptr< Circuits::Circuit< Time > > > ToMultipleQubitsLayersNoClone() const
Converts the circuit to layers oriented on multiple qubit gates.
Definition Circuit.h:2938
std::unordered_map< std::vector< bool >, size_t > ExecuteResults
The results of the execution of the circuit.
Definition Circuit.h:53
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:3031
void SetStateFromSample(const std::vector< bool > &measurements, OperationState &state, Simulators::ISimulator *rng=nullptr) const
Writes sampled outcomes into the classical state, applying readout error per measured qubit.
bool HasReadout() const
True when readout rates are attached to this measurement.
The state class that stores the classical state of a quantum circuit execution.
Definition Operations.h:68
void Reset(bool value=false)
Set the classical bits with the specified value.
Definition Operations.h:282
const std::vector< bool > & GetAllBits() const
Get the classical bits.
Definition Operations.h:244
void AllocateBits(size_t numBits)
Allocate more bits.
Definition Operations.h:179
ExecuteResults & res
Definition NetworkJob.h:660
bool optimiseMultipleShotsExecution
Definition NetworkJob.h:670
static bool IsOptimisableForMultipleShots(Simulators::SimulatorType t, size_t curCnt)
Definition NetworkJob.h:435
const Simulators::SimulatorType simType
Definition NetworkJob.h:666
uint64_t trajectorySeed
Definition NetworkJob.h:677
const size_t curCnt
Definition NetworkJob.h:661
std::vector< bool > executedGates
Definition NetworkJob.h:682
typename Circuits::Circuit< Time >::ExecuteResults ExecuteResults
Definition NetworkJob.h:37
std::shared_ptr< Network::INetwork< Time > > network
Definition NetworkJob.h:688
const size_t nrResultCbits
Definition NetworkJob.h:664
const size_t nrCbits
Definition NetworkJob.h:663
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:42
std::shared_ptr< std::mutex > cloneMutex
Definition NetworkJob.h:681
bool allowInternalMultithreading
Definition NetworkJob.h:671
std::shared_ptr< Simulators::ISimulator > optSim
Definition NetworkJob.h:679
std::shared_ptr< Circuits::Circuit< Time > > dcirc
Definition NetworkJob.h:659
std::mutex & resultsMutex
Definition NetworkJob.h:668
const size_t nrQubits
Definition NetworkJob.h:662
std::function< void(const Simulators::ISimulator &)> onSimulatorReady
Definition NetworkJob.h:38
const Simulators::SimulationType method
Definition NetworkJob.h:667
Configuration< Time > config
Definition NetworkJob.h:686
size_t GetJobCount() const
Definition NetworkJob.h:440
std::shared_ptr< Simulators::ISimulator > cloneSource
Definition NetworkJob.h:680
Interface class for a quantum computing simulator.
Definition Simulator.h:41
virtual SimulatorType GetType() const =0
Returns the type of simulator.
virtual void Configure(const char *key, const char *value)=0
Configures the state.
static uint64_t DeriveSeed(uint64_t seed, uint64_t stream)
Definition State.h:162
static IndexType EffectiveMapMaxBondDimension(size_t nrQubits, bool operatorChain, IndexType cap)
static MAESTRO_FACTORY_EXPORT std::shared_ptr< ISimulator > CreateSimulator(SimulatorType t=SimulatorType::kQCSim, SimulationType method=SimulationType::kMatrixProductState)
Create a quantum computing simulator.
Definition Factory.cpp:45
@ kGate
the usual quantum gate, result stays in simulator's state
Definition Operations.h:30
bool VirtualBondsEnabled(const Config &config)
double TruncationWeight(const Config &config)
uint64_t GenerateRandomSeed(SimulatorType type, const std::unordered_map< std::string, std::string > &options={})
Definition RandomSeed.h:11
SimulationType
The type of simulation.
Definition State.h:109
@ kStatevector
statevector simulation type
Definition State.h:110
@ kMatrixProductState
matrix product state simulation type
Definition State.h:111
@ kMatrixProductOperator
Matrix product operator simulation type.
Definition State.h:118
@ kPauliPropagator
Pauli propagator simulation type.
Definition State.h:114
SimulatorType
The type of simulator.
Definition State.h:79
@ kQCSim
qcsim simulator type
Definition State.h:83
@ kQiskitAer
qiskit aer simulator type
Definition State.h:81