Maestro 0.2.5
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
GpuState.h
Go to the documentation of this file.
1
13#pragma once
14
15#ifndef _GPUSTATE_H_
16#define _GPUSTATE_H_
17
18#ifdef __linux__
19
20#ifdef INCLUDED_BY_FACTORY
21
22namespace Simulators {
23// TODO: Maybe use the pimpl idiom
24// https://en.cppreference.com/w/cpp/language/pimpl to hide the implementation
25// for good but during development this should be good enough
26namespace Private {
27
38class GpuState : public ISimulator {
39 public:
47 void Initialize() override {
48 if (nrQubits) {
49 if (simulationType == SimulationType::kStatevector) {
50 state = SimulatorsFactory::CreateGpuLibStateVectorSim();
51 if (state) {
52 const bool res = state->Create(nrQubits);
53 if (!res)
54 throw std::runtime_error(
55 "GpuState::Initialize: Failed to create "
56 "and initialize the statevector state.");
57 } else
58 throw std::runtime_error(
59 "GpuState::Initialize: Failed to create the statevector state.");
60 } else if (simulationType == SimulationType::kMatrixProductState) {
61 mps = SimulatorsFactory::CreateGpuLibMPSSim();
62 if (mps) {
63 if (useDoublePrecision) mps->SetDataType(true);
64 if (limitEntanglement && singularValueThreshold > 0.)
65 mps->SetCutoff(singularValueThreshold);
66 if (limitSize && chi > 0) mps->SetMaxExtent(chi);
67 const bool res = mps->Create(nrQubits);
68 if (!res)
69 throw std::runtime_error(
70 "GpuState::Initialize: Failed to create "
71 "and initialize the MPS state.");
72 } else
73 throw std::runtime_error(
74 "GpuState::Initialize: Failed to create the MPS state.");
75 } else if (simulationType == SimulationType::kTensorNetwork) {
76 tn = SimulatorsFactory::CreateGpuLibTensorNetSim();
77 if (tn) {
78 const bool res = tn->Create(nrQubits);
79 if (!res)
80 throw std::runtime_error(
81 "GpuState::Initialize: Failed to create "
82 "and initialize the tensor network state.");
83 } else
84 throw std::runtime_error(
85 "GpuState::Initialize: Failed to create the tensor network "
86 "state.");
87 } else if (simulationType == SimulationType::kPauliPropagator) {
88 pp = SimulatorsFactory::CreateGpuPauliPropagatorSimulatorUnique();
89 if (pp) {
90 const bool res = pp->CreateSimulator(nrQubits);
91 if (!res)
92 throw std::runtime_error(
93 "GpuState::Initialize: Failed to create "
94 "and initialize the Pauli propagator state.");
95
96 pp->SetWillUseSampling(true); // TODO: check setting
97 if (!pp->AllocateMemory(0.9))
98 throw std::runtime_error(
99 "GpuState::Initialize: Failed to allocate memory for the "
100 "Pauli propagator state.");
101 } else
102 throw std::runtime_error(
103 "GpuState::Initialize: Failed to create the Pauli propagator "
104 "state.");
105 } else
106 throw std::runtime_error(
107 "GpuState::Initialize: Invalid simulation "
108 "type for initializing the state.");
109 }
110 }
111
123 void InitializeState(size_t num_qubits,
124 std::vector<std::complex<double>> &amplitudes) override {
125 if (num_qubits == 0) return;
126 Clear();
127 nrQubits = num_qubits;
128 Initialize();
129
130 if (simulationType != SimulationType::kStatevector)
131 throw std::runtime_error(
132 "GpuState::InitializeState: Invalid simulation "
133 "type for initializing the state.");
134
135 if (nrQubits) {
136 if (simulationType == SimulationType::kStatevector) {
137 state = SimulatorsFactory::CreateGpuLibStateVectorSim();
138 if (state)
139 state->CreateWithState(
140 nrQubits, reinterpret_cast<const double *>(amplitudes.data()));
141 }
142 }
143 }
144
156#ifndef NO_QISKIT_AER
157 void InitializeState(size_t num_qubits,
158 AER::Vector<std::complex<double>> &amplitudes) override {
159 if (num_qubits == 0) return;
160 Clear();
161 nrQubits = num_qubits;
162 Initialize();
163
164 if (simulationType != SimulationType::kStatevector)
165 throw std::runtime_error(
166 "GpuState::InitializeState: Invalid simulation "
167 "type for initializing the state.");
168
169 if (nrQubits) {
170 if (simulationType == SimulationType::kStatevector) {
171 state = SimulatorsFactory::CreateGpuLibStateVectorSim();
172 if (state)
173 state->CreateWithState(
174 nrQubits, reinterpret_cast<const double *>(amplitudes.data()));
175 }
176 }
177 }
178#endif
179
191 void InitializeState(size_t num_qubits,
192 Eigen::VectorXcd &amplitudes) override {
193 if (num_qubits == 0) return;
194 Clear();
195 nrQubits = num_qubits;
196 Initialize();
197
198 if (simulationType != SimulationType::kStatevector)
199 throw std::runtime_error(
200 "GpuState::InitializeState: Invalid simulation "
201 "type for initializing the state.");
202
203 if (nrQubits) {
204 if (simulationType == SimulationType::kStatevector) {
205 state = SimulatorsFactory::CreateGpuLibStateVectorSim();
206 if (state)
207 state->CreateWithState(
208 nrQubits, reinterpret_cast<const double *>(amplitudes.data()));
209 }
210 }
211 }
212
219 void Reset() override {
220 if (state)
221 state->Reset();
222 else if (mps)
223 mps->Reset();
224 else if (tn)
225 tn->Reset();
226 else if (pp)
227 pp->ClearOperators();
228 }
229
238 void SetInitialQubitsMap(
239 const std::vector<long long int> &initialMap) override {
240 if (mps) mps->SetInitialQubitsMap(initialMap);
241 }
242
251 void Configure(const char *key, const char *value) override {
252 if (std::string("method") == key) {
253 if (std::string("statevector") == value)
254 simulationType = SimulationType::kStatevector;
255 else if (std::string("matrix_product_state") == value)
256 simulationType = SimulationType::kMatrixProductState;
257 else if (std::string("tensor_network") == value)
258 simulationType = SimulationType::kTensorNetwork;
259 else if (std::string("pauli_propagator") == value)
260 simulationType = SimulationType::kPauliPropagator;
261 } else if (std::string("matrix_product_state_truncation_threshold") ==
262 key) {
263 singularValueThreshold = std::stod(value);
264 if (singularValueThreshold > 0.) {
265 limitEntanglement = true;
266 if (mps) mps->SetCutoff(singularValueThreshold);
267 if (tn) tn->SetCutoff(singularValueThreshold);
268 } else
269 limitEntanglement = false;
270 } else if (std::string("matrix_product_state_max_bond_dimension") == key) {
271 chi = std::stoi(value);
272 if (chi > 0) {
273 limitSize = true;
274 if (mps) mps->SetMaxExtent(chi);
275 if (tn) tn->SetMaxExtent(chi);
276 } else
277 limitSize = false;
278 } else if (std::string("use_double_precision") == key) {
279 useDoublePrecision =
280 (std::string("1") == value || std::string("true") == value);
281 }
282 // TODO: add pauli propagator configuration options
283 }
284
292 std::string GetConfiguration(const char *key) const override {
293 if (std::string("method") == key) {
294 switch (simulationType) {
295 case SimulationType::kStatevector:
296 return "statevector";
297 case SimulationType::kMatrixProductState:
298 return "matrix_product_state";
299 case SimulationType::kTensorNetwork:
300 return "tensor_network";
301 case SimulationType::kPauliPropagator:
302 return "pauli_propagator";
303 default:
304 return "other";
305 }
306 } else if (std::string("matrix_product_state_truncation_threshold") ==
307 key) {
308 if (limitEntanglement && singularValueThreshold > 0.)
309 return std::to_string(singularValueThreshold);
310 } else if (std::string("matrix_product_state_max_bond_dimension") == key) {
311 if (limitSize && limitSize > 0) return std::to_string(chi);
312 }
313 // TODO: add pauli propagator configuration options
314
315 return "";
316 }
317
325 size_t AllocateQubits(size_t num_qubits) override {
326 if ((simulationType == SimulationType::kStatevector && state) ||
327 (simulationType == SimulationType::kMatrixProductState && mps) ||
328 (simulationType == SimulationType::kPauliPropagator && pp))
329 return 0;
330
331 const size_t oldNrQubits = nrQubits;
332 nrQubits += num_qubits;
333
334 return oldNrQubits;
335 }
336
343 size_t GetNumberOfQubits() const override { return nrQubits; }
344
352 void Clear() override {
353 state = nullptr;
354 mps = nullptr;
355 tn = nullptr;
356 pp = nullptr;
357 nrQubits = 0;
358 }
359
370 size_t Measure(const Types::qubits_vector &qubits) override {
371 // TODO: this is inefficient, maybe implement it better in gpu sim
372 // for now it has the possibility of measuring a qubits interval, but not a
373 // list of qubits
374 if (qubits.size() > sizeof(size_t) * 8)
375 std::cerr
376 << "Warning: The number of qubits to measure is larger than the "
377 "number of bits in the size_t type, the outcome will be undefined"
378 << std::endl;
379
380 size_t res = 0;
381 size_t mask = 1ULL;
382
383 DontNotify();
384 if (simulationType == SimulationType::kStatevector) {
385 // TODO: measure all qubits in one shot?
386 for (size_t qubit : qubits) {
387 if (state->MeasureQubitCollapse(static_cast<int>(qubit))) res |= mask;
388 mask <<= 1;
389 }
390 } else if (simulationType == SimulationType::kMatrixProductState) {
391 // TODO: measure all qubits in one shot?
392 for (size_t qubit : qubits) {
393 if (mps->Measure(static_cast<unsigned int>(qubit))) res |= mask;
394 mask <<= 1;
395 }
396 } else if (simulationType == SimulationType::kTensorNetwork) {
397 // TODO: measure all qubits in one shot?
398 for (size_t qubit : qubits) {
399 if (tn->Measure(static_cast<unsigned int>(qubit))) res |= mask;
400 mask <<= 1;
401 }
402 } else if (simulationType == SimulationType::kPauliPropagator) {
403 // TODO: measure all qubits in one shot?
404 for (size_t qubit : qubits) {
405 if (pp->MeasureQubit(static_cast<int>(qubit))) res |= mask;
406 mask <<= 1;
407 }
408 }
409
410 Notify();
411 NotifyObservers(qubits);
412
413 return res;
414 }
415
422 std::vector<bool> MeasureMany(const Types::qubits_vector &qubits) override {
423 std::vector<bool> res(qubits.size(), false);
424
425 DontNotify();
426 if (simulationType == SimulationType::kStatevector) {
427 for (size_t i = 0; i < qubits.size(); ++i)
428 res[i] = state->MeasureQubitCollapse(static_cast<int>(qubits[i]));
429 } else if (simulationType == SimulationType::kMatrixProductState) {
430 for (size_t i = 0; i < qubits.size(); ++i)
431 res[i] = mps->Measure(static_cast<unsigned int>(qubits[i]));
432 } else if (simulationType == SimulationType::kTensorNetwork) {
433 for (size_t i = 0; i < qubits.size(); ++i)
434 res[i] = tn->Measure(static_cast<unsigned int>(qubits[i]));
435 } else if (simulationType == SimulationType::kPauliPropagator) {
436 for (size_t i = 0; i < qubits.size(); ++i)
437 res[i] = pp->MeasureQubit(static_cast<int>(qubits[i]));
438 }
439 Notify();
440 NotifyObservers(qubits);
441
442 return res;
443 }
444
451 void ApplyReset(const Types::qubits_vector &qubits) override {
452 DontNotify();
453 if (simulationType == SimulationType::kStatevector) {
454 for (size_t qubit : qubits)
455 if (state->MeasureQubitCollapse(static_cast<int>(qubit)))
456 state->ApplyX(static_cast<int>(qubit));
457 } else if (simulationType == SimulationType::kMatrixProductState) {
458 for (size_t qubit : qubits)
459 if (mps->Measure(static_cast<unsigned int>(qubit)))
460 mps->ApplyX(static_cast<unsigned int>(qubit));
461 } else if (simulationType == SimulationType::kTensorNetwork) {
462 for (size_t qubit : qubits)
463 if (tn->Measure(static_cast<unsigned int>(qubit)))
464 tn->ApplyX(static_cast<unsigned int>(qubit));
465 } else if (simulationType == SimulationType::kPauliPropagator) {
466 for (size_t qubit : qubits)
467 if (pp->MeasureQubit(static_cast<int>(qubit)))
468 pp->ApplyX(static_cast<int>(qubit));
469 }
470
471 Notify();
472 NotifyObservers(qubits);
473 }
474
486 double Probability(Types::qubit_t outcome) override {
487 if (simulationType == SimulationType::kStatevector)
488 return state->BasisStateProbability(outcome);
489 else if (simulationType == SimulationType::kMatrixProductState ||
490 simulationType == SimulationType::kTensorNetwork) {
491 const auto ampl = Amplitude(outcome);
492 return std::norm(ampl);
493 } else if (simulationType == SimulationType::kPauliPropagator) {
494 return pp->Probability(outcome);
495 }
496
497 return 0.0;
498 }
499
510 std::complex<double> Amplitude(Types::qubit_t outcome) override {
511 double real = 0.0;
512 double imag = 0.0;
513
514 if (simulationType == SimulationType::kStatevector)
515 state->Amplitude(outcome, &real, &imag);
516 else if (simulationType == SimulationType::kMatrixProductState ||
517 simulationType == SimulationType::kTensorNetwork) {
518 std::vector<long int> fixedValues(nrQubits);
519 for (size_t i = 0; i < nrQubits; ++i)
520 fixedValues[i] = (outcome & (1ULL << i)) ? 1 : 0;
521 if (simulationType == SimulationType::kMatrixProductState)
522 mps->Amplitude(nrQubits, fixedValues.data(), &real, &imag);
523 else if (simulationType == SimulationType::kTensorNetwork)
524 tn->Amplitude(nrQubits, fixedValues.data(), &real, &imag);
525 } else if (simulationType == SimulationType::kPauliPropagator) {
526 // Pauli propagator does not support amplitude calculation
527 throw std::runtime_error(
528 "GpuState::Amplitude: Invalid simulation type for amplitude "
529 "calculation.");
530 }
531
532 return std::complex<double>(real, imag);
533 }
534
548 std::complex<double> ProjectOnZero() override {
549 if (simulationType == SimulationType::kMatrixProductState)
550 return mps->ProjectOnZero();
551
552 return Amplitude(0);
553 }
554
565 std::vector<double> AllProbabilities() override {
566 if (nrQubits == 0) return {};
567 const size_t numStates = 1ULL << nrQubits;
568 std::vector<double> result(numStates);
569
570 if (simulationType == SimulationType::kStatevector)
571 state->AllProbabilities(result.data());
572 else if (simulationType == SimulationType::kMatrixProductState ||
573 simulationType == SimulationType::kTensorNetwork) {
574 // this is very slow, it should be used only for tests!
575 for (Types::qubit_t i = 0; i < (Types::qubit_t)numStates; ++i) {
576 const auto val = Amplitude(i);
577 result[i] = std::norm(std::complex<double>(val.real(), val.imag()));
578 }
579 } else if (simulationType == SimulationType::kPauliPropagator) {
580 // this is very slow, it should be used only for tests!
581 for (Types::qubit_t i = 0; i < (Types::qubit_t)numStates; ++i) {
582 result[i] = pp->Probability(i);
583 }
584 }
585
586 return result;
587 }
588
600 std::vector<double> Probabilities(
601 const Types::qubits_vector &qubits) override {
602 std::vector<double> result(qubits.size());
603
604 if (simulationType == SimulationType::kStatevector) {
605 for (size_t i = 0; i < qubits.size(); ++i)
606 result[i] = state->BasisStateProbability(qubits[i]);
607 } else if (simulationType == SimulationType::kMatrixProductState ||
608 simulationType == SimulationType::kTensorNetwork) {
609 for (size_t i = 0; i < qubits.size(); ++i) {
610 const auto ampl = Amplitude(qubits[i]);
611 result[i] = std::norm(ampl);
612 }
613 } else if (simulationType == SimulationType::kPauliPropagator) {
614 for (size_t i = 0; i < qubits.size(); ++i)
615 result[i] = pp->Probability(qubits[i]);
616 }
617
618 return result;
619 }
620
637 std::unordered_map<Types::qubit_t, Types::qubit_t> SampleCounts(
638 const Types::qubits_vector &qubits, size_t shots = 1000) override {
639 if (qubits.empty() || shots == 0) return {};
640
641 if (qubits.size() > sizeof(Types::qubit_t) * 8)
642 std::cerr
643 << "Warning: The number of qubits to measure is larger than the "
644 "number of bits in the Types::qubit_t type, the outcome will be "
645 "undefined"
646 << std::endl;
647
648 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
649
650 DontNotify();
651
652 if (simulationType == SimulationType::kStatevector) {
653 std::vector<long int> samples(shots);
654 state->SampleAll(shots, samples.data());
655
656 for (auto outcome : samples) {
657 // qubits might not be in order, translate the outcome to the correct
658 // order
659 Types::qubit_t translatedOutcome = 0;
660 Types::qubit_t mask = 1ULL;
661 for (size_t i = 0; i < qubits.size(); ++i) {
662 if (outcome & (1ULL << qubits[i])) translatedOutcome |= mask;
663 mask <<= 1;
664 }
665 ++result[translatedOutcome];
666 }
667 } else if (simulationType == SimulationType::kMatrixProductState) {
668 std::unordered_map<std::vector<bool>, int64_t> *map =
669 mps->GetMapForSample();
670
671 std::vector<unsigned int> qubitsIndices(qubits.begin(), qubits.end());
672
673 mps->Sample(shots, qubitsIndices.size(), qubitsIndices.data(), map);
674
675 // put the results in the result map
676 for (const auto &[meas, cnt] : *map) {
677 Types::qubit_t outcome = 0;
678 Types::qubit_t mask = 1ULL;
679 for (Types::qubit_t q = 0; q < qubits.size(); ++q) {
680 if (meas[q]) outcome |= mask;
681 mask <<= 1;
682 }
683
684 result[outcome] += cnt;
685 }
686
687 mps->FreeMapForSample(map);
688 } else if (simulationType == SimulationType::kTensorNetwork) {
689 std::unordered_map<std::vector<bool>, int64_t> *map =
690 tn->GetMapForSample();
691 std::vector<unsigned int> qubitsIndices(qubits.begin(), qubits.end());
692 tn->Sample(shots, qubitsIndices.size(), qubitsIndices.data(), map);
693 // put the results in the result map
694 for (const auto &[meas, cnt] : *map) {
695 Types::qubit_t outcome = 0;
696 Types::qubit_t mask = 1ULL;
697 for (Types::qubit_t q = 0; q < qubits.size(); ++q) {
698 if (meas[q]) outcome |= mask;
699 mask <<= 1;
700 }
701 result[outcome] += cnt;
702 }
703 tn->FreeMapForSample(map);
704 } else if (simulationType == SimulationType::kPauliPropagator) {
705 std::vector<int> qb(qubits.begin(), qubits.end());
706 for (size_t shot = 0; shot < shots; ++shot) {
707 size_t meas = 0;
708 auto res = pp->SampleQubits(qb);
709 for (size_t i = 0; i < qubits.size(); ++i) {
710 if (res[i]) meas |= (1ULL << i);
711 }
712 ++result[meas];
713 }
714 }
715
716 Notify();
717 NotifyObservers(qubits);
718
719 return result;
720 }
721
735 std::unordered_map<std::vector<bool>, Types::qubit_t> SampleCountsMany(
736 const Types::qubits_vector &qubits, size_t shots = 1000) override {
737 if (qubits.empty() || shots == 0) return {};
738
739 std::unordered_map<std::vector<bool>, Types::qubit_t> result;
740
741 DontNotify();
742
743 if (simulationType == SimulationType::kStatevector) {
744 std::vector<long int> samples(shots);
745 state->SampleAll(shots, samples.data());
746
747 std::vector<bool> outcomeVec(qubits.size());
748 for (auto outcome : samples) {
749 for (size_t i = 0; i < qubits.size(); ++i)
750 outcomeVec[i] = ((outcome >> qubits[i]) & 1) == 1;
751 ++result[outcomeVec];
752 }
753 } else if (simulationType == SimulationType::kMatrixProductState) {
754 std::unordered_map<std::vector<bool>, int64_t> *map =
755 mps->GetMapForSample();
756
757 std::vector<unsigned int> qubitsIndices(qubits.begin(), qubits.end());
758 mps->Sample(shots, qubitsIndices.size(), qubitsIndices.data(), map);
759
760 // put the results in the result map
761 for (const auto &[meas, cnt] : *map) result[meas] += cnt;
762
763 mps->FreeMapForSample(map);
764 } else if (simulationType == SimulationType::kTensorNetwork) {
765 std::unordered_map<std::vector<bool>, int64_t> *map =
766 tn->GetMapForSample();
767 std::vector<unsigned int> qubitsIndices(qubits.begin(), qubits.end());
768 tn->Sample(shots, qubitsIndices.size(), qubitsIndices.data(), map);
769 // put the results in the result map
770 for (const auto &[meas, cnt] : *map) result[meas] += cnt;
771 tn->FreeMapForSample(map);
772 } else if (simulationType == SimulationType::kPauliPropagator) {
773 std::vector<int> qb(qubits.begin(), qubits.end());
774 for (size_t shot = 0; shot < shots; ++shot) {
775 const auto res = pp->SampleQubits(qb);
776 ++result[res];
777 }
778 }
779
780 Notify();
781 NotifyObservers(qubits);
782
783 return result;
784 }
785
797 double ExpectationValue(const std::string &pauliString) override {
798 double result = 0.0;
799
800 if (simulationType == SimulationType::kStatevector)
801 result = state->ExpectationValue(pauliString);
802 else if (simulationType == SimulationType::kMatrixProductState)
803 result = mps->ExpectationValue(pauliString);
804 else if (simulationType == SimulationType::kTensorNetwork)
805 result = tn->ExpectationValue(pauliString);
806 else if (simulationType == SimulationType::kPauliPropagator)
807 result = pp->ExpectationValue(pauliString);
808 else
809 throw std::runtime_error(
810 "GpuState::ExpectationValue: Invalid simulation type for expectation "
811 "value calculation.");
812
813 return result;
814 }
815
823 SimulatorType GetType() const override { return SimulatorType::kGpuSim; }
824
833 SimulationType GetSimulationType() const override { return simulationType; }
834
843 void Flush() override {}
844
855 void SaveStateToInternalDestructive() override {
856 if (simulationType == SimulationType::kStatevector)
857 state->SaveStateDestructive();
858 else
859 throw std::runtime_error(
860 "GpuState::SaveStateToInternalDestructive: Invalid simulation type "
861 "for saving the state destructively.");
862 }
863
871 if (simulationType == SimulationType::kStatevector)
872 state->RestoreStateFreeSaved();
873 else
874 throw std::runtime_error(
875 "GpuState::RestoreInternalDestructiveSavedState: Invalid simulation "
876 "type for restoring the state destructively.");
877 }
878
887 void SaveState() override {
888 if (simulationType == SimulationType::kStatevector)
889 state->SaveState();
890 else if (simulationType == SimulationType::kMatrixProductState)
891 mps->SaveState();
892 else if (simulationType == SimulationType::kTensorNetwork)
893 tn->SaveState();
894 else if (simulationType == SimulationType::kPauliPropagator)
895 pp->SaveState();
896 }
897
905 void RestoreState() override {
906 if (simulationType == SimulationType::kStatevector)
907 state->RestoreStateNoFreeSaved();
908 else if (simulationType == SimulationType::kMatrixProductState)
909 mps->RestoreState();
910 else if (simulationType == SimulationType::kTensorNetwork)
911 tn->RestoreState();
912 else if (simulationType == SimulationType::kPauliPropagator)
913 pp->RestoreState();
914 }
915
923 std::complex<double> AmplitudeRaw(Types::qubit_t outcome) override {
924 return Amplitude(outcome);
925 }
926
935 void SetMultithreading(bool multithreading = true) override {
936 // don't do anything here, the multithreading is always enabled
937 }
938
946 bool GetMultithreading() const override { return true; }
947
958 bool IsQcsim() const override { return false; }
959
977 if (simulationType == SimulationType::kStatevector)
978 return state->MeasureAllQubitsNoCollapse();
979 else if (simulationType == SimulationType::kMatrixProductState ||
980 simulationType == SimulationType::kTensorNetwork ||
981 simulationType == SimulationType::kPauliPropagator) {
982 if (nrQubits > sizeof(Types::qubit_t) * 8)
983 std::cerr
984 << "Warning: The number of qubits to measure is larger than the "
985 "number of bits in the Types::qubit_t type, the outcome will be "
986 "undefined"
987 << std::endl;
988
989 Types::qubits_vector fixedValues(nrQubits);
990 std::iota(fixedValues.begin(), fixedValues.end(), 0);
991 const auto res = SampleCounts(fixedValues, 1);
992 if (res.empty()) return 0;
993 return res.begin()
994 ->first; // return the first outcome, as it is the only one
995 }
996
997 throw std::runtime_error(
998 "QCSimState::MeasureNoCollapse: Invalid simulation type for measuring "
999 "all the qubits without collapsing the state.");
1000
1001 return 0;
1002 }
1003
1018 std::vector<bool> MeasureNoCollapseMany() override {
1019 if (simulationType == SimulationType::kStatevector) {
1020 const auto meas = state->MeasureAllQubitsNoCollapse();
1021 std::vector<bool> result(nrQubits, false);
1022 for (size_t i = 0; i < nrQubits; ++i) result[i] = ((meas >> i) & 1) == 1;
1023 return result;
1024 } else if (simulationType == SimulationType::kMatrixProductState ||
1025 simulationType == SimulationType::kTensorNetwork ||
1026 simulationType == SimulationType::kPauliPropagator) {
1027 Types::qubits_vector fixedValues(nrQubits);
1028 std::iota(fixedValues.begin(), fixedValues.end(), 0);
1029 const auto res = SampleCountsMany(fixedValues, 1);
1030 if (res.empty()) return std::vector<bool>(nrQubits, false);
1031 return res.begin()
1032 ->first; // return the first outcome, as it is the only one
1033 }
1034
1035 throw std::runtime_error(
1036 "QCSimState::MeasureNoCollapseMany: Invalid simulation type for "
1037 "measuring "
1038 "all the qubits without collapsing the state.");
1039
1040 return std::vector<bool>(nrQubits, false);
1041 }
1042
1043 protected:
1044 SimulationType simulationType =
1045 SimulationType::kStatevector;
1047 std::unique_ptr<GpuLibStateVectorSim>
1048 state;
1049 std::unique_ptr<GpuLibMPSSim> mps;
1050 std::unique_ptr<GpuLibTNSim> tn;
1051 std::unique_ptr<GpuPauliPropagator>
1052 pp;
1054 size_t nrQubits = 0;
1055 bool limitSize = false;
1056 bool limitEntanglement = false;
1057 Eigen::Index chi = 10; // if limitSize is true
1058 double singularValueThreshold = 0.; // if limitEntanglement is true
1059 bool useDoublePrecision = false; // if true, GPU MPS uses float64
1060};
1061
1062} // namespace Private
1063} // namespace Simulators
1064
1065#endif
1066#endif
1067#endif
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)
uint_fast64_t qubit_t
The type of a qubit.
Definition Types.h:21
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
Definition Types.h:23