Maestro 0.1.0
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
QCSimState.h
Go to the documentation of this file.
1
13#pragma once
14
15#ifndef _QCSIMSTATE_H_
16#define _QCSIMSTATE_H_
17
18#ifdef INCLUDED_BY_FACTORY
19
20#include <algorithm>
21
22#include "Simulator.h"
23
24#include "Clifford.h"
25#include "MPSSimulator.h"
26#include "QubitRegister.h"
28
29#include "../TensorNetworks/ForestContractor.h"
30#include "../TensorNetworks/TensorNetwork.h"
31
32#include "../Utils/Alias.h"
33
34namespace Simulators {
35// TODO: Maybe use the pimpl idiom
36// https://en.cppreference.com/w/cpp/language/pimpl to hide the implementation
37// for good but during development this should be good enough
38namespace Private {
39
50class QCSimState : public ISimulator {
51 public:
52 QCSimState() : rng(std::random_device{}()), uniformZeroOne(0, 1) {}
53
61 void Initialize() override {
62 if (nrQubits != 0) {
63 if (simulationType == SimulationType::kMatrixProductState) {
64 mpsSimulator =
65 std::make_unique<QC::TensorNetworks::MPSSimulator>(nrQubits);
66 if (limitEntanglement && singularValueThreshold > 0.)
67 mpsSimulator->setLimitEntanglement(singularValueThreshold);
68 if (limitSize && chi > 0) mpsSimulator->setLimitBondDimension(chi);
69 } else if (simulationType == SimulationType::kStabilizer)
70 cliffordSimulator =
71 std::make_unique<QC::Clifford::StabilizerSimulator>(nrQubits);
72 else if (simulationType == SimulationType::kTensorNetwork) {
73 tensorNetwork =
74 std::make_unique<TensorNetworks::TensorNetwork>(nrQubits);
75 // for now the only used contractor is the forest one, but we'll use
76 // more in the future
77 const auto tensorContractor =
78 std::make_shared<TensorNetworks::ForestContractor>();
79 tensorNetwork->SetContractor(tensorContractor);
80 } else if (simulationType == SimulationType::kPauliPropagator) {
81 pp = std::make_unique<Simulators::QcsimPauliPropagator>();
82 pp->SetNrQubits(nrQubits);
83 } else
84 state = std::make_unique<QC::QubitRegister<>>(nrQubits);
85
86 SetMultithreading(enableMultithreading);
87 }
88 }
89
101 void InitializeState(size_t num_qubits,
102 std::vector<std::complex<double>> &amplitudes) override {
103 if (num_qubits == 0) return;
104 Clear();
105 nrQubits = num_qubits;
106 Initialize();
107 if (simulationType != SimulationType::kStatevector)
108 throw std::runtime_error(
109 "QCSimState::InitializeState: Invalid "
110 "simulation type for initializing the state.");
111
112 Eigen::VectorXcd amplitudesEigen(
113 Eigen::Map<Eigen::VectorXcd, Eigen::Unaligned>(amplitudes.data(),
114 amplitudes.size()));
115 state->setRegisterStorageFastNoNormalize(amplitudesEigen);
116 }
117
129 /*
130 void InitializeState(size_t num_qubits, std::vector<std::complex<double>,
131 avoid_init_allocator<std::complex<double>>>& amplitudes) override
132 {
133 Clear();
134 nrQubits = num_qubits;
135 Initialize();
136 Eigen::VectorXcd amplitudesEigen(Eigen::Map<Eigen::VectorXcd,
137 Eigen::Unaligned>(amplitudes.data(), amplitudes.size()));
138 state->setRegisterStorageFastNoNormalize(amplitudesEigen);
139 }
140 */
141
153#ifndef NO_QISKIT_AER
154 void InitializeState(size_t num_qubits,
155 AER::Vector<std::complex<double>> &amplitudes) override {
156 if (num_qubits == 0) return;
157 Clear();
158 nrQubits = num_qubits;
159 Initialize();
160 if (simulationType != SimulationType::kStatevector)
161 throw std::runtime_error(
162 "QCSimState::InitializeState: Invalid "
163 "simulation type for initializing the state.");
164
165 Eigen::VectorXcd amplitudesEigen(
166 Eigen::Map<Eigen::VectorXcd, Eigen::Unaligned>(amplitudes.data(),
167 amplitudes.size()));
168 state->setRegisterStorageFastNoNormalize(amplitudesEigen);
169 }
170#endif
171
183 void InitializeState(size_t num_qubits,
184 Eigen::VectorXcd &amplitudes) override {
185 if (num_qubits == 0) return;
186 Clear();
187 nrQubits = num_qubits;
188 Initialize();
189
190 if (simulationType != SimulationType::kStatevector)
191 throw std::runtime_error(
192 "QCSimState::InitializeState: Invalid "
193 "simulation type for initializing the state.");
194
195 state = std::make_unique<QC::QubitRegister<>>(nrQubits, amplitudes);
196 state->SetMultithreading(enableMultithreading);
197 }
198
205 void Reset() override {
206 if (mpsSimulator)
207 mpsSimulator->Clear();
208 else if (cliffordSimulator)
209 cliffordSimulator->Reset();
210 else if (tensorNetwork)
211 tensorNetwork->Clear();
212 else if (state)
213 state->Reset();
214 else if (pp)
215 pp->ClearOperations();
216 }
217
226 void Configure(const char *key, const char *value) override {
227 if (std::string("method") == key) {
228 if (std::string("statevector") == value)
229 simulationType = SimulationType::kStatevector;
230 else if (std::string("matrix_product_state") == value)
231 simulationType = SimulationType::kMatrixProductState;
232 else if (std::string("stabilizer") == value)
233 simulationType = SimulationType::kStabilizer;
234 else if (std::string("tensor_network") == value)
235 simulationType = SimulationType::kTensorNetwork;
236 else if (std::string("pauli_propagator") == value)
237 simulationType = SimulationType::kPauliPropagator;
238 } else if (std::string("matrix_product_state_truncation_threshold") ==
239 key) {
240 singularValueThreshold = std::stod(value);
241 if (singularValueThreshold > 0.) {
242 limitEntanglement = true;
243 if (mpsSimulator)
244 mpsSimulator->setLimitEntanglement(singularValueThreshold);
245 } else
246 limitEntanglement = false;
247 } else if (std::string("matrix_product_state_max_bond_dimension") == key) {
248 chi = std::stoi(value);
249 if (chi > 0) {
250 limitSize = true;
251 if (mpsSimulator) mpsSimulator->setLimitBondDimension(chi);
252 } else
253 limitSize = false;
254 } else if (std::string("mps_sample_measure_algorithm") == key)
255 useMPSMeasureNoCollapse = std::string("mps_probabilities") == value;
256 }
257
265 std::string GetConfiguration(const char *key) const override {
266 if (std::string("method") == key) {
267 switch (simulationType) {
268 case SimulationType::kStatevector:
269 return "statevector";
270 case SimulationType::kMatrixProductState:
271 return "matrix_product_state";
272 case SimulationType::kStabilizer:
273 return "stabilizer";
274 case SimulationType::kTensorNetwork:
275 return "tensor_network";
276 case SimulationType::kPauliPropagator:
277 return "pauli_propagator";
278 default:
279 return "other";
280 }
281 } else if (std::string("matrix_product_state_truncation_threshold") ==
282 key) {
283 if (limitEntanglement && singularValueThreshold > 0.)
284 return std::to_string(singularValueThreshold);
285 } else if (std::string("matrix_product_state_max_bond_dimension") == key) {
286 if (limitSize && limitSize > 0) return std::to_string(chi);
287 } else if (std::string("mps_sample_measure_algorithm") == key) {
288 return useMPSMeasureNoCollapse ? "mps_probabilities"
289 : "mps_apply_measure";
290 }
291
292 return "";
293 }
294
302 size_t AllocateQubits(size_t num_qubits) override {
303 if ((simulationType == SimulationType::kStatevector && state) ||
304 (simulationType == SimulationType::kMatrixProductState &&
305 mpsSimulator) ||
306 (simulationType == SimulationType::kStabilizer && cliffordSimulator) ||
307 (simulationType == SimulationType::kTensorNetwork && tensorNetwork))
308 return 0;
309
310 const size_t oldNrQubits = nrQubits;
311 nrQubits += num_qubits;
312 if (simulationType == SimulationType::kPauliPropagator)
313 if (pp)pp->SetNrQubits(nrQubits);
314
315 return oldNrQubits;
316 }
317
324 size_t GetNumberOfQubits() const override { return nrQubits; }
325
333 void Clear() override {
334 state = nullptr;
335 mpsSimulator = nullptr;
336 cliffordSimulator = nullptr;
337 tensorNetwork = nullptr;
338 pp = nullptr;
339 nrQubits = 0;
340 }
341
349 size_t Measure(const Types::qubits_vector &qubits) override {
350 // TODO: this is inefficient, maybe implement it better in qcsim
351 // for now it has the possibility of measuring a qubits interval, but not a
352 // list of qubits
353
354 size_t res = 0;
355 size_t mask = 1ULL;
356
357 DontNotify();
358 if (simulationType == SimulationType::kStatevector) {
359 for (size_t qubit : qubits) {
360 if (state->MeasureQubit(static_cast<unsigned int>(qubit))) res |= mask;
361 mask <<= 1;
362 }
363 } else if (simulationType == SimulationType::kStabilizer) {
364 for (size_t qubit : qubits) {
365 if (cliffordSimulator->MeasureQubit(static_cast<unsigned int>(qubit)))
366 res |= mask;
367 mask <<= 1;
368 }
369 } else if (simulationType == SimulationType::kTensorNetwork) {
370 for (size_t qubit : qubits) {
371 if (tensorNetwork->Measure(static_cast<unsigned int>(qubit)))
372 res |= mask;
373 mask <<= 1;
374 }
375 } else if (simulationType == SimulationType::kPauliPropagator) {
376 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
377 const auto res = pp->Measure(qubitsInt);
378 Types::qubit_t result = 0;
379 for (size_t i = 0; i < res.size(); ++i) {
380 if (res[i]) result |= mask;
381 mask <<= 1;
382 }
383 return result;
384 } else {
385 /*
386 for (size_t qubit : qubits)
387 {
388 if (mpsSimulator->MeasureQubit(static_cast<unsigned int>(qubit)))
389 res |= mask;
390 mask <<= 1;
391 }
392 */
393 const std::set<Eigen::Index> qubitsSet(qubits.begin(), qubits.end());
394 auto measured = mpsSimulator->MeasureQubits(qubitsSet);
395 for (Types::qubit_t qubit : qubits) {
396 if (measured[qubit]) res |= mask;
397 mask <<= 1;
398 }
399 }
400 Notify();
401
402 NotifyObservers(qubits);
403
404 return res;
405 }
406
413 void ApplyReset(const Types::qubits_vector &qubits) override {
414 QC::Gates::PauliXGate xGate;
415
416 DontNotify();
417 if (simulationType == SimulationType::kStatevector) {
418 for (size_t qubit : qubits)
419 if (state->MeasureQubit(static_cast<unsigned int>(qubit)))
420 state->ApplyGate(xGate, static_cast<unsigned int>(qubit));
421 } else if (simulationType == SimulationType::kStabilizer) {
422 for (size_t qubit : qubits)
423 if (cliffordSimulator->MeasureQubit(static_cast<unsigned int>(qubit)))
424 cliffordSimulator->ApplyX(static_cast<unsigned int>(qubit));
425 } else if (simulationType == SimulationType::kTensorNetwork) {
426 for (size_t qubit : qubits)
427 if (tensorNetwork->Measure(static_cast<unsigned int>(qubit)))
428 tensorNetwork->AddGate(xGate, static_cast<unsigned int>(qubit));
429 } else if (simulationType == SimulationType::kPauliPropagator) {
430 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
431 const auto res = pp->Measure(qubitsInt);
432 for (size_t i = 0; i < res.size(); ++i) {
433 if (res[i]) pp->ApplyX(qubitsInt[i]);
434 }
435 } else {
436 for (size_t qubit : qubits)
437 if (mpsSimulator->MeasureQubit(static_cast<unsigned int>(qubit)))
438 mpsSimulator->ApplyGate(xGate, static_cast<unsigned int>(qubit));
439 }
440 Notify();
441
442 NotifyObservers(qubits);
443 }
444
456 double Probability(Types::qubit_t outcome) override {
457 if (simulationType == SimulationType::kMatrixProductState)
458 return mpsSimulator->getBasisStateProbability(
459 static_cast<unsigned int>(outcome));
460 else if (simulationType == SimulationType::kStabilizer)
461 return cliffordSimulator->getBasisStateProbability(
462 static_cast<unsigned int>(outcome));
463 else if (simulationType == SimulationType::kTensorNetwork)
464 return tensorNetwork->getBasisStateProbability(outcome);
465 else if (simulationType == SimulationType::kPauliPropagator)
466 return pp->Probability(outcome);
467
468 return state->getBasisStateProbability(static_cast<unsigned int>(outcome));
469 }
470
481 std::complex<double> Amplitude(Types::qubit_t outcome) override {
482 if (simulationType == SimulationType::kMatrixProductState)
483 return mpsSimulator->getBasisStateAmplitude(
484 static_cast<unsigned int>(outcome));
485 else if (simulationType == SimulationType::kStabilizer)
486 throw std::runtime_error(
487 "QCSimState::Amplitude: Invalid simulation type for obtaining the "
488 "amplitude of the specified outcome.");
489 else if (simulationType == SimulationType::kTensorNetwork)
490 throw std::runtime_error(
491 "QCSimState::Amplitude: Not supported for the "
492 "tensor network simulator.");
493 else if (simulationType == SimulationType::kPauliPropagator)
494 throw std::runtime_error(
495 "QCSimState::Amplitude: Invalid simulation type for obtaining the "
496 "amplitude of the specified outcome.");
497
498 return state->getBasisStateAmplitude(static_cast<unsigned int>(outcome));
499 }
500
511 std::vector<double> AllProbabilities() override {
512 // TODO: In principle this could be done, but why? It should be costly.
513 if (simulationType == SimulationType::kTensorNetwork)
514 throw std::runtime_error(
515 "QCSimState::AllProbabilities: Invalid "
516 "simulation type for obtaining probabilities.");
517 else if (simulationType == SimulationType::kStabilizer)
518 return cliffordSimulator->AllProbabilities();
519 else if (simulationType == SimulationType::kPauliPropagator) {
520 const size_t nrBasisStates = 1ULL << GetNumberOfQubits();
521 std::vector<double> result(nrBasisStates);
522 for (size_t i = 0; i < nrBasisStates; ++i)
523 result[i] = pp->Probability(i);
524 return result;
525 }
526
527 const Eigen::VectorXcd probs =
528 simulationType == SimulationType::kMatrixProductState
529 ? mpsSimulator->getRegisterStorage().cwiseAbs2()
530 : state->getRegisterStorage().cwiseAbs2();
531
532 std::vector<double> result(probs.size());
533
534 for (int i = 0; i < probs.size(); ++i) result[i] = probs[i].real();
535
536 return result;
537 }
538
550 std::vector<double> Probabilities(
551 const Types::qubits_vector &qubits) override {
552 if (simulationType == SimulationType::kStabilizer)
553 throw std::runtime_error(
554 "QCSimState::Probabilities: Invalid simulation "
555 "type for obtaining probabilities.");
556 else if (simulationType == SimulationType::kTensorNetwork) {
557 // TODO: Implement this!!!
558 throw std::runtime_error(
559 "QCSimState::Probabilities: Not implemented yet "
560 "for the tensor network simulator.");
561 }
562
563 std::vector<double> result(qubits.size());
564
565 if (simulationType == SimulationType::kMatrixProductState) {
566 for (int i = 0; i < static_cast<int>(qubits.size()); ++i)
567 result[i] = mpsSimulator->getBasisStateProbability(qubits[i]);
568 } else if (simulationType == SimulationType::kPauliPropagator) {
569 for (int i = 0; i < static_cast<int>(qubits.size()); ++i)
570 result[i] = pp->Probability(qubits[i]);
571 } else {
572 const Eigen::VectorXcd &reg = state->getRegisterStorage();
573
574 for (int i = 0; i < static_cast<int>(qubits.size()); ++i)
575 result[i] = std::norm(reg[qubits[i]]);
576 }
577
578 return result;
579 }
580
594 std::unordered_map<Types::qubit_t, Types::qubit_t> SampleCounts(
595 const Types::qubits_vector &qubits, size_t shots = 1000) override {
596 if (qubits.empty() || shots == 0) return {};
597
598 // TODO: this is inefficient, maybe implement it better in qcsim
599 // for now it has the possibility of measuring a qubits interval, but not a
600 // list of qubits
601 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
602
603 DontNotify();
604
605 if (simulationType == SimulationType::kMatrixProductState) {
606 bool normal = true;
607 if (useMPSMeasureNoCollapse) {
608 // check to see if it can be used
609 std::unordered_set qset(qubits.begin(), qubits.end());
610 if (qset.size() == GetNumberOfQubits()) {
611 // it can!
612 normal = false;
613 for (size_t shot = 0; shot < shots; ++shot) {
614 const size_t measRaw = MeasureNoCollapse();
615 size_t meas = 0;
616 size_t mask = 1ULL;
617
618 // translate the measurement
619 for (auto q : qubits) {
620 const size_t qubitMask = 1ULL << q;
621 if (measRaw & qubitMask) meas |= mask;
622 mask <<= 1ULL;
623 }
624
625 ++result[meas];
626 }
627 }
628 }
629
630 if (normal) {
631 auto savedState = mpsSimulator->getState();
632 for (size_t shot = 0; shot < shots; ++shot) {
633 const size_t meas = Measure(qubits);
634 ++result[meas];
635 mpsSimulator->setState(savedState);
636 }
637 }
638 } else if (simulationType == SimulationType::kStabilizer) {
639 cliffordSimulator->SaveState();
640 for (size_t shot = 0; shot < shots; ++shot) {
641 const size_t meas = Measure(qubits);
642 ++result[meas];
643 cliffordSimulator->RestoreState();
644 }
645 cliffordSimulator->ClearSavedState();
646 } else if (simulationType == SimulationType::kTensorNetwork) {
647 tensorNetwork->SaveState();
648 for (size_t shot = 0; shot < shots; ++shot) {
649 const size_t meas = Measure(qubits);
650 ++result[meas];
651 tensorNetwork->RestoreState();
652 }
653 tensorNetwork->ClearSavedState();
654 } else if (simulationType == SimulationType::kPauliPropagator) {
655 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
656 for (size_t shot = 0; shot < shots; ++shot) {
657 const auto res = pp->Sample(qubitsInt);
658
659 size_t meas = 0;
660 for (size_t i = 0; i < qubits.size(); ++i) {
661 if (res[i]) meas |= (1ULL << i);
662 }
663
664 ++result[meas];
665 }
666 } else {
667 if (shots > 1) {
668 const auto &statev = state->getRegisterStorage();
669
670 const Utils::Alias alias(statev);
671
672 for (size_t shot = 0; shot < shots; ++shot) {
673 const double prob = 1. - uniformZeroOne(rng);
674 const size_t measRaw = alias.Sample(prob);
675
676 size_t meas = 0;
677 size_t mask = 1ULL;
678 for (auto q : qubits) {
679 const size_t qubitMask = 1ULL << q;
680 if ((measRaw & qubitMask) != 0) meas |= mask;
681 mask <<= 1ULL;
682 }
683
684 ++result[meas];
685 }
686 } else {
687 for (size_t shot = 0; shot < shots; ++shot) {
688 const size_t measRaw = MeasureNoCollapse();
689 size_t meas = 0;
690 size_t mask = 1ULL;
691
692 for (auto q : qubits) {
693 const size_t qubitMask = 1ULL << q;
694 if ((measRaw & qubitMask) != 0) meas |= mask;
695 mask <<= 1ULL;
696 }
697
698 ++result[meas];
699 }
700 }
701 }
702
703 Notify();
704 NotifyObservers(qubits);
705
706 return result;
707 }
708
720 double ExpectationValue(const std::string &pauliStringOrig) override {
721 if (pauliStringOrig.empty()) return 1.0;
722
723 std::string pauliString = pauliStringOrig;
724 if (pauliString.size() > GetNumberOfQubits()) {
725 for (size_t i = GetNumberOfQubits(); i < pauliString.size(); ++i) {
726 const auto pauliOp = toupper(pauliString[i]);
727 if (pauliOp != 'I' && pauliOp != 'Z') return 0.0;
728 }
729
730 pauliString.resize(GetNumberOfQubits());
731 }
732
733 if (simulationType == SimulationType::kStabilizer)
734 return cliffordSimulator->ExpectationValue(pauliString);
735 else if (simulationType == SimulationType::kTensorNetwork)
736 return tensorNetwork->ExpectationValue(pauliString);
737 else if (simulationType == SimulationType::kPauliPropagator)
738 return pp->ExpectationValue(pauliString);
739
740 // statevector or mps
741 static const QC::Gates::PauliXGate<> xgate;
742 static const QC::Gates::PauliYGate<> ygate;
743 static const QC::Gates::PauliZGate<> zgate;
744
745 std::vector<QC::Gates::AppliedGate<Eigen::MatrixXcd>> pauliStringVec;
746 pauliStringVec.reserve(pauliString.size());
747
748 for (size_t q = 0; q < pauliString.size(); ++q) {
749 switch (toupper(pauliString[q])) {
750 case 'X': {
751 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(
752 xgate.getRawOperatorMatrix(), static_cast<Types::qubit_t>(q));
753 pauliStringVec.emplace_back(std::move(ag));
754 } break;
755 case 'Y': {
756 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(
757 ygate.getRawOperatorMatrix(), static_cast<Types::qubit_t>(q));
758 pauliStringVec.emplace_back(std::move(ag));
759 } break;
760 case 'Z': {
761 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(
762 zgate.getRawOperatorMatrix(), static_cast<Types::qubit_t>(q));
763 pauliStringVec.emplace_back(std::move(ag));
764 } break;
765 case 'I':
766 [[fallthrough]];
767 default:
768 break;
769 }
770 }
771
772 if (pauliStringVec.empty()) return 1.0;
773
774 if (simulationType == SimulationType::kMatrixProductState)
775 return mpsSimulator->ExpectationValue(pauliStringVec).real();
776
777 return state->ExpectationValue(pauliStringVec).real();
778 }
779
787 SimulatorType GetType() const override { return SimulatorType::kQCSim; }
788
797 SimulationType GetSimulationType() const override { return simulationType; }
798
807 void Flush() override {}
808
818 void SaveStateToInternalDestructive() override {}
819
826 void RestoreInternalDestructiveSavedState() override {}
827
837 void SaveState() override {
838 if (simulationType == SimulationType::kMatrixProductState)
839 mpsSimulator->SaveState();
840 else if (simulationType == SimulationType::kStabilizer)
841 cliffordSimulator->SaveState();
842 else if (simulationType == SimulationType::kTensorNetwork)
843 tensorNetwork->SaveState();
844 else if (simulationType == SimulationType::kPauliPropagator)
845 pp->SaveState();
846 else
847 state->SaveState();
848 }
849
858 void RestoreState() override {
859 if (simulationType == SimulationType::kMatrixProductState)
860 mpsSimulator->RestoreState();
861 else if (simulationType == SimulationType::kStabilizer)
862 cliffordSimulator->RestoreState();
863 else if (simulationType == SimulationType::kTensorNetwork)
864 tensorNetwork->RestoreState();
865 else if (simulationType == SimulationType::kPauliPropagator)
866 pp->RestoreState();
867 else
868 state->RestoreState();
869 }
870
878 std::complex<double> AmplitudeRaw(Types::qubit_t outcome) override {
879 return Amplitude(outcome);
880 }
881
890 void SetMultithreading(bool multithreading = true) override {
891 enableMultithreading = multithreading;
892 if (state) state->SetMultithreading(multithreading);
893 if (cliffordSimulator) cliffordSimulator->SetMultithreading(multithreading);
894 if (tensorNetwork) tensorNetwork->SetMultithreading(multithreading);
895 if (pp)
896 {
897 if (multithreading) pp->EnableParallel();
898 else pp->DisableParallel();
899 }
900 }
901
909 bool GetMultithreading() const override { return enableMultithreading; }
910
921 bool IsQcsim() const override { return true; }
922
936 Types::qubit_t MeasureNoCollapse() override {
937 if (simulationType == SimulationType::kStatevector)
938 return state->MeasureNoCollapse();
939 else if (simulationType == SimulationType::kMatrixProductState) {
940 const auto measured = mpsSimulator->MeasureNoCollapse();
941 Types::qubit_t result = 0;
942 Types::qubit_t mask = 1;
943 for (const auto &meas : measured) {
944 if (meas) result |= mask;
945 mask <<= 1;
946 }
947 return result;
948 } else if (simulationType == SimulationType::kPauliPropagator) {
949 std::vector<int> qubitsInt(GetNumberOfQubits());
950 std::iota(qubitsInt.begin(), qubitsInt.end(), 0);
951 const auto res = pp->Sample(qubitsInt);
952 Types::qubit_t result = 0;
953 for (size_t i = 0; i < res.size(); ++i) {
954 if (res[i]) result |= (1ULL << i);
955 }
956 return result;
957 }
958
959 throw std::runtime_error(
960 "QCSimState::MeasureNoCollapse: Invalid simulation type for measuring "
961 "all the qubits without collapsing the state.");
962
963 return 0;
964 }
965
966 protected:
967 SimulationType simulationType =
968 SimulationType::kStatevector;
970 std::unique_ptr<QC::QubitRegister<>> state;
971 std::unique_ptr<QC::TensorNetworks::MPSSimulator>
972 mpsSimulator;
973 std::unique_ptr<QC::Clifford::StabilizerSimulator>
974 cliffordSimulator;
975 std::unique_ptr<TensorNetworks::TensorNetwork>
976 tensorNetwork;
977 std::unique_ptr<QcsimPauliPropagator>
978 pp;
980 size_t nrQubits = 0;
981 bool limitSize = false;
982 bool limitEntanglement = false;
983 Eigen::Index chi = 10; // if limitSize is true
984 double singularValueThreshold = 0.; // if limitEntanglement is true
985 bool enableMultithreading = true;
986 bool useMPSMeasureNoCollapse =
987 true;
989 std::mt19937_64 rng;
990 std::uniform_real_distribution<double> uniformZeroOne;
991};
992
993} // namespace Private
994} // namespace Simulators
995
996#endif
997
998#endif // !_QCSIMSTATE_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:85