Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
QCSimPathIntegralSimulator.h
Go to the documentation of this file.
1#pragma once
2#if defined(INCLUDED_BY_FACTORY)
5#define _USE_MATH_DEFINES
6#include <math.h>
7
9{
10// path_integral backend. Owns exactly one native QCSim implementation.
11class QCSimPathIntegralSimulator : public QCSimGateSimulator
12{
13 public:
14 QCSimPathIntegralSimulator()
15 {
16 configuration.SetConfiguration("method", "path_integral");
17 }
18
19 const char *MethodName() const override
20 {
21 return "path_integral";
22 }
23
24 void Initialize() override
25 {
26 if (nrQubits != 0)
27 {
28 InitializeSamplingSeed();
29 {
30 pathIntegralSimulator = std::make_unique<PathIntegralSimulator>();
31 pathIntegralSimulator->SetStartZeroState(nrQubits);
32 pathIntegralSimulator->SetSeed(samplingSeed);
33 }
34 SetMultithreading(enableMultithreading);
35 for (const auto &[key, value] : configuration.GetConfigMap())
36 if (key != "method")
37 Configure(key.c_str(), value.c_str());
38 }
39 }
40
41 void Reset() override
42 {
43 if (pathIntegralSimulator)
44 {
45 pathIntegralSimulator->Reset();
46 pathIntegralSimulator->SetStartZeroState(nrQubits);
47 }
48 upcomingGateIndex = 0;
49 }
50
51 void Configure(const char *key, const char *value) override
52 {
53 if (ConfigureSampling(key, value))
54 return;
55 if (std::string("method") == key)
56 {
57 ValidateMethod(value);
58 configuration.SetConfiguration(key, value);
59 return;
60 }
61 if (!configuration.WasApplied(key, value))
62 configuration.SetConfiguration(key, value);
63 if (std::string("seed") == key)
64 {
65 const uint64_t seed = std::stoull(value);
66 SeedAuxiliaryRng(seed);
67 SeedSampling(seed);
68 if (pathIntegralSimulator)
69 pathIntegralSimulator->SetSeed(seed);
70 return;
71 }
72 if (std::string(key) == "pauli_propagator_workers")
73 {
74 const auto workers = configuration.GetConfigurationAsUnsigned(key);
75 if (workers > 1024)
76 throw std::invalid_argument("pauli_propagator_workers exceeds 1024");
77 }
78 if (pathIntegralSimulator)
79 {
80 if (std::string(key) == "path_integral_threshold")
81 {
82 pathIntegralSimulator->SetTrimValue(configuration.GetConfigurationAsDouble(key));
83 }
84 }
85 }
86
87 size_t AllocateQubits(size_t num_qubits) override
88 {
89 const size_t oldNrQubits = nrQubits;
90 nrQubits += num_qubits;
91 return oldNrQubits;
92 }
93
94 void Clear() override
95 {
96 pathIntegralSimulator = nullptr;
97 nrQubits = 0;
98 upcomingGateIndex = 0;
99 upcomingGates.clear();
100 }
101
102 size_t Measure(const Types::qubits_vector &qubits) override
103 {
104 if (qubits.size() > sizeof(size_t) * 8)
105 std::cerr << "Warning: The number of qubits to measure is larger than the "
106 "number of bits in the size_t type, the outcome will be undefined"
107 << std::endl;
108 size_t res = 0;
109 size_t mask = 1ULL;
110 DontNotify();
111 {
112 for (size_t qubit : qubits)
113 {
114 if (pathIntegralSimulator->MeasureQubit(qubit))
115 res |= mask;
116 mask <<= 1;
117 }
118 }
119 Notify();
120 NotifyObservers(qubits);
121 return res;
122 }
123
124 std::vector<bool> MeasureMany(const Types::qubits_vector &qubits) override
125 {
126 std::vector<bool> res(qubits.size(), false);
127 DontNotify();
128 {
129 for (size_t q = 0; q < qubits.size(); ++q)
130 if (pathIntegralSimulator->MeasureQubit(qubits[q]))
131 res[q] = true;
132 }
133 Notify();
134 NotifyObservers(qubits);
135 return res;
136 }
137
138 void ApplyReset(const Types::qubits_vector &qubits) override
139 {
140 DontNotify();
141 {
142 for (size_t qubit : qubits)
143 if (pathIntegralSimulator->MeasureQubit(qubit))
144 {
145 QC::Gates::AppliedGate<> gate(xgate.getRawOperatorMatrix(), qubit);
146 pathIntegralSimulator->PropagateStep(gate, pathIntegralSimulator->Amplitudes());
147 }
148 }
149 Notify();
150 NotifyObservers(qubits);
151 }
152
153 double Probability(Types::qubit_t outcome) override
154 {
155 return pathIntegralSimulator->Probability(outcome);
156 }
157
158 std::complex<double> Amplitude(Types::qubit_t outcome) override
159 {
160 return pathIntegralSimulator->AmplitudeForOutcome(outcome);
161 }
162
163 std::vector<double> AllProbabilities() override
164 {
165 const size_t nrBasisStates = 1ULL << GetNumberOfQubits();
166 std::vector<double> result(nrBasisStates);
167 for (size_t i = 0; i < nrBasisStates; ++i)
168 result[i] = pathIntegralSimulator->Probability(i);
169 return result;
170 }
171
172 std::vector<double> Probabilities(const Types::qubits_vector &qubits) override
173 {
174 std::vector<double> result(qubits.size());
175 {
176 for (int i = 0; i < static_cast<int>(qubits.size()); ++i)
177 result[i] = pathIntegralSimulator->Probability(qubits[i]);
178 }
179 return result;
180 }
181
182 std::unordered_map<Types::qubit_t, Types::qubit_t> SampleCounts(const Types::qubits_vector &qubits, size_t shots = 1000) override
183 {
184 if (!LegacySampling())
185 return SamplePrepared<false>(qubits, shots);
186 if (qubits.empty() || shots == 0)
187 return {};
188 if (qubits.size() > sizeof(size_t) * 8)
189 std::cerr << "Warning: The number of qubits to measure is larger than the "
190 "number of bits in the size_t type, the outcome will be undefined"
191 << std::endl;
192 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
193 DontNotify();
194 {
195 if (nrQubits < 64)
196 {
197 if (shots > 1)
198 {
199 const auto &amplitudes = pathIntegralSimulator->Amplitudes();
200 const Utils::Alias alias(amplitudes);
201 for (size_t shot = 0; shot < shots; ++shot)
202 {
203 const double prob = 1. - uniformZeroOne(rng);
204 const size_t measRaw = alias.Sample(prob);
205 size_t meas = 0;
206 size_t mask = 1ULL;
207 for (auto q : qubits)
208 {
209 const size_t qubitMask = 1ULL << q;
210 if ((measRaw & qubitMask) != 0)
211 meas |= mask;
212 mask <<= 1ULL;
213 }
214 ++result[meas];
215 }
216 }
217 else
218 {
219 const size_t measRaw = MeasureNoCollapse();
220 size_t meas = 0;
221 size_t mask = 1ULL;
222 for (auto q : qubits)
223 {
224 const size_t qubitMask = 1ULL << q;
225 if ((measRaw & qubitMask) != 0)
226 meas |= mask;
227 mask <<= 1ULL;
228 }
229 ++result[meas];
230 }
231 }
232 else
233 {
234 throw std::runtime_error("QCSimState::SampleCounts: The path integral simulator does not "
235 "support sampling for more than 63 qubits into 64 bits integers.");
236 }
237 }
238 Notify();
239 NotifyObservers(qubits);
240 return result;
241 }
242
243 std::unordered_map<std::vector<bool>, Types::qubit_t> SampleCountsMany(const Types::qubits_vector &qubits, size_t shots = 1000) override
244 {
245 if (!LegacySampling())
246 return SamplePrepared<true>(qubits, shots);
247 if (qubits.empty() || shots == 0)
248 return {};
249 std::unordered_map<std::vector<bool>, Types::qubit_t> result;
250 DontNotify();
251 {
252 if (nrQubits < 64)
253 {
254 if (shots > 1)
255 {
256 const auto &amplitudes = pathIntegralSimulator->Amplitudes();
257 const Utils::Alias alias(amplitudes);
258 for (size_t shot = 0; shot < shots; ++shot)
259 {
260 const double prob = 1. - uniformZeroOne(rng);
261 const size_t measRaw = alias.Sample(prob);
262 std::vector<bool> meas(qubits.size(), false);
263 for (size_t i = 0; i < qubits.size(); ++i)
264 if (((measRaw >> qubits[i]) & 1) == 1)
265 meas[i] = true;
266 ++result[meas];
267 }
268 }
269 else
270 {
271 for (size_t shot = 0; shot < shots; ++shot)
272 {
273 const auto measRaw = MeasureNoCollapseMany();
274 std::vector<bool> meas(qubits.size(), false);
275 for (size_t i = 0; i < qubits.size(); ++i)
276 if (measRaw[qubits[i]])
277 meas[i] = true;
278 ++result[meas];
279 }
280 }
281 }
282 else
283 {
284 if (shots > 1)
285 {
286 const auto &amplitudes = pathIntegralSimulator->Amplitudes();
287 const Utils::AliasBig alias(amplitudes);
288 for (size_t shot = 0; shot < shots; ++shot)
289 {
290 const double prob = 1. - uniformZeroOne(rng);
291 const auto measRaw = alias.Sample(prob);
292 std::vector<bool> meas(qubits.size(), false);
293 for (size_t i = 0; i < qubits.size(); ++i)
294 if (measRaw.get(qubits[i]))
295 meas[i] = true;
296 ++result[meas];
297 }
298 }
299 else
300 {
301 for (size_t shot = 0; shot < shots; ++shot)
302 {
303 const auto measRaw = MeasureNoCollapseMany();
304 std::vector<bool> meas(qubits.size(), false);
305 for (size_t i = 0; i < qubits.size(); ++i)
306 if (measRaw[qubits[i]])
307 meas[i] = true;
308 ++result[meas];
309 }
310 }
311 }
312 }
313 Notify();
314 NotifyObservers(qubits);
315 return result;
316 }
317
318 double ExpectationValue(const std::string &pauliStringOrig) override
319 {
320 if (pauliStringOrig.empty())
321 return 1.0;
322 std::string pauliString = pauliStringOrig;
323 if (pauliString.size() > GetNumberOfQubits())
324 {
325 for (size_t i = GetNumberOfQubits(); i < pauliString.size(); ++i)
326 {
327 const auto pauliOp = toupper(pauliString[i]);
328 if (pauliOp != 'I' && pauliOp != 'Z')
329 return 0.0;
330 }
331 pauliString.resize(GetNumberOfQubits());
332 }
333 return pathIntegralSimulator->ExpectationValue(pauliString);
334 }
335
336 SimulationType GetSimulationType() const override
337 {
338 return SimulationType::kPathIntegral;
339 }
340
341 void SaveState() override
342 {
343 pathIntegralSimulator->SaveState();
344 }
345
346 void RestoreState() override
347 {
348 pathIntegralSimulator->RestoreState();
349 }
350
351 void SetMultithreading(bool multithreading = true) override
352 {
353 enableMultithreading = multithreading;
354 if (pathIntegralSimulator)
355 {
356 enableMultithreading = false;
357 }
358 }
359
361 {
362 if (GetNumberOfQubits() > sizeof(Types::qubit_t) * 8)
363 std::cerr << "Warning: The number of qubits to measure is larger than the "
364 "number of bits in the Types::qubit_t type, the outcome will be "
365 "undefined"
366 << std::endl;
367 {
368 if (nrQubits < 64)
369 {
370 const auto measured = pathIntegralSimulator->MeasureNoCollapse();
371 Types::qubit_t result = 0;
372 Types::qubit_t mask = 1;
373 for (Types::qubit_t q = 0; q < measured.size(); ++q)
374 {
375 if (measured.get(q))
376 result |= mask;
377 mask <<= 1;
378 }
379 return result;
380 }
381 else
382 {
383 throw std::runtime_error("QCSimState::MeasureNoCollapse: The path integral simulator does "
384 "not "
385 "support measuring more than 63 qubits into 64 bits integers.");
386 }
387 }
388 }
389
390 std::vector<bool> MeasureNoCollapseMany() override
391 {
392 const auto measured = pathIntegralSimulator->MeasureNoCollapse();
393 std::vector<bool> res(nrQubits);
394 for (size_t i = 0; i < nrQubits; ++i)
395 res[i] = measured.get(i);
396 return res;
397 }
398
399 void ApplyP(Types::qubit_t qubit, double lambda) override
400 {
401 pgate.SetPhaseShift(lambda);
402 {
403 QC::Gates::AppliedGate<> agate(pgate.getRawOperatorMatrix(), qubit);
404 pathIntegralSimulator->ApplyGate(agate);
405 }
406 NotifyObservers({qubit});
407 }
408
409 void ApplyX(Types::qubit_t qubit) override
410 {
411 {
412 QC::Gates::AppliedGate<> agate(xgate.getRawOperatorMatrix(), qubit);
413 pathIntegralSimulator->ApplyGate(agate);
414 }
415 NotifyObservers({qubit});
416 }
417
418 void ApplyY(Types::qubit_t qubit) override
419 {
420 {
421 QC::Gates::AppliedGate<> agate(ygate.getRawOperatorMatrix(), qubit);
422 pathIntegralSimulator->ApplyGate(agate);
423 }
424 NotifyObservers({qubit});
425 }
426
427 void ApplyZ(Types::qubit_t qubit) override
428 {
429 {
430 QC::Gates::AppliedGate<> agate(zgate.getRawOperatorMatrix(), qubit);
431 pathIntegralSimulator->ApplyGate(agate);
432 }
433 NotifyObservers({qubit});
434 }
435
436 void ApplyH(Types::qubit_t qubit) override
437 {
438 {
439 QC::Gates::AppliedGate<> agate(h.getRawOperatorMatrix(), qubit);
440 pathIntegralSimulator->ApplyGate(agate);
441 }
442 NotifyObservers({qubit});
443 }
444
445 void ApplyS(Types::qubit_t qubit) override
446 {
447 {
448 QC::Gates::AppliedGate<> agate(sgate.getRawOperatorMatrix(), qubit);
449 pathIntegralSimulator->ApplyGate(agate);
450 }
451 NotifyObservers({qubit});
452 }
453
454 void ApplySDG(Types::qubit_t qubit) override
455 {
456 {
457 QC::Gates::AppliedGate<> agate(sdggate.getRawOperatorMatrix(), qubit);
458 pathIntegralSimulator->ApplyGate(agate);
459 }
460 NotifyObservers({qubit});
461 }
462
463 void ApplyT(Types::qubit_t qubit) override
464 {
465 {
466 QC::Gates::AppliedGate<> agate(tgate.getRawOperatorMatrix(), qubit);
467 pathIntegralSimulator->ApplyGate(agate);
468 }
469 NotifyObservers({qubit});
470 }
471
472 void ApplyTDG(Types::qubit_t qubit) override
473 {
474 {
475 QC::Gates::AppliedGate<> agate(tdggate.getRawOperatorMatrix(), qubit);
476 pathIntegralSimulator->ApplyGate(agate);
477 }
478 NotifyObservers({qubit});
479 }
480
481 void ApplySx(Types::qubit_t qubit) override
482 {
483 {
484 QC::Gates::AppliedGate<> agate(sxgate.getRawOperatorMatrix(), qubit);
485 pathIntegralSimulator->ApplyGate(agate);
486 }
487 NotifyObservers({qubit});
488 }
489
490 void ApplySxDAG(Types::qubit_t qubit) override
491 {
492 {
493 QC::Gates::AppliedGate<> agate(sxdaggate.getRawOperatorMatrix(), qubit);
494 pathIntegralSimulator->ApplyGate(agate);
495 }
496 NotifyObservers({qubit});
497 }
498
499 void ApplyK(Types::qubit_t qubit) override
500 {
501 {
502 QC::Gates::AppliedGate<> agate(k.getRawOperatorMatrix(), qubit);
503 pathIntegralSimulator->ApplyGate(agate);
504 }
505 NotifyObservers({qubit});
506 }
507
508 void ApplyRx(Types::qubit_t qubit, double theta) override
509 {
510 rxgate.SetTheta(theta);
511 {
512 QC::Gates::AppliedGate<> agate(rxgate.getRawOperatorMatrix(), qubit);
513 pathIntegralSimulator->ApplyGate(agate);
514 }
515 NotifyObservers({qubit});
516 }
517
518 void ApplyRy(Types::qubit_t qubit, double theta) override
519 {
520 rygate.SetTheta(theta);
521 {
522 QC::Gates::AppliedGate<> agate(rygate.getRawOperatorMatrix(), qubit);
523 pathIntegralSimulator->ApplyGate(agate);
524 }
525 NotifyObservers({qubit});
526 }
527
528 void ApplyRz(Types::qubit_t qubit, double theta) override
529 {
530 rzgate.SetTheta(theta);
531 {
532 QC::Gates::AppliedGate<> agate(rzgate.getRawOperatorMatrix(), qubit);
533 pathIntegralSimulator->ApplyGate(agate);
534 }
535 NotifyObservers({qubit});
536 }
537
538 void ApplyU(Types::qubit_t qubit, double theta, double phi, double lambda, double gamma) override
539 {
540 ugate.SetParams(theta, phi, lambda, gamma);
541 {
542 QC::Gates::AppliedGate<> agate(ugate.getRawOperatorMatrix(), qubit);
543 pathIntegralSimulator->ApplyGate(agate);
544 }
545 NotifyObservers({qubit});
546 }
547
548 void ApplyCX(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
549 {
550 {
551 QC::Gates::AppliedGate<> agate(cxgate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
552 pathIntegralSimulator->ApplyGate(agate);
553 }
554 NotifyObservers({tgt_qubit, ctrl_qubit});
555 }
556
557 void ApplyCY(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
558 {
559 {
560 QC::Gates::AppliedGate<> agate(cygate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
561 pathIntegralSimulator->ApplyGate(agate);
562 }
563 NotifyObservers({tgt_qubit, ctrl_qubit});
564 }
565
566 void ApplyCZ(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
567 {
568 {
569 QC::Gates::AppliedGate<> agate(czgate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
570 pathIntegralSimulator->ApplyGate(agate);
571 }
572 NotifyObservers({tgt_qubit, ctrl_qubit});
573 }
574
575 void ApplyCP(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double lambda) override
576 {
577 cpgate.SetPhaseShift(lambda);
578 {
579 QC::Gates::AppliedGate<> agate(cpgate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
580 pathIntegralSimulator->ApplyGate(agate);
581 }
582 NotifyObservers({tgt_qubit, ctrl_qubit});
583 }
584
585 void ApplyCRx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
586 {
587 crxgate.SetTheta(theta);
588 {
589 QC::Gates::AppliedGate<> agate(crxgate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
590 pathIntegralSimulator->ApplyGate(agate);
591 }
592 NotifyObservers({tgt_qubit, ctrl_qubit});
593 }
594
595 void ApplyCRy(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
596 {
597 crygate.SetTheta(theta);
598 {
599 QC::Gates::AppliedGate<> agate(crygate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
600 pathIntegralSimulator->ApplyGate(agate);
601 }
602 NotifyObservers({tgt_qubit, ctrl_qubit});
603 }
604
605 void ApplyCRz(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
606 {
607 crzgate.SetTheta(theta);
608 {
609 QC::Gates::AppliedGate<> agate(crzgate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
610 pathIntegralSimulator->ApplyGate(agate);
611 }
612 NotifyObservers({tgt_qubit, ctrl_qubit});
613 }
614
615 void ApplyCH(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
616 {
617 {
618 QC::Gates::AppliedGate<> agate(ch.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
619 pathIntegralSimulator->ApplyGate(agate);
620 }
621 NotifyObservers({tgt_qubit, ctrl_qubit});
622 }
623
624 void ApplyCSx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
625 {
626 {
627 QC::Gates::AppliedGate<> agate(csx.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
628 pathIntegralSimulator->ApplyGate(agate);
629 }
630 NotifyObservers({tgt_qubit, ctrl_qubit});
631 }
632
633 void ApplyCSxDAG(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
634 {
635 {
636 QC::Gates::AppliedGate<> agate(csxdag.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
637 pathIntegralSimulator->ApplyGate(agate);
638 }
639 NotifyObservers({tgt_qubit, ctrl_qubit});
640 }
641
642 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1) override
643 {
644 {
645 QC::Gates::AppliedGate<> agate(swapgate.getRawOperatorMatrix(), qubit1, qubit0);
646 pathIntegralSimulator->ApplyGate(agate);
647 }
648 NotifyObservers({qubit1, qubit0});
649 }
650
651 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1, Types::qubit_t qubit2) override
652 {
653 QC::Gates::AppliedGate<> agate(ccxgate.getRawOperatorMatrix(), qubit2, qubit1, qubit0);
654 pathIntegralSimulator->ApplyGate(agate);
655 NotifyObservers({qubit2, qubit1, qubit0});
656 }
657
658 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0, Types::qubit_t qubit1) override
659 {
660 QC::Gates::AppliedGate<> agate(cswapgate.getRawOperatorMatrix(), qubit1, qubit0, ctrl_qubit);
661 pathIntegralSimulator->ApplyGate(agate);
662 NotifyObservers({qubit1, qubit0, ctrl_qubit});
663 }
664
665 void ApplyCU(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta, double phi, double lambda, double gamma) override
666 {
667 cugate.SetParams(theta, phi, lambda, gamma);
668 {
669 QC::Gates::AppliedGate<> agate(cugate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
670 pathIntegralSimulator->ApplyGate(agate);
671 }
672 NotifyObservers({tgt_qubit, ctrl_qubit});
673 }
674
675 std::unique_ptr<ISimulator> Clone() override
676 {
677 return CloneForExecution(NextCloneSeed());
678 }
679
680 std::unique_ptr<ISimulator> CloneForExecution(uint64_t seed) override
681 {
682 auto cloned = std::make_unique<QCSimPathIntegralSimulator>();
683 cloned->nrQubits = nrQubits;
684 cloned->enableMultithreading = enableMultithreading;
685 cloned->upcomingGates = upcomingGates;
686 cloned->upcomingGateIndex = upcomingGateIndex;
687 if (pathIntegralSimulator)
688 cloned->pathIntegralSimulator = pathIntegralSimulator->Clone();
689 for (const auto &[key, value] : configuration.GetConfigMap())
690 cloned->Configure(key.c_str(), value.c_str());
691 cloned->SetSeed(seed);
692 return cloned;
693 }
694
695 protected:
696 std::unique_ptr<PathIntegralSimulator> pathIntegralSimulator;
697
698 private:
699 template <bool Many> Utils::Sampling::Counts<Many> SamplePrepared(const Types::qubits_vector &qubits, size_t shots)
700 {
701 if (qubits.empty() || !shots)
702 return {};
703 Utils::Sampling::ValidateQubits(qubits, nrQubits, Many);
704 if (shots == 1)
705 {
706 // Native direct sampling already normalizes the retained mass.
707 // Project from the full label, including packed subsets above bit 63.
708 const auto row = pathIntegralSimulator->MeasureNoCollapse();
709 auto result = Utils::Sampling::Single<Many>(qubits.size(), [&](size_t bit) { return row.get(qubits[bit]); });
710 NotifyObservers(qubits);
711 return result;
712 }
713 const auto &amplitudes = pathIntegralSimulator->Amplitudes();
714 auto options = SamplingOptions();
715 const size_t count = amplitudes.size();
716 if (count > (options.memoryBytes - 4096) / (sizeof(double) + sizeof(const uint64_t *)))
717 {
718 // AmplitudeMap only exposes sequential iteration. Sweep bounded
719 // target batches when a random-access snapshot would exceed the
720 // budget, borrowing the original full-width labels as we visit them.
722 amplitudes, shots, qubits.size(), [](const auto &row) { return std::norm(row.second); },
723 [&](const auto &row, size_t bit) { return row.first.get(qubits[bit]); }, [&] { return Utils::RandomStream::Uniform(rng); }, options);
724 NotifyObservers(qubits);
725 return result;
726 }
727 options.memoryBytes -= count * (sizeof(double) + sizeof(const uint64_t *));
728 std::vector<double> probabilities;
729 std::vector<const uint64_t *> labels;
730 probabilities.reserve(count);
731 labels.reserve(count);
732 // Iteration follows AmplitudeMap's stored row order, preserved by copy.
733 // Labels borrow immutable storage for this batch only, never across a
734 // mutation, restore or clone; no wide labels are copied into alias rows.
735 for (const auto &entry : amplitudes)
736 {
737 probabilities.push_back(std::norm(entry.second));
738 labels.push_back(entry.first.getWords());
739 }
740 const Utils::Sampling::Prepared plan(
741 count, shots, [&](size_t row) { return probabilities[row]; }, options);
742 auto result = Utils::Sampling::Count<Many>(
743 plan, shots, qubits.size(),
744 [&](size_t row, size_t bit) {
745 const auto q = qubits[bit];
746 return ((labels[row][q / 64] >> (q % 64)) & 1) != 0;
747 },
748 [&] { return Utils::RandomStream::Uniform(rng); });
749 NotifyObservers(qubits);
750 return result;
751 }
752};
753} // namespace Simulators::Private
754#endif
int ApplyK(void *sim, int qubit)
double Probability(void *sim, unsigned long long int outcome)
int RestoreState(void *sim)
int ApplyRx(void *sim, int qubit, double theta)
int ApplyReset(void *sim, const unsigned long int *qubits, unsigned long int nrQubits)
int ApplyX(void *sim, int qubit)
int ApplyU(void *sim, int qubit, double theta, double phi, double lambda, double gamma)
int ApplyCRy(void *sim, int controlQubit, int targetQubit, double theta)
int ApplyTDG(void *sim, int qubit)
int ApplyS(void *sim, int qubit)
int ApplyCX(void *sim, int controlQubit, int targetQubit)
unsigned long int AllocateQubits(void *sim, unsigned long int nrQubits)
int ApplyCRz(void *sim, int controlQubit, int targetQubit, double theta)
unsigned long int GetNumberOfQubits(void *sim)
double * AllProbabilities(void *sim)
unsigned long long int MeasureNoCollapse(void *sim)
int ApplyCP(void *sim, int controlQubit, int targetQubit, double theta)
int ApplySDG(void *sim, int qubit)
unsigned long long int Measure(void *sim, const unsigned long int *qubits, unsigned long int nrQubits)
int ApplyCSwap(void *sim, int controlQubit, int qubit1, int qubit2)
int ApplyCCX(void *sim, int controlQubit1, int controlQubit2, int targetQubit)
int ApplyY(void *sim, int qubit)
double * Amplitude(void *sim, unsigned long long int outcome)
int ApplyZ(void *sim, int qubit)
int ApplyH(void *sim, int qubit)
int ApplyCY(void *sim, int controlQubit, int targetQubit)
double * Probabilities(void *sim, const unsigned long long int *qubits, unsigned long int nrQubits)
int SetMultithreading(void *sim, int multithreading)
int ApplyCU(void *sim, int controlQubit, int targetQubit, double theta, double phi, double lambda, double gamma)
int ApplySwap(void *sim, int qubit1, int qubit2)
int ApplyRy(void *sim, int qubit, double theta)
int ApplyP(void *sim, int qubit, double theta)
int ApplyCH(void *sim, int controlQubit, int targetQubit)
int GetSimulationType(void *sim)
unsigned long long int * SampleCounts(void *sim, const unsigned long long int *qubits, unsigned long int nrQubits, unsigned long int shots)
int ApplyCZ(void *sim, int controlQubit, int targetQubit)
int ApplyRz(void *sim, int qubit, double theta)
int ApplyT(void *sim, int qubit)
int ApplyCRx(void *sim, int controlQubit, int targetQubit, double theta)
int SaveState(void *sim)
SimulationType
The type of simulation.
Definition State.h:109
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
Definition Types.h:24
uint_fast64_t qubit_t
The type of a qubit.
Definition Types.h:23
Counts< Many > Count(const Plan &plan, size_t shots, size_t bits, const Bit &bit, Uniform &&uniform)
Definition Sampling.h:472
Counts< Many > Single(size_t bits, const Bit &bit)
Definition Sampling.h:375
void ValidateQubits(const Qubits &qubits, size_t width, bool many)
Definition Sampling.h:394
std::unordered_map< std::conditional_t< Many, std::vector< bool >, Types::qubit_t >, Types::qubit_t > Counts
Definition Sampling.h:373
Counts< Many > CountCdfRange(const Range &rows, size_t shots, size_t bits, const Probability &probability, const Bit &bit, Uniform &&uniform, Options options={})
Definition Sampling.h:407