Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
QuestState.h
Go to the documentation of this file.
1
12
13#pragma once
14
15#ifndef _QUESTSTATE_H_
16#define _QUESTSTATE_H_
17
18#ifdef INCLUDED_BY_FACTORY
19
21#include "QuestLibSim.h"
22
23#include <random>
24#include <unordered_map>
25#include <vector>
26
28
29namespace Simulators
30{
31namespace Private
32{
43class QuestState : public ISimulator
44{
45 public:
46 QuestState() : rng(std::random_device{}()), uniformZeroOne(0, 1)
47 {
48 }
49
57 void Initialize() override
58 {
59 if (!questLib)
60 questLib = SimulatorsFactory::GetQuestLibrary();
61 if (nrQubits && questLib && questLib->IsValid())
62 {
63 simHandle = questLib->CreateSimulator(static_cast<int>(nrQubits));
64 sim = questLib->GetSimulator(simHandle);
65 if (!sim)
66 throw std::runtime_error("QuestState::Initialize: Failed to create "
67 "and initialize the statevector state.");
68 }
69 }
70
82 void InitializeState(size_t num_qubits, std::vector<std::complex<double>> &amplitudes) override
83 {
84 throw std::runtime_error("QuestState::InitializeState: Not supported for Quest simulator.");
85 }
86
98#ifndef NO_QISKIT_AER
99 void InitializeState(size_t num_qubits, AER::Vector<std::complex<double>> &amplitudes) override
100 {
101 throw std::runtime_error("QuestState::InitializeState: Not supported for Quest simulator.");
102 }
103#endif
104
116 void InitializeState(size_t num_qubits, Eigen::VectorXcd &amplitudes) override
117 {
118 throw std::runtime_error("QuestState::InitializeState: Not supported for Quest simulator.");
119 }
120
127 void Reset() override
128 {
129 if (sim && questLib)
130 {
131 questLib->DestroySimulator(simHandle);
132 simHandle = questLib->CreateSimulator(static_cast<int>(nrQubits));
133 sim = questLib->GetSimulator(simHandle);
134 }
135 }
136
146 void Configure(const char *key, const char *value) override
147 {
148 if (std::string("seed") == key)
149 {
150 const uint64_t seed = std::stoull(value);
151 SeedAuxiliaryRng(seed);
152 rng.seed(seed);
153 configuration.SetConfiguration(key, value);
154 }
155 }
156
164 std::string GetConfiguration(const char *key) const override
165 {
166 if (std::string("method") == key)
167 return "statevector";
168 return configuration.GetConfiguration(key);
169 }
170
178 size_t AllocateQubits(size_t num_qubits) override
179 {
180 if (sim)
181 return 0;
182
183 const size_t oldNrQubits = nrQubits;
184 nrQubits += num_qubits;
185
186 return oldNrQubits;
187 }
188
195 size_t GetNumberOfQubits() const override
196 {
197 return nrQubits;
198 }
199
207 void Clear() override
208 {
209 if (sim && questLib)
210 {
211 questLib->DestroySimulator(simHandle);
212 sim = nullptr;
213 simHandle = 0;
214 }
215 if (savedSim && questLib)
216 {
217 questLib->DestroySimulator(savedSimHandle);
218 savedSim = nullptr;
219 savedSimHandle = 0;
220 }
221 nrQubits = 0;
222 }
223
234 size_t Measure(const Types::qubits_vector &qubits) override
235 {
236 if (qubits.size() > sizeof(size_t) * 8)
237 std::cerr << "Warning: The number of qubits to measure is larger than the "
238 "number of bits in the size_t type, the outcome will be undefined"
239 << std::endl;
240
241 DontNotify();
242
243 std::vector<int> qb(qubits.begin(), qubits.end());
244 const size_t res = static_cast<size_t>(questLib->MeasureQubits(sim, qb.data(), static_cast<int>(qubits.size())));
245
246 Notify();
247 NotifyObservers(qubits);
248
249 return res;
250 }
251
258 std::vector<bool> MeasureMany(const Types::qubits_vector &qubits) override
259 {
260 std::vector<bool> res(qubits.size(), false);
261
262 DontNotify();
263
264 std::vector<int> qb(qubits.begin(), qubits.end());
265 const size_t resm = static_cast<size_t>(questLib->MeasureQubits(sim, qb.data(), static_cast<int>(qubits.size())));
266
267 size_t mask = 1ULL;
268 for (size_t i = 0; i < qubits.size(); ++i)
269 {
270 res[i] = (resm & mask) != 0;
271 mask <<= 1;
272 }
273
274 Notify();
275 NotifyObservers(qubits);
276
277 return res;
278 }
279
286 void ApplyReset(const Types::qubits_vector &qubits) override
287 {
288 DontNotify();
289 std::vector<int> qb(qubits.begin(), qubits.end());
290 const size_t res = static_cast<size_t>(questLib->MeasureQubits(sim, qb.data(), static_cast<int>(qubits.size())));
291 size_t mask = 1ULL;
292 for (size_t i = 0; i < qubits.size(); ++i)
293 {
294 if (res & mask)
295 questLib->ApplyX(sim, static_cast<int>(qubits[i]));
296 mask <<= 1;
297 }
298
299 Notify();
300 NotifyObservers(qubits);
301 }
302
314 double Probability(Types::qubit_t outcome) override
315 {
316 return questLib->GetOutcomeProbability(sim, static_cast<long long int>(outcome));
317 }
318
329 std::complex<double> Amplitude(Types::qubit_t outcome) override
330 {
331 std::complex<double> amplitude;
332 if (questLib->GetAmplitude(sim, static_cast<long long int>(outcome), amplitude))
333 {
334 return amplitude;
335 }
336 return std::complex<double>(0.0, 0.0);
337 }
338
352 std::complex<double> ProjectOnZero() override
353 {
354 return Amplitude(0);
355 }
356
367 std::vector<double> AllProbabilities() override
368 {
369 if (nrQubits == 0)
370 return {};
371 const size_t numStates = 1ULL << nrQubits;
372 std::vector<std::complex<double>> amplitudes(numStates);
373 questLib->GetAmplitudes(sim, amplitudes);
374
375 std::vector<double> result(numStates);
376 for (size_t i = 0; i < numStates; ++i)
377 result[i] = std::norm(amplitudes[i]);
378 return result;
379 }
380
392 std::vector<double> Probabilities(const Types::qubits_vector &qubits) override
393 {
394 std::vector<double> result(qubits.size());
395 for (size_t i = 0; i < qubits.size(); ++i)
396 result[i] = questLib->GetOutcomeProbability(sim, static_cast<long long int>(qubits[i]));
397 return result;
398 }
399
416 std::unordered_map<Types::qubit_t, Types::qubit_t> SampleCounts(const Types::qubits_vector &qubits, size_t shots = 1000) override
417 {
418 if (qubits.empty() || shots == 0)
419 return {};
420
421 if (qubits.size() > sizeof(Types::qubit_t) * 8)
422 std::cerr << "Warning: The number of qubits to measure is larger than the "
423 "number of bits in the Types::qubit_t type, the outcome will be "
424 "undefined"
425 << std::endl;
426
427 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
428
429 if (shots > 1)
430 {
431 const size_t numStates = 1ULL << nrQubits;
432 std::vector<std::complex<double>> amplitudes(numStates);
433 questLib->GetAmplitudes(sim, amplitudes);
434
435 const Utils::Alias alias(amplitudes);
436
437 for (size_t shot = 0; shot < shots; ++shot)
438 {
439 const double prob = 1. - uniformZeroOne(rng);
440 const size_t measRaw = alias.Sample(prob);
441
442 size_t meas = 0;
443 size_t mask = 1ULL;
444 for (auto q : qubits)
445 {
446 const size_t qubitMask = 1ULL << q;
447 if ((measRaw & qubitMask) != 0)
448 meas |= mask;
449 mask <<= 1ULL;
450 }
451
452 ++result[meas];
453 }
454 }
455 else
456 {
457 for (size_t shot = 0; shot < shots; ++shot)
458 {
459 const size_t measRaw = MeasureNoCollapse();
460 size_t meas = 0;
461 size_t mask = 1ULL;
462
463 for (auto q : qubits)
464 {
465 const size_t qubitMask = 1ULL << q;
466 if ((measRaw & qubitMask) != 0)
467 meas |= mask;
468 mask <<= 1ULL;
469 }
470
471 ++result[meas];
472 }
473 }
474
475 Notify();
476 NotifyObservers(qubits);
477
478 return result;
479 }
480
494 std::unordered_map<std::vector<bool>, Types::qubit_t> SampleCountsMany(const Types::qubits_vector &qubits, size_t shots = 1000) override
495 {
496 if (qubits.empty() || shots == 0)
497 return {};
498
499 std::unordered_map<std::vector<bool>, Types::qubit_t> result;
500
501 if (shots > 1)
502 {
503 const size_t numStates = 1ULL << nrQubits;
504 std::vector<std::complex<double>> amplitudes(numStates);
505 questLib->GetAmplitudes(sim, amplitudes);
506
507 const Utils::Alias alias(amplitudes);
508
509 for (size_t shot = 0; shot < shots; ++shot)
510 {
511 const double prob = 1. - uniformZeroOne(rng);
512 const size_t measRaw = alias.Sample(prob);
513
514 std::vector<bool> meas(qubits.size(), false);
515
516 for (size_t i = 0; i < qubits.size(); ++i)
517 if (((measRaw >> qubits[i]) & 1) == 1)
518 meas[i] = true;
519
520 ++result[meas];
521 }
522 }
523 else
524 {
525 for (size_t shot = 0; shot < shots; ++shot)
526 {
527 const auto measRaw = MeasureNoCollapseMany();
528 std::vector<bool> meas(qubits.size(), false);
529
530 for (size_t i = 0; i < qubits.size(); ++i)
531 if (measRaw[qubits[i]])
532 meas[i] = true;
533
534 ++result[meas];
535 }
536 }
537
538 Notify();
539 NotifyObservers(qubits);
540
541 return result;
542 }
543
555 double ExpectationValue(const std::string &pauliString) override
556 {
557 return questLib->GetExpectationValue(sim, pauliString.c_str());
558 }
559
567 SimulatorType GetType() const override
568 {
569 return SimulatorType::kQuestSim;
570 }
571
580 SimulationType GetSimulationType() const override
581 {
582 return SimulationType::kStatevector;
583 }
584
591 void Flush() override
592 {
593 }
594
603 void SaveStateToInternalDestructive() override
604 {
605 if (savedSim && questLib)
606 {
607 questLib->DestroySimulator(savedSimHandle);
608 savedSim = nullptr;
609 savedSimHandle = 0;
610 }
611 savedSimHandle = simHandle;
612 simHandle = 0;
613 savedSim = sim;
614 sim = nullptr;
615 }
616
624 {
625 if (sim && questLib)
626 questLib->DestroySimulator(simHandle);
627 simHandle = savedSimHandle;
628 sim = savedSim;
629 savedSimHandle = 0;
630 savedSim = nullptr;
631 }
632
641 void SaveState() override
642 {
643 if (savedSim && questLib)
644 {
645 questLib->DestroySimulator(savedSimHandle);
646 savedSim = nullptr;
647 savedSimHandle = 0;
648 }
649 savedSimHandle = questLib->CloneSimulator(sim);
650 savedSim = questLib->GetSimulator(savedSimHandle);
651 }
652
660 void RestoreState() override
661 {
662 if (sim && questLib)
663 questLib->DestroySimulator(simHandle);
664 simHandle = questLib->CloneSimulator(savedSim);
665 sim = questLib->GetSimulator(simHandle);
666 }
667
673 std::complex<double> AmplitudeRaw(Types::qubit_t outcome) override
674 {
675 return Amplitude(outcome);
676 }
677
686 void SetMultithreading(bool multithreading = true) override
687 {
688 // Quest manages its own threading
689 }
690
698 bool GetMultithreading() const override
699 {
700 return true;
701 }
702
710 bool IsQcsim() const override
711 {
712 return false;
713 }
714
729 {
730 if (nrQubits > sizeof(Types::qubit_t) * 8)
731 std::cerr << "Warning: The number of qubits to measure is larger than the "
732 "number of bits in the Types::qubit_t type, the outcome will be "
733 "undefined"
734 << std::endl;
735
736 const size_t numStates = 1ULL << nrQubits;
737 std::vector<std::complex<double>> amplitudes(numStates);
738 questLib->GetAmplitudes(sim, amplitudes);
739
740 std::vector<double> probs(numStates);
741 for (size_t i = 0; i < numStates; ++i)
742 probs[i] = std::norm(amplitudes[i]);
743
744 std::discrete_distribution<Types::qubit_t> dist(probs.begin(), probs.end());
745
746 return dist(rng);
747 }
748
760 std::vector<bool> MeasureNoCollapseMany() override
761 {
762 const auto meas = MeasureNoCollapse();
763 std::vector<bool> result(nrQubits, false);
764 for (size_t i = 0; i < nrQubits; ++i)
765 result[i] = ((meas >> i) & 1) == 1;
766 return result;
767 }
768
769 const Configuration &GetConfiguration() const
770 {
771 return configuration;
772 }
773
774 const std::unordered_map<std::string, std::string> &GetConfigMap() const override
775 {
776 return configuration.GetConfigMap();
777 }
778
779 protected:
780 std::shared_ptr<QuestLibSim> questLib;
781 unsigned long int simHandle = 0;
782 void *sim = nullptr;
783 size_t nrQubits = 0;
784 unsigned long int savedSimHandle = 0;
785 void *savedSim = nullptr;
786 std::mt19937_64 rng;
787 std::uniform_real_distribution<double> uniformZeroOne;
788
789 Configuration configuration;
790};
791} // namespace Private
792} // namespace Simulators
793
794#endif
795
796#endif // _QUESTSTATE_H_
double Probability(void *sim, unsigned long long int outcome)
char * GetConfiguration(void *sim, const char *key)
int RestoreState(void *sim)
int ApplyReset(void *sim, const unsigned long int *qubits, unsigned long int nrQubits)
unsigned long int AllocateQubits(void *sim, unsigned long int nrQubits)
unsigned long int GetNumberOfQubits(void *sim)
double * AllProbabilities(void *sim)
unsigned long long int MeasureNoCollapse(void *sim)
int GetMultithreading(void *sim)
unsigned long long int Measure(void *sim, const unsigned long int *qubits, unsigned long int nrQubits)
double * Amplitude(void *sim, unsigned long long int outcome)
double * Probabilities(void *sim, const unsigned long long int *qubits, unsigned long int nrQubits)
int SetMultithreading(void *sim, int multithreading)
int SaveStateToInternalDestructive(void *sim)
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 RestoreInternalDestructiveSavedState(void *sim)
int IsQcsim(void *sim)
int SaveState(void *sim)
size_t Sample(double v) const
Definition Alias.h:110
Bounded online routing based on current physical bond dimensions.
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