18#ifdef INCLUDED_BY_FACTORY
29#include "MPSSimulator.h"
30#include "QubitRegister.h"
57class QCSimState :
public ISimulator {
59 QCSimState() : rng(std::random_device{}()), uniformZeroOne(0, 1) {}
68 void Initialize()
override {
70 if (simulationType == SimulationType::kMatrixProductState) {
72 std::make_unique<QC::TensorNetworks::MPSSimulator>(nrQubits);
73 if (limitEntanglement && singularValueThreshold > 0.)
74 mpsSimulator->setLimitEntanglement(singularValueThreshold);
75 if (limitSize && chi > 0) mpsSimulator->setLimitBondDimension(chi);
77 if (!useOptimalMeetingPosition)
78 mpsSimulator->SetUseOptimalMeetingPosition(
false);
79 }
else if (simulationType == SimulationType::kStabilizer)
81 std::make_unique<QC::Clifford::StabilizerSimulator>(nrQubits);
82 else if (simulationType == SimulationType::kTensorNetwork) {
84 std::make_unique<TensorNetworks::TensorNetwork>(nrQubits);
87 const auto tensorContractor =
88 std::make_shared<TensorNetworks::ForestContractor>();
89 tensorNetwork->SetContractor(tensorContractor);
90 }
else if (simulationType == SimulationType::kPauliPropagator) {
91 pp = std::make_unique<Simulators::QcsimPauliPropagator>();
92 pp->SetNrQubits(
static_cast<int>(nrQubits));
93 if (ppCoefficientThreshold > 0.)
94 pp->SetCoefficientThreshold(ppCoefficientThreshold);
95 if (ppPauliWeightThreshold < std::numeric_limits<size_t>::max())
96 pp->SetPauliWeightThreshold(ppPauliWeightThreshold);
97 if (ppStepsBetweenTrims < std::numeric_limits<int>::max())
98 pp->SetStepsBetweenTrims(ppStepsBetweenTrims);
99 }
else if (simulationType == SimulationType::kPathIntegral) {
100 pathIntegralSimulator = std::make_unique<PathIntegralSimulator>();
101 pathIntegralSimulator->SetStartZeroState(nrQubits);
103 state = std::make_unique<QC::QubitRegister<>>(nrQubits);
120 void InitializeState(
size_t num_qubits,
121 std::vector<std::complex<double>> &litudes)
override {
122 if (num_qubits == 0)
return;
124 nrQubits = num_qubits;
126 if (simulationType != SimulationType::kStatevector)
127 throw std::runtime_error(
128 "QCSimState::InitializeState: Invalid "
129 "simulation type for initializing the state.");
131 Eigen::VectorXcd amplitudesEigen(
132 Eigen::Map<Eigen::VectorXcd, Eigen::Unaligned>(amplitudes.data(),
134 state->setRegisterStorageFastNoNormalize(amplitudesEigen);
173 void InitializeState(
size_t num_qubits,
174 AER::Vector<std::complex<double>> &litudes)
override {
175 if (num_qubits == 0)
return;
177 nrQubits = num_qubits;
179 if (simulationType != SimulationType::kStatevector)
180 throw std::runtime_error(
181 "QCSimState::InitializeState: Invalid "
182 "simulation type for initializing the state.");
184 Eigen::VectorXcd amplitudesEigen(
185 Eigen::Map<Eigen::VectorXcd, Eigen::Unaligned>(amplitudes.data(),
187 state->setRegisterStorageFastNoNormalize(amplitudesEigen);
202 void InitializeState(
size_t num_qubits,
203 Eigen::VectorXcd &litudes)
override {
204 if (num_qubits == 0)
return;
206 nrQubits = num_qubits;
209 if (simulationType != SimulationType::kStatevector)
210 throw std::runtime_error(
211 "QCSimState::InitializeState: Invalid "
212 "simulation type for initializing the state.");
214 state = std::make_unique<QC::QubitRegister<>>(nrQubits, amplitudes);
215 state->SetMultithreading(enableMultithreading);
224 void Reset()
override {
226 mpsSimulator->Clear();
227 else if (cliffordSimulator)
228 cliffordSimulator->Reset();
229 else if (tensorNetwork)
230 tensorNetwork->Clear();
234 pp->ClearOperations();
235 else if (pathIntegralSimulator) {
236 pathIntegralSimulator->Reset();
237 pathIntegralSimulator->SetStartZeroState(nrQubits);
240 upcomingGateIndex = 0;
250 bool SupportsMPSSwapOptimization()
const override {
return true; }
260 void SetInitialQubitsMap(
261 const std::vector<long long int> &initialMap)
override {
263 mpsSimulator->SetInitialQubitsMap(initialMap);
264 if (!dummySim || dummySim->getNrQubits() != initialMap.size()) {
266 std::make_unique<Simulators::MPSDummySimulator>(initialMap.size());
267 dummySim->SetMaxBondDimension(
268 limitSize ?
static_cast<long long int>(chi) : 0);
270 dummySim->setGrowthFactorGate(growthFactorGate);
271 dummySim->setGrowthFactorSwap(growthFactorSwap);
272 dummySim->SetInitialQubitsMap(initialMap);
276 void SetUseOptimalMeetingPosition(
bool enable)
override {
277 useOptimalMeetingPosition = enable;
278 if (mpsSimulator) mpsSimulator->SetUseOptimalMeetingPosition(enable);
281 void SetLookaheadDepth(
int depth)
override {
282 lookaheadDepth = depth;
283 if (mpsSimulator && depth > 0 && !useOptimalMeetingPosition)
284 mpsSimulator->SetUseOptimalMeetingPosition(
true);
287 void SetLookaheadDepthWithHeuristic(
int depth)
override {
288 lookaheadDepthWithHeuristic = depth;
289 if (lookaheadDepth < depth) SetLookaheadDepth(depth);
292 void SetUpcomingGates(
295 upcomingGates = gates;
296 upcomingGateIndex = 0;
298 if (!mpsSimulator || lookaheadDepth <= 0 || lookaheadDepth == std::numeric_limits<int>::max())
return;
303 gateCounterObserver =
304 std::make_shared<GateCounterObserver>(upcomingGateIndex);
305 RegisterObserver(gateCounterObserver);
311 mpsSimulator->SetMeetingPositionCallback(
312 [
this](
const auto &bondDims)
313 -> QC::TensorNetworks::MPSSimulatorInterface::IndexType {
314 if (upcomingGates.empty() ||
315 upcomingGateIndex >= upcomingGates.size()) {
319 const size_t nQ = bondDims.size() + 1;
321 if (!dummySim || dummySim->getNrQubits() != nQ) {
322 dummySim = std::make_unique<Simulators::MPSDummySimulator>(nQ);
323 dummySim->SetMaxBondDimension(
324 limitSize ?
static_cast<long long int>(chi) : 0);
325 dummySim->setGrowthFactorGate(growthFactorGate);
326 dummySim->setGrowthFactorSwap(growthFactorSwap);
332 dummySim->setTotalSwappingCost(0);
350 std::vector<double> bondDimsD(bondDims.begin(), bondDims.end());
351 dummySim->SetCurrentBondDimensions(bondDimsD);
362 const auto &op = upcomingGates[upcomingGateIndex];
363 const auto qbits = op->AffectedQubits();
365 if (qbits.size() != 2) {
366 std::cerr <<
"Error: Meeting position callback called for a gate "
367 "that does not have exactly 2 qubits."
403 double bestCost = std::numeric_limits<double>::infinity();
404 auto res = dummySim->FindBestMeetingPosition(
405 upcomingGates, upcomingGateIndex, lookaheadDepth,
406 lookaheadDepthWithHeuristic, 0, bestCost);
411 dummySim->SwapQubitsToPosition(qbits[0], qbits[1], res);
412 dummySim->ApplyGate(op);
442 long long int GetGatesCounter()
const override {
return upcomingGateIndex; }
453 void SetGatesCounter(
long long int counter)
override {
454 upcomingGateIndex = counter;
465 void IncrementGatesCounter()
override { ++upcomingGateIndex; }
467 double getGrowthFactorSwap()
const override {
return growthFactorSwap; }
468 double getGrowthFactorGate()
const override {
return growthFactorGate; }
470 void setGrowthFactorSwap(
double factor)
override {
471 growthFactorSwap = factor;
472 if (dummySim) dummySim->setGrowthFactorSwap(factor);
475 void setGrowthFactorGate(
double factor)
override {
476 growthFactorGate = factor;
477 if (dummySim) dummySim->setGrowthFactorGate(factor);
488 void Configure(
const char *key,
const char *value)
override {
489 if (std::string(
"method") == key) {
490 if (std::string(
"statevector") == value)
491 simulationType = SimulationType::kStatevector;
492 else if (std::string(
"matrix_product_state") == value)
493 simulationType = SimulationType::kMatrixProductState;
494 else if (std::string(
"stabilizer") == value)
495 simulationType = SimulationType::kStabilizer;
496 else if (std::string(
"tensor_network") == value)
497 simulationType = SimulationType::kTensorNetwork;
498 else if (std::string(
"pauli_propagator") == value)
499 simulationType = SimulationType::kPauliPropagator;
500 else if (std::string(
"path_integral") == value)
501 simulationType = SimulationType::kPathIntegral;
502 }
else if (std::string(
"matrix_product_state_truncation_threshold") ==
504 singularValueThreshold = std::stod(value);
505 if (singularValueThreshold > 0.) {
506 limitEntanglement =
true;
508 mpsSimulator->setLimitEntanglement(singularValueThreshold);
510 limitEntanglement =
false;
511 }
else if (std::string(
"matrix_product_state_max_bond_dimension") == key) {
512 chi = std::stoi(value);
515 if (mpsSimulator) mpsSimulator->setLimitBondDimension(chi);
517 dummySim->SetMaxBondDimension(
static_cast<long long int>(chi));
520 if (mpsSimulator) mpsSimulator->setLimitBondDimension(0);
521 if (dummySim) dummySim->SetMaxBondDimension(0);
523 }
else if (std::string(
"mps_sample_measure_algorithm") == key)
524 useMPSMeasureNoCollapse = std::string(
"mps_probabilities") == value;
525 else if (std::string(
"pauli_propagator_coefficient_threshold") == key) {
526 ppCoefficientThreshold = std::stod(value);
527 if (pp && ppCoefficientThreshold > 0.)
528 pp->SetCoefficientThreshold(ppCoefficientThreshold);
529 }
else if (std::string(
"pauli_propagator_pauli_weight_threshold") == key) {
530 ppPauliWeightThreshold = std::stoull(value);
531 if (pp && ppPauliWeightThreshold < std::numeric_limits<size_t>::max())
532 pp->SetPauliWeightThreshold(ppPauliWeightThreshold);
533 }
else if (std::string(
"pauli_propagator_steps_between_trims") == key) {
534 ppStepsBetweenTrims = std::stoi(value);
535 if (pp && ppStepsBetweenTrims < std::numeric_limits<int>::max())
536 pp->SetStepsBetweenTrims(ppStepsBetweenTrims);
548 if (std::string(
"method") == key) {
549 switch (simulationType) {
550 case SimulationType::kStatevector:
551 return "statevector";
552 case SimulationType::kMatrixProductState:
553 return "matrix_product_state";
554 case SimulationType::kStabilizer:
556 case SimulationType::kTensorNetwork:
557 return "tensor_network";
558 case SimulationType::kPauliPropagator:
559 return "pauli_propagator";
560 case SimulationType::kPathIntegral:
561 return "path_integral";
565 }
else if (std::string(
"matrix_product_state_truncation_threshold") ==
567 if (limitEntanglement && singularValueThreshold > 0.) {
568 std::ostringstream oss;
569 oss << std::setprecision(std::numeric_limits<double>::max_digits10)
570 << singularValueThreshold;
573 }
else if (std::string(
"matrix_product_state_max_bond_dimension") == key) {
574 if (limitSize && chi > 0)
return std::to_string(chi);
575 }
else if (std::string(
"mps_sample_measure_algorithm") == key) {
576 return useMPSMeasureNoCollapse ?
"mps_probabilities"
577 :
"mps_apply_measure";
591 if ((simulationType == SimulationType::kStatevector && state) ||
592 (simulationType == SimulationType::kMatrixProductState &&
594 (simulationType == SimulationType::kStabilizer && cliffordSimulator) ||
595 (simulationType == SimulationType::kTensorNetwork && tensorNetwork))
598 const size_t oldNrQubits = nrQubits;
599 nrQubits += num_qubits;
600 if (simulationType == SimulationType::kPauliPropagator)
601 if (pp) pp->SetNrQubits(
static_cast<int>(nrQubits));
621 void Clear()
override {
623 mpsSimulator =
nullptr;
624 cliffordSimulator =
nullptr;
625 tensorNetwork =
nullptr;
627 pathIntegralSimulator =
nullptr;
630 upcomingGateIndex = 0;
631 upcomingGates.clear();
648 if (qubits.size() >
sizeof(
size_t) * 8)
650 <<
"Warning: The number of qubits to measure is larger than the "
651 "number of bits in the size_t type, the outcome will be undefined"
658 if (simulationType == SimulationType::kStatevector) {
659 for (
size_t qubit : qubits) {
660 if (state->MeasureQubit(
static_cast<unsigned int>(qubit))) res |= mask;
663 }
else if (simulationType == SimulationType::kStabilizer) {
664 for (
size_t qubit : qubits) {
665 if (cliffordSimulator->MeasureQubit(
static_cast<unsigned int>(qubit)))
669 }
else if (simulationType == SimulationType::kTensorNetwork) {
670 for (
size_t qubit : qubits) {
671 if (tensorNetwork->Measure(
static_cast<unsigned int>(qubit)))
675 }
else if (simulationType == SimulationType::kPauliPropagator) {
676 std::vector<int> qubitsInt;
677 qubitsInt.reserve(qubits.size());
678 for (
const auto q : qubits)
679 qubitsInt.push_back(
static_cast<int>(q));
680 const auto res = pp->Measure(qubitsInt);
682 for (
size_t i = 0; i < res.size(); ++i) {
683 if (res[i]) result |= mask;
687 }
else if (simulationType == SimulationType::kPathIntegral) {
688 for (
size_t qubit : qubits) {
689 if (pathIntegralSimulator->MeasureQubit(qubit)) res |= mask;
701 const std::set<Eigen::Index> qubitsSet(qubits.begin(), qubits.end());
702 auto measured = mpsSimulator->MeasureQubits(qubitsSet);
704 if (measured[qubit]) res |= mask;
710 NotifyObservers(qubits);
722 std::vector<bool> res(qubits.size(),
false);
725 if (simulationType == SimulationType::kStatevector) {
726 for (
size_t q = 0; q < qubits.size(); ++q)
727 if (state->MeasureQubit(
static_cast<unsigned int>(qubits[q])))
729 }
else if (simulationType == SimulationType::kStabilizer) {
730 for (
size_t q = 0; q < qubits.size(); ++q)
731 if (cliffordSimulator->MeasureQubit(
732 static_cast<unsigned int>(qubits[q])))
734 }
else if (simulationType == SimulationType::kTensorNetwork) {
735 for (
size_t q = 0; q < qubits.size(); ++q)
736 if (tensorNetwork->Measure(
static_cast<unsigned int>(qubits[q])))
738 }
else if (simulationType == SimulationType::kPauliPropagator) {
739 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
740 res = pp->Measure(qubitsInt);
741 }
else if (simulationType == SimulationType::kPathIntegral) {
742 for (
size_t q = 0; q < qubits.size(); ++q)
743 if (pathIntegralSimulator->MeasureQubit(qubits[q])) res[q] =
true;
745 const std::set<Eigen::Index> qubitsSet(qubits.begin(), qubits.end());
746 auto measured = mpsSimulator->MeasureQubits(qubitsSet);
747 for (
size_t q = 0; q < qubits.size(); ++q)
748 if (measured[qubits[q]]) res[q] =
true;
751 NotifyObservers(qubits);
763 QC::Gates::PauliXGate xGate;
766 if (simulationType == SimulationType::kStatevector) {
767 for (
size_t qubit : qubits)
768 if (state->MeasureQubit(
static_cast<unsigned int>(qubit)))
769 state->ApplyGate(xGate,
static_cast<unsigned int>(qubit));
770 }
else if (simulationType == SimulationType::kStabilizer) {
771 for (
size_t qubit : qubits)
772 if (cliffordSimulator->MeasureQubit(
static_cast<unsigned int>(qubit)))
773 cliffordSimulator->ApplyX(
static_cast<unsigned int>(qubit));
774 }
else if (simulationType == SimulationType::kTensorNetwork) {
775 for (
size_t qubit : qubits)
776 if (tensorNetwork->Measure(
static_cast<unsigned int>(qubit)))
777 tensorNetwork->AddGate(xGate,
static_cast<unsigned int>(qubit));
778 }
else if (simulationType == SimulationType::kPauliPropagator) {
779 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
780 const auto res = pp->Measure(qubitsInt);
781 for (
size_t i = 0; i < res.size(); ++i) {
782 if (res[i]) pp->ApplyX(qubitsInt[i]);
784 }
else if (simulationType == SimulationType::kPathIntegral) {
785 for (
size_t qubit : qubits)
786 if (pathIntegralSimulator->MeasureQubit(qubit)) {
787 QC::Gates::AppliedGate<> gate(xGate.getRawOperatorMatrix(), qubit);
788 pathIntegralSimulator->PropagateStep(
789 gate, pathIntegralSimulator->Amplitudes());
792 for (
size_t qubit : qubits)
793 if (mpsSimulator->MeasureQubit(
static_cast<unsigned int>(qubit)))
794 mpsSimulator->ApplyGate(xGate,
static_cast<unsigned int>(qubit));
798 NotifyObservers(qubits);
813 if (simulationType == SimulationType::kMatrixProductState)
814 return mpsSimulator->getBasisStateProbability(
815 static_cast<unsigned int>(outcome));
816 else if (simulationType == SimulationType::kStabilizer)
817 return cliffordSimulator->getBasisStateProbability(
818 static_cast<unsigned int>(outcome));
819 else if (simulationType == SimulationType::kTensorNetwork)
820 return tensorNetwork->getBasisStateProbability(outcome);
821 else if (simulationType == SimulationType::kPauliPropagator)
822 return pp->Probability(outcome);
823 else if (simulationType == SimulationType::kPathIntegral)
824 return pathIntegralSimulator->Probability(outcome);
826 return state->getBasisStateProbability(
static_cast<unsigned int>(outcome));
840 if (simulationType == SimulationType::kMatrixProductState)
841 return mpsSimulator->getBasisStateAmplitude(
842 static_cast<unsigned int>(outcome));
843 else if (simulationType == SimulationType::kPathIntegral)
844 return pathIntegralSimulator->AmplitudeForOutcome(outcome);
845 else if (simulationType == SimulationType::kStabilizer)
846 throw std::runtime_error(
847 "QCSimState::Amplitude: Invalid simulation type for obtaining the "
848 "amplitude of the specified outcome.");
849 else if (simulationType == SimulationType::kTensorNetwork)
850 throw std::runtime_error(
851 "QCSimState::Amplitude: Not supported for the "
852 "tensor network simulator.");
853 else if (simulationType == SimulationType::kPauliPropagator)
854 throw std::runtime_error(
855 "QCSimState::Amplitude: Invalid simulation type for obtaining the "
856 "amplitude of the specified outcome.");
858 return state->getBasisStateAmplitude(
static_cast<unsigned int>(outcome));
874 std::complex<double> ProjectOnZero()
override {
875 if (simulationType == SimulationType::kMatrixProductState)
876 return mpsSimulator->ProjectOnZero();
893 if (simulationType == SimulationType::kTensorNetwork)
894 throw std::runtime_error(
895 "QCSimState::AllProbabilities: Invalid "
896 "simulation type for obtaining probabilities.");
897 else if (simulationType == SimulationType::kStabilizer)
898 return cliffordSimulator->AllProbabilities();
899 else if (simulationType == SimulationType::kPauliPropagator) {
901 std::vector<double> result(nrBasisStates);
902 for (
size_t i = 0; i < nrBasisStates; ++i) result[i] = pp->Probability(i);
904 }
else if (simulationType == SimulationType::kPathIntegral) {
906 std::vector<double> result(nrBasisStates);
907 for (
size_t i = 0; i < nrBasisStates; ++i)
908 result[i] = pathIntegralSimulator->Probability(i);
912 const Eigen::VectorXcd probs =
913 simulationType == SimulationType::kMatrixProductState
914 ? mpsSimulator->getRegisterStorage().cwiseAbs2()
915 : state->getRegisterStorage().cwiseAbs2();
917 std::vector<double> result(probs.size());
919 for (
int i = 0; i < probs.size(); ++i) result[i] = probs[i].real();
937 if (simulationType == SimulationType::kStabilizer)
938 throw std::runtime_error(
939 "QCSimState::Probabilities: Invalid simulation "
940 "type for obtaining probabilities.");
941 else if (simulationType == SimulationType::kTensorNetwork) {
943 throw std::runtime_error(
944 "QCSimState::Probabilities: Not implemented yet "
945 "for the tensor network simulator.");
948 std::vector<double> result(qubits.size());
950 if (simulationType == SimulationType::kMatrixProductState) {
951 for (
int i = 0; i < static_cast<int>(qubits.size()); ++i)
952 result[i] = mpsSimulator->getBasisStateProbability(qubits[i]);
953 }
else if (simulationType == SimulationType::kPauliPropagator) {
954 for (
int i = 0; i < static_cast<int>(qubits.size()); ++i)
955 result[i] = pp->Probability(qubits[i]);
956 }
else if (simulationType == SimulationType::kPathIntegral) {
957 for (
int i = 0; i < static_cast<int>(qubits.size()); ++i)
958 result[i] = pathIntegralSimulator->Probability(qubits[i]);
960 const Eigen::VectorXcd ® = state->getRegisterStorage();
962 for (
int i = 0; i < static_cast<int>(qubits.size()); ++i)
963 result[i] = std::norm(reg[qubits[i]]);
985 std::unordered_map<Types::qubit_t, Types::qubit_t>
SampleCounts(
987 if (qubits.empty() || shots == 0)
return {};
989 if (qubits.size() >
sizeof(
size_t) * 8)
991 <<
"Warning: The number of qubits to measure is larger than the "
992 "number of bits in the size_t type, the outcome will be undefined"
998 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
1002 if (simulationType == SimulationType::kMatrixProductState) {
1004 if (useMPSMeasureNoCollapse) {
1006 const std::set<Eigen::Index> qset(qubits.begin(), qubits.end());
1010 for (
size_t shot = 0; shot < shots; ++shot) {
1016 for (
auto q : qubits) {
1017 const size_t qubitMask = 1ULL << q;
1018 if (measRaw & qubitMask) meas |= mask;
1024 }
else if (qset.size() > 1) {
1025 mpsSimulator->MoveAtBeginningOfChain(qset);
1028 for (
size_t shot = 0; shot < shots; ++shot) {
1029 const auto measRaw = mpsSimulator->MeasureNoCollapse(qset);
1035 for (
auto q : qubits) {
1036 if (measRaw.at(q)) meas |= mask;
1043 }
else if (qset.size() == 1) {
1046 const auto prob0 = mpsSimulator->GetProbability(qubits[0]);
1047 for (
size_t shot = 0; shot < shots; ++shot) {
1048 const size_t meas = uniformZeroOne(rng) < prob0 ? 0ULL : 1ULL;
1051 for (
size_t i = 1; i < qubits.size(); ++i) {
1061 auto savedState = mpsSimulator->getState();
1062 for (
size_t shot = 0; shot < shots; ++shot) {
1063 const size_t meas =
Measure(qubits);
1065 mpsSimulator->setState(savedState);
1068 }
else if (simulationType == SimulationType::kStabilizer) {
1069 cliffordSimulator->SaveState();
1070 for (
size_t shot = 0; shot < shots; ++shot) {
1071 const size_t meas =
Measure(qubits);
1073 cliffordSimulator->RestoreState();
1075 cliffordSimulator->ClearSavedState();
1076 }
else if (simulationType == SimulationType::kTensorNetwork) {
1077 tensorNetwork->SaveState();
1078 for (
size_t shot = 0; shot < shots; ++shot) {
1079 const size_t meas =
Measure(qubits);
1081 tensorNetwork->RestoreState();
1083 tensorNetwork->ClearSavedState();
1084 }
else if (simulationType == SimulationType::kPauliPropagator) {
1085 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
1086 for (
size_t shot = 0; shot < shots; ++shot) {
1087 const auto res = pp->Sample(qubitsInt);
1090 for (
size_t i = 0; i < qubits.size(); ++i) {
1091 if (res[i]) meas |= (1ULL << i);
1096 }
else if (simulationType == SimulationType::kPathIntegral) {
1097 if (nrQubits < 64) {
1099 const auto &litudes = pathIntegralSimulator->Amplitudes();
1102 for (
size_t shot = 0; shot < shots; ++shot) {
1103 const double prob = 1. - uniformZeroOne(rng);
1104 const size_t measRaw = alias.
Sample(prob);
1108 for (
auto q : qubits) {
1109 const size_t qubitMask = 1ULL << q;
1110 if ((measRaw & qubitMask) != 0) meas |= mask;
1120 for (
auto q : qubits) {
1121 const size_t qubitMask = 1ULL << q;
1122 if ((measRaw & qubitMask) != 0) meas |= mask;
1128 throw std::runtime_error(
1129 "QCSimState::SampleCounts: The path integral simulator does not "
1130 "support sampling for more than 63 qubits into 64 bits integers.");
1134 const auto &statev = state->getRegisterStorage();
1138 for (
size_t shot = 0; shot < shots; ++shot) {
1139 const double prob = 1. - uniformZeroOne(rng);
1140 const size_t measRaw = alias.
Sample(prob);
1144 for (
auto q : qubits) {
1145 const size_t qubitMask = 1ULL << q;
1146 if ((measRaw & qubitMask) != 0) meas |= mask;
1153 for (
size_t shot = 0; shot < shots; ++shot) {
1158 for (
auto q : qubits) {
1159 const size_t qubitMask = 1ULL << q;
1160 if ((measRaw & qubitMask) != 0) meas |= mask;
1170 NotifyObservers(qubits);
1188 std::unordered_map<std::vector<bool>,
Types::qubit_t> SampleCountsMany(
1190 if (qubits.empty() || shots == 0)
return {};
1196 if (simulationType == SimulationType::kMatrixProductState) {
1198 if (useMPSMeasureNoCollapse) {
1200 const std::set<Eigen::Index> qset(qubits.begin(), qubits.end());
1204 for (
size_t shot = 0; shot < shots; ++shot) {
1205 const auto meas = MeasureNoCollapseMany();
1209 std::vector<bool> measVec(qubits.size());
1210 for (
size_t i = 0; i < qubits.size(); ++i)
1211 measVec[i] = meas[qubits[i]];
1215 }
else if (qset.size() > 1) {
1216 mpsSimulator->MoveAtBeginningOfChain(qset);
1219 for (
size_t shot = 0; shot < shots; ++shot) {
1220 const auto meas = mpsSimulator->MeasureNoCollapse(qset);
1224 std::vector<bool> measVec(qubits.size());
1225 for (
size_t i = 0; i < qubits.size(); ++i)
1226 measVec[i] = meas.at(qubits[i]);
1230 }
else if (qset.size() == 1) {
1233 const auto prob0 = mpsSimulator->GetProbability(qubits[0]);
1234 for (
size_t shot = 0; shot < shots; ++shot) {
1235 const size_t meas = uniformZeroOne(rng) < prob0 ? 0ULL : 1ULL;
1236 const std::vector<bool> m(qubits.size(), meas);
1243 auto savedState = mpsSimulator->getState();
1244 for (
size_t shot = 0; shot < shots; ++shot) {
1245 const auto meas = MeasureMany(qubits);
1248 mpsSimulator->setState(savedState);
1251 }
else if (simulationType == SimulationType::kStabilizer) {
1252 cliffordSimulator->SaveState();
1253 for (
size_t shot = 0; shot < shots; ++shot) {
1254 const auto meas = MeasureMany(qubits);
1256 cliffordSimulator->RestoreState();
1258 cliffordSimulator->ClearSavedState();
1259 }
else if (simulationType == SimulationType::kTensorNetwork) {
1260 tensorNetwork->SaveState();
1261 for (
size_t shot = 0; shot < shots; ++shot) {
1262 const auto meas = MeasureMany(qubits);
1264 tensorNetwork->RestoreState();
1266 tensorNetwork->ClearSavedState();
1267 }
else if (simulationType == SimulationType::kPauliPropagator) {
1268 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
1269 for (
size_t shot = 0; shot < shots; ++shot) {
1270 const auto meas = pp->Sample(qubitsInt);
1273 }
else if (simulationType == SimulationType::kPathIntegral) {
1274 if (nrQubits < 64) {
1276 const auto &litudes = pathIntegralSimulator->Amplitudes();
1278 for (
size_t shot = 0; shot < shots; ++shot) {
1279 const double prob = 1. - uniformZeroOne(rng);
1280 const size_t measRaw = alias.
Sample(prob);
1281 std::vector<bool> meas(qubits.size(),
false);
1282 for (
size_t i = 0; i < qubits.size(); ++i)
1283 if (((measRaw >> qubits[i]) & 1) == 1) meas[i] =
true;
1287 for (
size_t shot = 0; shot < shots; ++shot) {
1288 const auto measRaw = MeasureNoCollapseMany();
1289 std::vector<bool> meas(qubits.size(),
false);
1291 for (
size_t i = 0; i < qubits.size(); ++i)
1292 if (measRaw[qubits[i]]) meas[i] =
true;
1299 const auto &litudes = pathIntegralSimulator->Amplitudes();
1302 for (
size_t shot = 0; shot < shots; ++shot) {
1303 const double prob = 1. - uniformZeroOne(rng);
1304 const auto measRaw = alias.
Sample(prob);
1305 std::vector<bool> meas(qubits.size(),
false);
1306 for (
size_t i = 0; i < qubits.size(); ++i)
1307 if (measRaw.get(qubits[i])) meas[i] =
true;
1311 for (
size_t shot = 0; shot < shots; ++shot) {
1312 const auto measRaw = MeasureNoCollapseMany();
1313 std::vector<bool> meas(qubits.size(),
false);
1315 for (
size_t i = 0; i < qubits.size(); ++i)
1316 if (measRaw[qubits[i]]) meas[i] =
true;
1324 const auto &statev = state->getRegisterStorage();
1328 for (
size_t shot = 0; shot < shots; ++shot) {
1329 const double prob = 1. - uniformZeroOne(rng);
1330 const size_t measRaw = alias.
Sample(prob);
1332 std::vector<bool> meas(qubits.size(),
false);
1334 for (
size_t i = 0; i < qubits.size(); ++i)
1335 if (((measRaw >> qubits[i]) & 1) == 1) meas[i] =
true;
1340 for (
size_t shot = 0; shot < shots; ++shot) {
1341 const auto measRaw = MeasureNoCollapseMany();
1342 std::vector<bool> meas(qubits.size(),
false);
1344 for (
size_t i = 0; i < qubits.size(); ++i)
1345 if (measRaw[qubits[i]]) meas[i] =
true;
1353 NotifyObservers(qubits);
1369 double ExpectationValue(
const std::string &pauliStringOrig)
override {
1370 if (pauliStringOrig.empty())
return 1.0;
1372 std::string pauliString = pauliStringOrig;
1375 const auto pauliOp = toupper(pauliString[i]);
1376 if (pauliOp !=
'I' && pauliOp !=
'Z')
return 0.0;
1382 if (simulationType == SimulationType::kStabilizer)
1383 return cliffordSimulator->ExpectationValue(pauliString);
1384 else if (simulationType == SimulationType::kTensorNetwork)
1385 return tensorNetwork->ExpectationValue(pauliString);
1386 else if (simulationType == SimulationType::kPauliPropagator)
1387 return pp->ExpectationValue(pauliString);
1388 else if (simulationType == SimulationType::kPathIntegral)
1389 return pathIntegralSimulator->ExpectationValue(pauliString);
1392 static const QC::Gates::PauliXGate<> xgate;
1393 static const QC::Gates::PauliYGate<> ygate;
1394 static const QC::Gates::PauliZGate<> zgate;
1396 std::vector<QC::Gates::AppliedGate<Eigen::MatrixXcd>> pauliStringVec;
1397 pauliStringVec.reserve(pauliString.size());
1399 for (
size_t q = 0; q < pauliString.size(); ++q) {
1400 switch (toupper(pauliString[q])) {
1402 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(
1404 pauliStringVec.emplace_back(std::move(ag));
1407 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(
1409 pauliStringVec.emplace_back(std::move(ag));
1412 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(
1414 pauliStringVec.emplace_back(std::move(ag));
1423 if (pauliStringVec.empty())
return 1.0;
1425 if (simulationType == SimulationType::kMatrixProductState)
1426 return mpsSimulator->ExpectationValue(pauliStringVec).real();
1428 return state->ExpectationValue(pauliStringVec).real();
1438 SimulatorType GetType()
const override {
return SimulatorType::kQCSim; }
1458 void Flush()
override {}
1489 if (simulationType == SimulationType::kMatrixProductState)
1490 mpsSimulator->SaveState();
1491 else if (simulationType == SimulationType::kStabilizer)
1492 cliffordSimulator->SaveState();
1493 else if (simulationType == SimulationType::kTensorNetwork)
1494 tensorNetwork->SaveState();
1495 else if (simulationType == SimulationType::kPauliPropagator)
1497 else if (simulationType == SimulationType::kPathIntegral)
1498 pathIntegralSimulator->SaveState();
1512 if (simulationType == SimulationType::kMatrixProductState)
1513 mpsSimulator->RestoreState();
1514 else if (simulationType == SimulationType::kStabilizer)
1515 cliffordSimulator->RestoreState();
1516 else if (simulationType == SimulationType::kTensorNetwork)
1517 tensorNetwork->RestoreState();
1518 else if (simulationType == SimulationType::kPauliPropagator)
1520 else if (simulationType == SimulationType::kPathIntegral)
1521 pathIntegralSimulator->RestoreState();
1523 state->RestoreState();
1533 std::complex<double> AmplitudeRaw(
Types::qubit_t outcome)
override {
1546 enableMultithreading = multithreading;
1547 if (state) state->SetMultithreading(multithreading);
1548 if (cliffordSimulator) cliffordSimulator->SetMultithreading(multithreading);
1549 if (tensorNetwork) tensorNetwork->SetMultithreading(multithreading);
1552 pp->EnableParallel();
1554 pp->DisableParallel();
1556 if (pathIntegralSimulator) {
1557 enableMultithreading =
false;
1580 bool IsQcsim()
const override {
return true; }
1602 <<
"Warning: The number of qubits to measure is larger than the "
1603 "number of bits in the Types::qubit_t type, the outcome will be "
1607 if (simulationType == SimulationType::kStatevector)
1608 return state->MeasureNoCollapse();
1609 else if (simulationType == SimulationType::kMatrixProductState) {
1610 const auto measured = mpsSimulator->MeasureNoCollapse();
1614 if (measured.at(q)) result |= mask;
1618 }
else if (simulationType == SimulationType::kPauliPropagator) {
1620 std::iota(qubitsInt.begin(), qubitsInt.end(), 0);
1621 const auto res = pp->Sample(qubitsInt);
1623 for (
size_t i = 0; i < res.size(); ++i) {
1624 if (res[i]) result |= (1ULL << i);
1627 }
else if (simulationType == SimulationType::kPathIntegral) {
1628 if (nrQubits < 64) {
1629 const auto measured = pathIntegralSimulator->MeasureNoCollapse();
1633 if (measured.get(q)) result |= mask;
1638 throw std::runtime_error(
1639 "QCSimState::MeasureNoCollapse: The path integral simulator does not "
1640 "support measuring more than 63 qubits into 64 bits integers.");
1644 throw std::runtime_error(
1645 "QCSimState::MeasureNoCollapse: Invalid simulation type for "
1647 "all the qubits without collapsing the state.");
1667 std::vector<bool> MeasureNoCollapseMany()
override {
1668 if (simulationType == SimulationType::kStatevector) {
1670 std::vector<bool> res(nrQubits);
1671 for (
size_t i = 0; i < nrQubits; ++i) res[i] = ((state >> i) & 1) == 1;
1673 }
else if (simulationType == SimulationType::kMatrixProductState) {
1674 const auto measured = mpsSimulator->MeasureNoCollapse();
1675 std::vector<bool> res(nrQubits);
1676 for (
size_t i = 0; i < nrQubits; ++i) res[i] = measured.at(i);
1678 }
else if (simulationType == SimulationType::kPauliPropagator) {
1680 std::iota(qubitsInt.begin(), qubitsInt.end(), 0);
1681 return pp->Sample(qubitsInt);
1682 }
else if (simulationType == SimulationType::kPathIntegral) {
1683 const auto measured = pathIntegralSimulator->MeasureNoCollapse();
1684 std::vector<bool> res(nrQubits);
1685 for (
size_t i = 0; i < nrQubits; ++i) res[i] = measured.get(i);
1689 throw std::runtime_error(
1690 "QCSimState::MeasureNoCollapseMany: Invalid simulation type for "
1691 "measuring all the qubits without collapsing the state.");
1697 SimulationType simulationType =
1698 SimulationType::kStatevector;
1700 std::unique_ptr<QC::QubitRegister<>> state;
1701 std::unique_ptr<QC::TensorNetworks::MPSSimulator>
1703 std::unique_ptr<QC::Clifford::StabilizerSimulator>
1705 std::unique_ptr<TensorNetworks::TensorNetwork>
1707 std::unique_ptr<QcsimPauliPropagator> pp;
1708 std::unique_ptr<PathIntegralSimulator>
1709 pathIntegralSimulator;
1711 size_t nrQubits = 0;
1712 bool limitSize =
false;
1713 bool limitEntanglement =
false;
1714 Eigen::Index chi = 10;
1715 double singularValueThreshold = 0.;
1716 bool enableMultithreading =
true;
1717 bool useMPSMeasureNoCollapse =
1721 double ppCoefficientThreshold = 0.;
1722 size_t ppPauliWeightThreshold = std::numeric_limits<size_t>::max();
1723 int ppStepsBetweenTrims = std::numeric_limits<int>::max();
1725 int lookaheadDepth = 0;
1726 int lookaheadDepthWithHeuristic = 0;
1727 bool useOptimalMeetingPosition =
true;
1728 std::vector<std::shared_ptr<Circuits::IOperation<>>> upcomingGates;
1729 long long int upcomingGateIndex = 0;
1730 double growthFactorSwap = 1.;
1731 double growthFactorGate = 0.65;
1733 std::unique_ptr<Simulators::MPSDummySimulator> dummySim;
1736 class GateCounterObserver :
public ISimulatorObserver {
1738 GateCounterObserver(
long long int &indexRef) : index(indexRef) {}
1742 long long int &index;
1744 std::shared_ptr<GateCounterObserver> gateCounterObserver;
1746 std::mt19937_64 rng;
1747 std::uniform_real_distribution<double> uniformZeroOne;
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)
QC::PathIntegral::FastVectorBool Sample(double v) const
size_t Sample(double v) const
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
uint_fast64_t qubit_t
The type of a qubit.