2#if defined(INCLUDED_BY_FACTORY)
5#define _USE_MATH_DEFINES
11class QCSimPathIntegralSimulator :
public QCSimGateSimulator
14 QCSimPathIntegralSimulator()
16 configuration.SetConfiguration(
"method",
"path_integral");
19 const char *MethodName()
const override
21 return "path_integral";
24 void Initialize()
override
28 InitializeSamplingSeed();
30 pathIntegralSimulator = std::make_unique<PathIntegralSimulator>();
31 pathIntegralSimulator->SetStartZeroState(nrQubits);
32 pathIntegralSimulator->SetSeed(samplingSeed);
35 for (
const auto &[key, value] : configuration.GetConfigMap())
37 Configure(key.c_str(), value.c_str());
43 if (pathIntegralSimulator)
45 pathIntegralSimulator->Reset();
46 pathIntegralSimulator->SetStartZeroState(nrQubits);
48 upcomingGateIndex = 0;
51 void Configure(
const char *key,
const char *value)
override
53 if (ConfigureSampling(key, value))
55 if (std::string(
"method") == key)
57 ValidateMethod(value);
58 configuration.SetConfiguration(key, value);
61 if (!configuration.WasApplied(key, value))
62 configuration.SetConfiguration(key, value);
63 if (std::string(
"seed") == key)
65 const uint64_t seed = std::stoull(value);
66 SeedAuxiliaryRng(seed);
68 if (pathIntegralSimulator)
69 pathIntegralSimulator->SetSeed(seed);
72 if (std::string(key) ==
"pauli_propagator_workers")
74 const auto workers = configuration.GetConfigurationAsUnsigned(key);
76 throw std::invalid_argument(
"pauli_propagator_workers exceeds 1024");
78 if (pathIntegralSimulator)
80 if (std::string(key) ==
"path_integral_threshold")
82 pathIntegralSimulator->SetTrimValue(configuration.GetConfigurationAsDouble(key));
89 const size_t oldNrQubits = nrQubits;
90 nrQubits += num_qubits;
96 pathIntegralSimulator =
nullptr;
98 upcomingGateIndex = 0;
99 upcomingGates.clear();
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"
112 for (
size_t qubit : qubits)
114 if (pathIntegralSimulator->MeasureQubit(qubit))
120 NotifyObservers(qubits);
126 std::vector<bool> res(qubits.size(),
false);
129 for (
size_t q = 0; q < qubits.size(); ++q)
130 if (pathIntegralSimulator->MeasureQubit(qubits[q]))
134 NotifyObservers(qubits);
142 for (
size_t qubit : qubits)
143 if (pathIntegralSimulator->MeasureQubit(qubit))
145 QC::Gates::AppliedGate<> gate(xgate.getRawOperatorMatrix(), qubit);
146 pathIntegralSimulator->PropagateStep(gate, pathIntegralSimulator->Amplitudes());
150 NotifyObservers(qubits);
155 return pathIntegralSimulator->Probability(outcome);
160 return pathIntegralSimulator->AmplitudeForOutcome(outcome);
166 std::vector<double> result(nrBasisStates);
167 for (
size_t i = 0; i < nrBasisStates; ++i)
168 result[i] = pathIntegralSimulator->Probability(i);
174 std::vector<double> result(qubits.size());
176 for (
int i = 0; i < static_cast<int>(qubits.size()); ++i)
177 result[i] = pathIntegralSimulator->Probability(qubits[i]);
184 if (!LegacySampling())
185 return SamplePrepared<false>(qubits, shots);
186 if (qubits.empty() || shots == 0)
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"
192 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
199 const auto &litudes = pathIntegralSimulator->Amplitudes();
200 const Utils::Alias alias(amplitudes);
201 for (
size_t shot = 0; shot < shots; ++shot)
203 const double prob = 1. - uniformZeroOne(rng);
204 const size_t measRaw = alias.Sample(prob);
207 for (
auto q : qubits)
209 const size_t qubitMask = 1ULL << q;
210 if ((measRaw & qubitMask) != 0)
222 for (
auto q : qubits)
224 const size_t qubitMask = 1ULL << q;
225 if ((measRaw & qubitMask) != 0)
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.");
239 NotifyObservers(qubits);
245 if (!LegacySampling())
246 return SamplePrepared<true>(qubits, shots);
247 if (qubits.empty() || shots == 0)
256 const auto &litudes = pathIntegralSimulator->Amplitudes();
257 const Utils::Alias alias(amplitudes);
258 for (
size_t shot = 0; shot < shots; ++shot)
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)
271 for (
size_t shot = 0; shot < shots; ++shot)
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]])
286 const auto &litudes = pathIntegralSimulator->Amplitudes();
287 const Utils::AliasBig alias(amplitudes);
288 for (
size_t shot = 0; shot < shots; ++shot)
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]))
301 for (
size_t shot = 0; shot < shots; ++shot)
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]])
314 NotifyObservers(qubits);
318 double ExpectationValue(
const std::string &pauliStringOrig)
override
320 if (pauliStringOrig.empty())
322 std::string pauliString = pauliStringOrig;
327 const auto pauliOp = toupper(pauliString[i]);
328 if (pauliOp !=
'I' && pauliOp !=
'Z')
333 return pathIntegralSimulator->ExpectationValue(pauliString);
338 return SimulationType::kPathIntegral;
343 pathIntegralSimulator->SaveState();
348 pathIntegralSimulator->RestoreState();
353 enableMultithreading = multithreading;
354 if (pathIntegralSimulator)
356 enableMultithreading =
false;
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 "
370 const auto measured = pathIntegralSimulator->MeasureNoCollapse();
383 throw std::runtime_error(
"QCSimState::MeasureNoCollapse: The path integral simulator does "
385 "support measuring more than 63 qubits into 64 bits integers.");
390 std::vector<bool> MeasureNoCollapseMany()
override
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);
401 pgate.SetPhaseShift(lambda);
403 QC::Gates::AppliedGate<> agate(pgate.getRawOperatorMatrix(), qubit);
404 pathIntegralSimulator->ApplyGate(agate);
406 NotifyObservers({qubit});
412 QC::Gates::AppliedGate<> agate(xgate.getRawOperatorMatrix(), qubit);
413 pathIntegralSimulator->ApplyGate(agate);
415 NotifyObservers({qubit});
421 QC::Gates::AppliedGate<> agate(ygate.getRawOperatorMatrix(), qubit);
422 pathIntegralSimulator->ApplyGate(agate);
424 NotifyObservers({qubit});
430 QC::Gates::AppliedGate<> agate(zgate.getRawOperatorMatrix(), qubit);
431 pathIntegralSimulator->ApplyGate(agate);
433 NotifyObservers({qubit});
439 QC::Gates::AppliedGate<> agate(h.getRawOperatorMatrix(), qubit);
440 pathIntegralSimulator->ApplyGate(agate);
442 NotifyObservers({qubit});
448 QC::Gates::AppliedGate<> agate(sgate.getRawOperatorMatrix(), qubit);
449 pathIntegralSimulator->ApplyGate(agate);
451 NotifyObservers({qubit});
457 QC::Gates::AppliedGate<> agate(sdggate.getRawOperatorMatrix(), qubit);
458 pathIntegralSimulator->ApplyGate(agate);
460 NotifyObservers({qubit});
466 QC::Gates::AppliedGate<> agate(tgate.getRawOperatorMatrix(), qubit);
467 pathIntegralSimulator->ApplyGate(agate);
469 NotifyObservers({qubit});
475 QC::Gates::AppliedGate<> agate(tdggate.getRawOperatorMatrix(), qubit);
476 pathIntegralSimulator->ApplyGate(agate);
478 NotifyObservers({qubit});
484 QC::Gates::AppliedGate<> agate(sxgate.getRawOperatorMatrix(), qubit);
485 pathIntegralSimulator->ApplyGate(agate);
487 NotifyObservers({qubit});
493 QC::Gates::AppliedGate<> agate(sxdaggate.getRawOperatorMatrix(), qubit);
494 pathIntegralSimulator->ApplyGate(agate);
496 NotifyObservers({qubit});
502 QC::Gates::AppliedGate<> agate(k.getRawOperatorMatrix(), qubit);
503 pathIntegralSimulator->ApplyGate(agate);
505 NotifyObservers({qubit});
510 rxgate.SetTheta(theta);
512 QC::Gates::AppliedGate<> agate(rxgate.getRawOperatorMatrix(), qubit);
513 pathIntegralSimulator->ApplyGate(agate);
515 NotifyObservers({qubit});
520 rygate.SetTheta(theta);
522 QC::Gates::AppliedGate<> agate(rygate.getRawOperatorMatrix(), qubit);
523 pathIntegralSimulator->ApplyGate(agate);
525 NotifyObservers({qubit});
530 rzgate.SetTheta(theta);
532 QC::Gates::AppliedGate<> agate(rzgate.getRawOperatorMatrix(), qubit);
533 pathIntegralSimulator->ApplyGate(agate);
535 NotifyObservers({qubit});
538 void ApplyU(
Types::qubit_t qubit,
double theta,
double phi,
double lambda,
double gamma)
override
540 ugate.SetParams(theta, phi, lambda, gamma);
542 QC::Gates::AppliedGate<> agate(ugate.getRawOperatorMatrix(), qubit);
543 pathIntegralSimulator->ApplyGate(agate);
545 NotifyObservers({qubit});
551 QC::Gates::AppliedGate<> agate(cxgate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
552 pathIntegralSimulator->ApplyGate(agate);
554 NotifyObservers({tgt_qubit, ctrl_qubit});
560 QC::Gates::AppliedGate<> agate(cygate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
561 pathIntegralSimulator->ApplyGate(agate);
563 NotifyObservers({tgt_qubit, ctrl_qubit});
569 QC::Gates::AppliedGate<> agate(czgate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
570 pathIntegralSimulator->ApplyGate(agate);
572 NotifyObservers({tgt_qubit, ctrl_qubit});
577 cpgate.SetPhaseShift(lambda);
579 QC::Gates::AppliedGate<> agate(cpgate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
580 pathIntegralSimulator->ApplyGate(agate);
582 NotifyObservers({tgt_qubit, ctrl_qubit});
587 crxgate.SetTheta(theta);
589 QC::Gates::AppliedGate<> agate(crxgate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
590 pathIntegralSimulator->ApplyGate(agate);
592 NotifyObservers({tgt_qubit, ctrl_qubit});
597 crygate.SetTheta(theta);
599 QC::Gates::AppliedGate<> agate(crygate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
600 pathIntegralSimulator->ApplyGate(agate);
602 NotifyObservers({tgt_qubit, ctrl_qubit});
607 crzgate.SetTheta(theta);
609 QC::Gates::AppliedGate<> agate(crzgate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
610 pathIntegralSimulator->ApplyGate(agate);
612 NotifyObservers({tgt_qubit, ctrl_qubit});
618 QC::Gates::AppliedGate<> agate(ch.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
619 pathIntegralSimulator->ApplyGate(agate);
621 NotifyObservers({tgt_qubit, ctrl_qubit});
627 QC::Gates::AppliedGate<> agate(csx.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
628 pathIntegralSimulator->ApplyGate(agate);
630 NotifyObservers({tgt_qubit, ctrl_qubit});
636 QC::Gates::AppliedGate<> agate(csxdag.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
637 pathIntegralSimulator->ApplyGate(agate);
639 NotifyObservers({tgt_qubit, ctrl_qubit});
645 QC::Gates::AppliedGate<> agate(swapgate.getRawOperatorMatrix(), qubit1, qubit0);
646 pathIntegralSimulator->ApplyGate(agate);
648 NotifyObservers({qubit1, qubit0});
653 QC::Gates::AppliedGate<> agate(ccxgate.getRawOperatorMatrix(), qubit2, qubit1, qubit0);
654 pathIntegralSimulator->ApplyGate(agate);
655 NotifyObservers({qubit2, qubit1, qubit0});
660 QC::Gates::AppliedGate<> agate(cswapgate.getRawOperatorMatrix(), qubit1, qubit0, ctrl_qubit);
661 pathIntegralSimulator->ApplyGate(agate);
662 NotifyObservers({qubit1, qubit0, ctrl_qubit});
667 cugate.SetParams(theta, phi, lambda, gamma);
669 QC::Gates::AppliedGate<> agate(cugate.getRawOperatorMatrix(), tgt_qubit, ctrl_qubit);
670 pathIntegralSimulator->ApplyGate(agate);
672 NotifyObservers({tgt_qubit, ctrl_qubit});
675 std::unique_ptr<ISimulator> Clone()
override
677 return CloneForExecution(NextCloneSeed());
680 std::unique_ptr<ISimulator> CloneForExecution(uint64_t seed)
override
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);
696 std::unique_ptr<PathIntegralSimulator> pathIntegralSimulator;
701 if (qubits.empty() || !shots)
708 const auto row = pathIntegralSimulator->MeasureNoCollapse();
710 NotifyObservers(qubits);
713 const auto &litudes = 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 *)))
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);
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);
735 for (
const auto &entry : amplitudes)
737 probabilities.push_back(std::norm(entry.second));
738 labels.push_back(entry.first.getWords());
740 const Utils::Sampling::Prepared plan(
741 count, shots, [&](
size_t row) {
return probabilities[row]; }, options);
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;
748 [&] { return Utils::RandomStream::Uniform(rng); });
749 NotifyObservers(qubits);
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)
SimulationType
The type of simulation.
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
uint_fast64_t qubit_t
The type of a qubit.
Counts< Many > Count(const Plan &plan, size_t shots, size_t bits, const Bit &bit, Uniform &&uniform)
Counts< Many > Single(size_t bits, const Bit &bit)
void ValidateQubits(const Qubits &qubits, size_t width, bool many)
std::unordered_map< std::conditional_t< Many, std::vector< bool >, Types::qubit_t >, Types::qubit_t > Counts
Counts< Many > CountCdfRange(const Range &rows, size_t shots, size_t bits, const Probability &probability, const Bit &bit, Uniform &&uniform, Options options={})