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 }
else if (simulationType == SimulationType::kPathIntegral) {
94 pathIntegralSimulator = std::make_unique<PathIntegralSimulator>();
95 pathIntegralSimulator->SetStartZeroState(nrQubits);
97 state = std::make_unique<QC::QubitRegister<>>(nrQubits);
114 void InitializeState(
size_t num_qubits,
115 std::vector<std::complex<double>> &litudes)
override {
116 if (num_qubits == 0)
return;
118 nrQubits = num_qubits;
120 if (simulationType != SimulationType::kStatevector)
121 throw std::runtime_error(
122 "QCSimState::InitializeState: Invalid "
123 "simulation type for initializing the state.");
125 Eigen::VectorXcd amplitudesEigen(
126 Eigen::Map<Eigen::VectorXcd, Eigen::Unaligned>(amplitudes.data(),
128 state->setRegisterStorageFastNoNormalize(amplitudesEigen);
167 void InitializeState(
size_t num_qubits,
168 AER::Vector<std::complex<double>> &litudes)
override {
169 if (num_qubits == 0)
return;
171 nrQubits = num_qubits;
173 if (simulationType != SimulationType::kStatevector)
174 throw std::runtime_error(
175 "QCSimState::InitializeState: Invalid "
176 "simulation type for initializing the state.");
178 Eigen::VectorXcd amplitudesEigen(
179 Eigen::Map<Eigen::VectorXcd, Eigen::Unaligned>(amplitudes.data(),
181 state->setRegisterStorageFastNoNormalize(amplitudesEigen);
196 void InitializeState(
size_t num_qubits,
197 Eigen::VectorXcd &litudes)
override {
198 if (num_qubits == 0)
return;
200 nrQubits = num_qubits;
203 if (simulationType != SimulationType::kStatevector)
204 throw std::runtime_error(
205 "QCSimState::InitializeState: Invalid "
206 "simulation type for initializing the state.");
208 state = std::make_unique<QC::QubitRegister<>>(nrQubits, amplitudes);
209 state->SetMultithreading(enableMultithreading);
218 void Reset()
override {
220 mpsSimulator->Clear();
221 else if (cliffordSimulator)
222 cliffordSimulator->Reset();
223 else if (tensorNetwork)
224 tensorNetwork->Clear();
228 pp->ClearOperations();
229 else if (pathIntegralSimulator) {
230 pathIntegralSimulator->Reset();
231 pathIntegralSimulator->SetStartZeroState(nrQubits);
234 upcomingGateIndex = 0;
244 bool SupportsMPSSwapOptimization()
const override {
return true; }
254 void SetInitialQubitsMap(
255 const std::vector<long long int> &initialMap)
override {
257 mpsSimulator->SetInitialQubitsMap(initialMap);
258 if (!dummySim || dummySim->getNrQubits() != initialMap.size()) {
260 std::make_unique<Simulators::MPSDummySimulator>(initialMap.size());
261 dummySim->SetMaxBondDimension(
262 limitSize ?
static_cast<long long int>(chi) : 0);
264 dummySim->setGrowthFactorGate(growthFactorGate);
265 dummySim->setGrowthFactorSwap(growthFactorSwap);
266 dummySim->SetInitialQubitsMap(initialMap);
270 void SetUseOptimalMeetingPosition(
bool enable)
override {
271 useOptimalMeetingPosition = enable;
272 if (mpsSimulator) mpsSimulator->SetUseOptimalMeetingPosition(enable);
275 void SetLookaheadDepth(
int depth)
override {
276 lookaheadDepth = depth;
277 if (mpsSimulator && depth > 0 && !useOptimalMeetingPosition)
278 mpsSimulator->SetUseOptimalMeetingPosition(
true);
281 void SetLookaheadDepthWithHeuristic(
int depth)
override {
282 lookaheadDepthWithHeuristic = depth;
283 if (lookaheadDepth < depth) SetLookaheadDepth(depth);
286 void SetUpcomingGates(
289 upcomingGates = gates;
290 upcomingGateIndex = 0;
292 if (!mpsSimulator || lookaheadDepth <= 0)
return;
297 gateCounterObserver =
298 std::make_shared<GateCounterObserver>(upcomingGateIndex);
299 RegisterObserver(gateCounterObserver);
305 mpsSimulator->SetMeetingPositionCallback(
306 [
this](
const auto &bondDims)
307 -> QC::TensorNetworks::MPSSimulatorInterface::IndexType {
308 if (upcomingGates.empty() ||
309 upcomingGateIndex >= upcomingGates.size()) {
313 const size_t nQ = bondDims.size() + 1;
315 if (!dummySim || dummySim->getNrQubits() != nQ) {
316 dummySim = std::make_unique<Simulators::MPSDummySimulator>(nQ);
317 dummySim->SetMaxBondDimension(
318 limitSize ?
static_cast<long long int>(chi) : 0);
319 dummySim->setGrowthFactorGate(growthFactorGate);
320 dummySim->setGrowthFactorSwap(growthFactorSwap);
326 dummySim->setTotalSwappingCost(0);
344 std::vector<double> bondDimsD(bondDims.begin(), bondDims.end());
345 dummySim->SetCurrentBondDimensions(bondDimsD);
356 const auto &op = upcomingGates[upcomingGateIndex];
357 const auto qbits = op->AffectedQubits();
359 if (qbits.size() != 2) {
360 std::cerr <<
"Error: Meeting position callback called for a gate "
361 "that does not have exactly 2 qubits."
397 double bestCost = std::numeric_limits<double>::infinity();
398 auto res = dummySim->FindBestMeetingPosition(
399 upcomingGates, upcomingGateIndex, lookaheadDepth,
400 lookaheadDepthWithHeuristic, 0, bestCost);
405 dummySim->SwapQubitsToPosition(qbits[0], qbits[1], res);
406 dummySim->ApplyGate(op);
436 long long int GetGatesCounter()
const override {
return upcomingGateIndex; }
447 void SetGatesCounter(
long long int counter)
override {
448 upcomingGateIndex = counter;
459 void IncrementGatesCounter()
override { ++upcomingGateIndex; }
461 double getGrowthFactorSwap()
const override {
return growthFactorSwap; }
462 double getGrowthFactorGate()
const override {
return growthFactorGate; }
464 void setGrowthFactorSwap(
double factor)
override {
465 growthFactorSwap = factor;
466 if (dummySim) dummySim->setGrowthFactorSwap(factor);
469 void setGrowthFactorGate(
double factor)
override {
470 growthFactorGate = factor;
471 if (dummySim) dummySim->setGrowthFactorGate(factor);
482 void Configure(
const char *key,
const char *value)
override {
483 if (std::string(
"method") == key) {
484 if (std::string(
"statevector") == value)
485 simulationType = SimulationType::kStatevector;
486 else if (std::string(
"matrix_product_state") == value)
487 simulationType = SimulationType::kMatrixProductState;
488 else if (std::string(
"stabilizer") == value)
489 simulationType = SimulationType::kStabilizer;
490 else if (std::string(
"tensor_network") == value)
491 simulationType = SimulationType::kTensorNetwork;
492 else if (std::string(
"pauli_propagator") == value)
493 simulationType = SimulationType::kPauliPropagator;
494 else if (std::string(
"path_integral") == value)
495 simulationType = SimulationType::kPathIntegral;
496 }
else if (std::string(
"matrix_product_state_truncation_threshold") ==
498 singularValueThreshold = std::stod(value);
499 if (singularValueThreshold > 0.) {
500 limitEntanglement =
true;
502 mpsSimulator->setLimitEntanglement(singularValueThreshold);
504 limitEntanglement =
false;
505 }
else if (std::string(
"matrix_product_state_max_bond_dimension") == key) {
506 chi = std::stoi(value);
509 if (mpsSimulator) mpsSimulator->setLimitBondDimension(chi);
511 dummySim->SetMaxBondDimension(
static_cast<long long int>(chi));
514 if (mpsSimulator) mpsSimulator->setLimitBondDimension(0);
515 if (dummySim) dummySim->SetMaxBondDimension(0);
517 }
else if (std::string(
"mps_sample_measure_algorithm") == key)
518 useMPSMeasureNoCollapse = std::string(
"mps_probabilities") == value;
529 if (std::string(
"method") == key) {
530 switch (simulationType) {
531 case SimulationType::kStatevector:
532 return "statevector";
533 case SimulationType::kMatrixProductState:
534 return "matrix_product_state";
535 case SimulationType::kStabilizer:
537 case SimulationType::kTensorNetwork:
538 return "tensor_network";
539 case SimulationType::kPauliPropagator:
540 return "pauli_propagator";
541 case SimulationType::kPathIntegral:
542 return "path_integral";
546 }
else if (std::string(
"matrix_product_state_truncation_threshold") ==
548 if (limitEntanglement && singularValueThreshold > 0.) {
549 std::ostringstream oss;
550 oss << std::setprecision(std::numeric_limits<double>::max_digits10)
551 << singularValueThreshold;
554 }
else if (std::string(
"matrix_product_state_max_bond_dimension") == key) {
555 if (limitSize && chi > 0)
return std::to_string(chi);
556 }
else if (std::string(
"mps_sample_measure_algorithm") == key) {
557 return useMPSMeasureNoCollapse ?
"mps_probabilities"
558 :
"mps_apply_measure";
572 if ((simulationType == SimulationType::kStatevector && state) ||
573 (simulationType == SimulationType::kMatrixProductState &&
575 (simulationType == SimulationType::kStabilizer && cliffordSimulator) ||
576 (simulationType == SimulationType::kTensorNetwork && tensorNetwork))
579 const size_t oldNrQubits = nrQubits;
580 nrQubits += num_qubits;
581 if (simulationType == SimulationType::kPauliPropagator)
582 if (pp) pp->SetNrQubits(
static_cast<int>(nrQubits));
602 void Clear()
override {
604 mpsSimulator =
nullptr;
605 cliffordSimulator =
nullptr;
606 tensorNetwork =
nullptr;
608 pathIntegralSimulator =
nullptr;
611 upcomingGateIndex = 0;
612 upcomingGates.clear();
629 if (qubits.size() >
sizeof(
size_t) * 8)
631 <<
"Warning: The number of qubits to measure is larger than the "
632 "number of bits in the size_t type, the outcome will be undefined"
639 if (simulationType == SimulationType::kStatevector) {
640 for (
size_t qubit : qubits) {
641 if (state->MeasureQubit(
static_cast<unsigned int>(qubit))) res |= mask;
644 }
else if (simulationType == SimulationType::kStabilizer) {
645 for (
size_t qubit : qubits) {
646 if (cliffordSimulator->MeasureQubit(
static_cast<unsigned int>(qubit)))
650 }
else if (simulationType == SimulationType::kTensorNetwork) {
651 for (
size_t qubit : qubits) {
652 if (tensorNetwork->Measure(
static_cast<unsigned int>(qubit)))
656 }
else if (simulationType == SimulationType::kPauliPropagator) {
657 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
658 const auto res = pp->Measure(qubitsInt);
660 for (
size_t i = 0; i < res.size(); ++i) {
661 if (res[i]) result |= mask;
665 }
else if (simulationType == SimulationType::kPathIntegral) {
666 for (
size_t qubit : qubits) {
667 if (pathIntegralSimulator->MeasureQubit(qubit)) res |= mask;
679 const std::set<Eigen::Index> qubitsSet(qubits.begin(), qubits.end());
680 auto measured = mpsSimulator->MeasureQubits(qubitsSet);
682 if (measured[qubit]) res |= mask;
688 NotifyObservers(qubits);
700 std::vector<bool> res(qubits.size(),
false);
703 if (simulationType == SimulationType::kStatevector) {
704 for (
size_t q = 0; q < qubits.size(); ++q)
705 if (state->MeasureQubit(
static_cast<unsigned int>(qubits[q])))
707 }
else if (simulationType == SimulationType::kStabilizer) {
708 for (
size_t q = 0; q < qubits.size(); ++q)
709 if (cliffordSimulator->MeasureQubit(
710 static_cast<unsigned int>(qubits[q])))
712 }
else if (simulationType == SimulationType::kTensorNetwork) {
713 for (
size_t q = 0; q < qubits.size(); ++q)
714 if (tensorNetwork->Measure(
static_cast<unsigned int>(qubits[q])))
716 }
else if (simulationType == SimulationType::kPauliPropagator) {
717 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
718 res = pp->Measure(qubitsInt);
719 }
else if (simulationType == SimulationType::kPathIntegral) {
720 for (
size_t q = 0; q < qubits.size(); ++q)
721 if (pathIntegralSimulator->MeasureQubit(qubits[q])) res[q] =
true;
723 const std::set<Eigen::Index> qubitsSet(qubits.begin(), qubits.end());
724 auto measured = mpsSimulator->MeasureQubits(qubitsSet);
725 for (
size_t q = 0; q < qubits.size(); ++q)
726 if (measured[qubits[q]]) res[q] =
true;
729 NotifyObservers(qubits);
741 QC::Gates::PauliXGate xGate;
744 if (simulationType == SimulationType::kStatevector) {
745 for (
size_t qubit : qubits)
746 if (state->MeasureQubit(
static_cast<unsigned int>(qubit)))
747 state->ApplyGate(xGate,
static_cast<unsigned int>(qubit));
748 }
else if (simulationType == SimulationType::kStabilizer) {
749 for (
size_t qubit : qubits)
750 if (cliffordSimulator->MeasureQubit(
static_cast<unsigned int>(qubit)))
751 cliffordSimulator->ApplyX(
static_cast<unsigned int>(qubit));
752 }
else if (simulationType == SimulationType::kTensorNetwork) {
753 for (
size_t qubit : qubits)
754 if (tensorNetwork->Measure(
static_cast<unsigned int>(qubit)))
755 tensorNetwork->AddGate(xGate,
static_cast<unsigned int>(qubit));
756 }
else if (simulationType == SimulationType::kPauliPropagator) {
757 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
758 const auto res = pp->Measure(qubitsInt);
759 for (
size_t i = 0; i < res.size(); ++i) {
760 if (res[i]) pp->ApplyX(qubitsInt[i]);
762 }
else if (simulationType == SimulationType::kPathIntegral) {
763 for (
size_t qubit : qubits)
764 if (pathIntegralSimulator->MeasureQubit(qubit)) {
765 QC::Gates::AppliedGate<> gate(xGate.getRawOperatorMatrix(), qubit);
766 pathIntegralSimulator->PropagateStep(
767 gate, pathIntegralSimulator->Amplitudes());
770 for (
size_t qubit : qubits)
771 if (mpsSimulator->MeasureQubit(
static_cast<unsigned int>(qubit)))
772 mpsSimulator->ApplyGate(xGate,
static_cast<unsigned int>(qubit));
776 NotifyObservers(qubits);
791 if (simulationType == SimulationType::kMatrixProductState)
792 return mpsSimulator->getBasisStateProbability(
793 static_cast<unsigned int>(outcome));
794 else if (simulationType == SimulationType::kStabilizer)
795 return cliffordSimulator->getBasisStateProbability(
796 static_cast<unsigned int>(outcome));
797 else if (simulationType == SimulationType::kTensorNetwork)
798 return tensorNetwork->getBasisStateProbability(outcome);
799 else if (simulationType == SimulationType::kPauliPropagator)
800 return pp->Probability(outcome);
801 else if (simulationType == SimulationType::kPathIntegral)
802 return pathIntegralSimulator->Probability(outcome);
804 return state->getBasisStateProbability(
static_cast<unsigned int>(outcome));
818 if (simulationType == SimulationType::kMatrixProductState)
819 return mpsSimulator->getBasisStateAmplitude(
820 static_cast<unsigned int>(outcome));
821 else if (simulationType == SimulationType::kPathIntegral)
822 return pathIntegralSimulator->AmplitudeForOutcome(outcome);
823 else if (simulationType == SimulationType::kStabilizer)
824 throw std::runtime_error(
825 "QCSimState::Amplitude: Invalid simulation type for obtaining the "
826 "amplitude of the specified outcome.");
827 else if (simulationType == SimulationType::kTensorNetwork)
828 throw std::runtime_error(
829 "QCSimState::Amplitude: Not supported for the "
830 "tensor network simulator.");
831 else if (simulationType == SimulationType::kPauliPropagator)
832 throw std::runtime_error(
833 "QCSimState::Amplitude: Invalid simulation type for obtaining the "
834 "amplitude of the specified outcome.");
836 return state->getBasisStateAmplitude(
static_cast<unsigned int>(outcome));
852 std::complex<double> ProjectOnZero()
override {
853 if (simulationType == SimulationType::kMatrixProductState)
854 return mpsSimulator->ProjectOnZero();
871 if (simulationType == SimulationType::kTensorNetwork)
872 throw std::runtime_error(
873 "QCSimState::AllProbabilities: Invalid "
874 "simulation type for obtaining probabilities.");
875 else if (simulationType == SimulationType::kStabilizer)
876 return cliffordSimulator->AllProbabilities();
877 else if (simulationType == SimulationType::kPauliPropagator) {
879 std::vector<double> result(nrBasisStates);
880 for (
size_t i = 0; i < nrBasisStates; ++i) result[i] = pp->Probability(i);
882 }
else if (simulationType == SimulationType::kPathIntegral) {
884 std::vector<double> result(nrBasisStates);
885 for (
size_t i = 0; i < nrBasisStates; ++i)
886 result[i] = pathIntegralSimulator->Probability(i);
890 const Eigen::VectorXcd probs =
891 simulationType == SimulationType::kMatrixProductState
892 ? mpsSimulator->getRegisterStorage().cwiseAbs2()
893 : state->getRegisterStorage().cwiseAbs2();
895 std::vector<double> result(probs.size());
897 for (
int i = 0; i < probs.size(); ++i) result[i] = probs[i].real();
915 if (simulationType == SimulationType::kStabilizer)
916 throw std::runtime_error(
917 "QCSimState::Probabilities: Invalid simulation "
918 "type for obtaining probabilities.");
919 else if (simulationType == SimulationType::kTensorNetwork) {
921 throw std::runtime_error(
922 "QCSimState::Probabilities: Not implemented yet "
923 "for the tensor network simulator.");
926 std::vector<double> result(qubits.size());
928 if (simulationType == SimulationType::kMatrixProductState) {
929 for (
int i = 0; i < static_cast<int>(qubits.size()); ++i)
930 result[i] = mpsSimulator->getBasisStateProbability(qubits[i]);
931 }
else if (simulationType == SimulationType::kPauliPropagator) {
932 for (
int i = 0; i < static_cast<int>(qubits.size()); ++i)
933 result[i] = pp->Probability(qubits[i]);
934 }
else if (simulationType == SimulationType::kPathIntegral) {
935 for (
int i = 0; i < static_cast<int>(qubits.size()); ++i)
936 result[i] = pathIntegralSimulator->Probability(qubits[i]);
938 const Eigen::VectorXcd ® = state->getRegisterStorage();
940 for (
int i = 0; i < static_cast<int>(qubits.size()); ++i)
941 result[i] = std::norm(reg[qubits[i]]);
963 std::unordered_map<Types::qubit_t, Types::qubit_t>
SampleCounts(
965 if (qubits.empty() || shots == 0)
return {};
967 if (qubits.size() >
sizeof(
size_t) * 8)
969 <<
"Warning: The number of qubits to measure is larger than the "
970 "number of bits in the size_t type, the outcome will be undefined"
976 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
980 if (simulationType == SimulationType::kMatrixProductState) {
982 if (useMPSMeasureNoCollapse) {
984 const std::set<Eigen::Index> qset(qubits.begin(), qubits.end());
988 for (
size_t shot = 0; shot < shots; ++shot) {
994 for (
auto q : qubits) {
995 const size_t qubitMask = 1ULL << q;
996 if (measRaw & qubitMask) meas |= mask;
1002 }
else if (qset.size() > 1) {
1003 mpsSimulator->MoveAtBeginningOfChain(qset);
1006 for (
size_t shot = 0; shot < shots; ++shot) {
1007 const auto measRaw = mpsSimulator->MeasureNoCollapse(qset);
1013 for (
auto q : qubits) {
1014 if (measRaw.at(q)) meas |= mask;
1021 }
else if (qset.size() == 1) {
1024 const auto prob0 = mpsSimulator->GetProbability(qubits[0]);
1025 for (
size_t shot = 0; shot < shots; ++shot) {
1026 const size_t meas = uniformZeroOne(rng) < prob0 ? 0ULL : 1ULL;
1029 for (
size_t i = 1; i < qubits.size(); ++i) {
1039 auto savedState = mpsSimulator->getState();
1040 for (
size_t shot = 0; shot < shots; ++shot) {
1041 const size_t meas =
Measure(qubits);
1043 mpsSimulator->setState(savedState);
1046 }
else if (simulationType == SimulationType::kStabilizer) {
1047 cliffordSimulator->SaveState();
1048 for (
size_t shot = 0; shot < shots; ++shot) {
1049 const size_t meas =
Measure(qubits);
1051 cliffordSimulator->RestoreState();
1053 cliffordSimulator->ClearSavedState();
1054 }
else if (simulationType == SimulationType::kTensorNetwork) {
1055 tensorNetwork->SaveState();
1056 for (
size_t shot = 0; shot < shots; ++shot) {
1057 const size_t meas =
Measure(qubits);
1059 tensorNetwork->RestoreState();
1061 tensorNetwork->ClearSavedState();
1062 }
else if (simulationType == SimulationType::kPauliPropagator) {
1063 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
1064 for (
size_t shot = 0; shot < shots; ++shot) {
1065 const auto res = pp->Sample(qubitsInt);
1068 for (
size_t i = 0; i < qubits.size(); ++i) {
1069 if (res[i]) meas |= (1ULL << i);
1074 }
else if (simulationType == SimulationType::kPathIntegral) {
1075 if (nrQubits < 64) {
1077 const auto &litudes = pathIntegralSimulator->Amplitudes();
1080 for (
size_t shot = 0; shot < shots; ++shot) {
1081 const double prob = 1. - uniformZeroOne(rng);
1082 const size_t measRaw = alias.
Sample(prob);
1086 for (
auto q : qubits) {
1087 const size_t qubitMask = 1ULL << q;
1088 if ((measRaw & qubitMask) != 0) meas |= mask;
1098 for (
auto q : qubits) {
1099 const size_t qubitMask = 1ULL << q;
1100 if ((measRaw & qubitMask) != 0) meas |= mask;
1106 throw std::runtime_error(
1107 "QCSimState::SampleCounts: The path integral simulator does not "
1108 "support sampling for more than 63 qubits into 64 bits integers.");
1112 const auto &statev = state->getRegisterStorage();
1116 for (
size_t shot = 0; shot < shots; ++shot) {
1117 const double prob = 1. - uniformZeroOne(rng);
1118 const size_t measRaw = alias.
Sample(prob);
1122 for (
auto q : qubits) {
1123 const size_t qubitMask = 1ULL << q;
1124 if ((measRaw & qubitMask) != 0) meas |= mask;
1131 for (
size_t shot = 0; shot < shots; ++shot) {
1136 for (
auto q : qubits) {
1137 const size_t qubitMask = 1ULL << q;
1138 if ((measRaw & qubitMask) != 0) meas |= mask;
1148 NotifyObservers(qubits);
1166 std::unordered_map<std::vector<bool>,
Types::qubit_t> SampleCountsMany(
1168 if (qubits.empty() || shots == 0)
return {};
1174 if (simulationType == SimulationType::kMatrixProductState) {
1176 if (useMPSMeasureNoCollapse) {
1178 const std::set<Eigen::Index> qset(qubits.begin(), qubits.end());
1182 for (
size_t shot = 0; shot < shots; ++shot) {
1183 const auto meas = MeasureNoCollapseMany();
1187 std::vector<bool> measVec(qubits.size());
1188 for (
size_t i = 0; i < qubits.size(); ++i)
1189 measVec[i] = meas[qubits[i]];
1193 }
else if (qset.size() > 1) {
1194 mpsSimulator->MoveAtBeginningOfChain(qset);
1197 for (
size_t shot = 0; shot < shots; ++shot) {
1198 const auto meas = mpsSimulator->MeasureNoCollapse(qset);
1202 std::vector<bool> measVec(qubits.size());
1203 for (
size_t i = 0; i < qubits.size(); ++i)
1204 measVec[i] = meas.at(qubits[i]);
1208 }
else if (qset.size() == 1) {
1211 const auto prob0 = mpsSimulator->GetProbability(qubits[0]);
1212 for (
size_t shot = 0; shot < shots; ++shot) {
1213 const size_t meas = uniformZeroOne(rng) < prob0 ? 0ULL : 1ULL;
1214 const std::vector<bool> m(qubits.size(), meas);
1221 auto savedState = mpsSimulator->getState();
1222 for (
size_t shot = 0; shot < shots; ++shot) {
1223 const auto meas = MeasureMany(qubits);
1226 mpsSimulator->setState(savedState);
1229 }
else if (simulationType == SimulationType::kStabilizer) {
1230 cliffordSimulator->SaveState();
1231 for (
size_t shot = 0; shot < shots; ++shot) {
1232 const auto meas = MeasureMany(qubits);
1234 cliffordSimulator->RestoreState();
1236 cliffordSimulator->ClearSavedState();
1237 }
else if (simulationType == SimulationType::kTensorNetwork) {
1238 tensorNetwork->SaveState();
1239 for (
size_t shot = 0; shot < shots; ++shot) {
1240 const auto meas = MeasureMany(qubits);
1242 tensorNetwork->RestoreState();
1244 tensorNetwork->ClearSavedState();
1245 }
else if (simulationType == SimulationType::kPauliPropagator) {
1246 std::vector<int> qubitsInt(qubits.begin(), qubits.end());
1247 for (
size_t shot = 0; shot < shots; ++shot) {
1248 const auto meas = pp->Sample(qubitsInt);
1251 }
else if (simulationType == SimulationType::kPathIntegral) {
1252 if (nrQubits < 64) {
1254 const auto &litudes = pathIntegralSimulator->Amplitudes();
1256 for (
size_t shot = 0; shot < shots; ++shot) {
1257 const double prob = 1. - uniformZeroOne(rng);
1258 const size_t measRaw = alias.
Sample(prob);
1259 std::vector<bool> meas(qubits.size(),
false);
1260 for (
size_t i = 0; i < qubits.size(); ++i)
1261 if (((measRaw >> qubits[i]) & 1) == 1) meas[i] =
true;
1265 for (
size_t shot = 0; shot < shots; ++shot) {
1266 const auto measRaw = MeasureNoCollapseMany();
1267 std::vector<bool> meas(qubits.size(),
false);
1269 for (
size_t i = 0; i < qubits.size(); ++i)
1270 if (measRaw[qubits[i]]) meas[i] =
true;
1277 const auto &litudes = pathIntegralSimulator->Amplitudes();
1280 for (
size_t shot = 0; shot < shots; ++shot) {
1281 const double prob = 1. - uniformZeroOne(rng);
1282 const auto measRaw = alias.
Sample(prob);
1283 std::vector<bool> meas(qubits.size(),
false);
1284 for (
size_t i = 0; i < qubits.size(); ++i)
1285 if (measRaw.get(qubits[i])) meas[i] =
true;
1289 for (
size_t shot = 0; shot < shots; ++shot) {
1290 const auto measRaw = MeasureNoCollapseMany();
1291 std::vector<bool> meas(qubits.size(),
false);
1293 for (
size_t i = 0; i < qubits.size(); ++i)
1294 if (measRaw[qubits[i]]) meas[i] =
true;
1302 const auto &statev = state->getRegisterStorage();
1306 for (
size_t shot = 0; shot < shots; ++shot) {
1307 const double prob = 1. - uniformZeroOne(rng);
1308 const size_t measRaw = alias.
Sample(prob);
1310 std::vector<bool> meas(qubits.size(),
false);
1312 for (
size_t i = 0; i < qubits.size(); ++i)
1313 if (((measRaw >> qubits[i]) & 1) == 1) meas[i] =
true;
1318 for (
size_t shot = 0; shot < shots; ++shot) {
1319 const auto measRaw = MeasureNoCollapseMany();
1320 std::vector<bool> meas(qubits.size(),
false);
1322 for (
size_t i = 0; i < qubits.size(); ++i)
1323 if (measRaw[qubits[i]]) meas[i] =
true;
1331 NotifyObservers(qubits);
1347 double ExpectationValue(
const std::string &pauliStringOrig)
override {
1348 if (pauliStringOrig.empty())
return 1.0;
1350 std::string pauliString = pauliStringOrig;
1353 const auto pauliOp = toupper(pauliString[i]);
1354 if (pauliOp !=
'I' && pauliOp !=
'Z')
return 0.0;
1360 if (simulationType == SimulationType::kStabilizer)
1361 return cliffordSimulator->ExpectationValue(pauliString);
1362 else if (simulationType == SimulationType::kTensorNetwork)
1363 return tensorNetwork->ExpectationValue(pauliString);
1364 else if (simulationType == SimulationType::kPauliPropagator)
1365 return pp->ExpectationValue(pauliString);
1366 else if (simulationType == SimulationType::kPathIntegral)
1367 return pathIntegralSimulator->ExpectationValue(pauliString);
1370 static const QC::Gates::PauliXGate<> xgate;
1371 static const QC::Gates::PauliYGate<> ygate;
1372 static const QC::Gates::PauliZGate<> zgate;
1374 std::vector<QC::Gates::AppliedGate<Eigen::MatrixXcd>> pauliStringVec;
1375 pauliStringVec.reserve(pauliString.size());
1377 for (
size_t q = 0; q < pauliString.size(); ++q) {
1378 switch (toupper(pauliString[q])) {
1380 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(
1382 pauliStringVec.emplace_back(std::move(ag));
1385 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(
1387 pauliStringVec.emplace_back(std::move(ag));
1390 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(
1392 pauliStringVec.emplace_back(std::move(ag));
1401 if (pauliStringVec.empty())
return 1.0;
1403 if (simulationType == SimulationType::kMatrixProductState)
1404 return mpsSimulator->ExpectationValue(pauliStringVec).real();
1406 return state->ExpectationValue(pauliStringVec).real();
1416 SimulatorType GetType()
const override {
return SimulatorType::kQCSim; }
1436 void Flush()
override {}
1467 if (simulationType == SimulationType::kMatrixProductState)
1468 mpsSimulator->SaveState();
1469 else if (simulationType == SimulationType::kStabilizer)
1470 cliffordSimulator->SaveState();
1471 else if (simulationType == SimulationType::kTensorNetwork)
1472 tensorNetwork->SaveState();
1473 else if (simulationType == SimulationType::kPauliPropagator)
1475 else if (simulationType == SimulationType::kPathIntegral)
1476 pathIntegralSimulator->SaveState();
1490 if (simulationType == SimulationType::kMatrixProductState)
1491 mpsSimulator->RestoreState();
1492 else if (simulationType == SimulationType::kStabilizer)
1493 cliffordSimulator->RestoreState();
1494 else if (simulationType == SimulationType::kTensorNetwork)
1495 tensorNetwork->RestoreState();
1496 else if (simulationType == SimulationType::kPauliPropagator)
1498 else if (simulationType == SimulationType::kPathIntegral)
1499 pathIntegralSimulator->RestoreState();
1501 state->RestoreState();
1511 std::complex<double> AmplitudeRaw(
Types::qubit_t outcome)
override {
1524 enableMultithreading = multithreading;
1525 if (state) state->SetMultithreading(multithreading);
1526 if (cliffordSimulator) cliffordSimulator->SetMultithreading(multithreading);
1527 if (tensorNetwork) tensorNetwork->SetMultithreading(multithreading);
1530 pp->EnableParallel();
1532 pp->DisableParallel();
1534 if (pathIntegralSimulator) {
1535 enableMultithreading =
false;
1558 bool IsQcsim()
const override {
return true; }
1580 <<
"Warning: The number of qubits to measure is larger than the "
1581 "number of bits in the Types::qubit_t type, the outcome will be "
1585 if (simulationType == SimulationType::kStatevector)
1586 return state->MeasureNoCollapse();
1587 else if (simulationType == SimulationType::kMatrixProductState) {
1588 const auto measured = mpsSimulator->MeasureNoCollapse();
1592 if (measured.at(q)) result |= mask;
1596 }
else if (simulationType == SimulationType::kPauliPropagator) {
1598 std::iota(qubitsInt.begin(), qubitsInt.end(), 0);
1599 const auto res = pp->Sample(qubitsInt);
1601 for (
size_t i = 0; i < res.size(); ++i) {
1602 if (res[i]) result |= (1ULL << i);
1605 }
else if (simulationType == SimulationType::kPathIntegral) {
1606 if (nrQubits < 64) {
1607 const auto measured = pathIntegralSimulator->MeasureNoCollapse();
1611 if (measured.get(q)) result |= mask;
1616 throw std::runtime_error(
1617 "QCSimState::MeasureNoCollapse: The path integral simulator does not "
1618 "support measuring more than 63 qubits into 64 bits integers.");
1622 throw std::runtime_error(
1623 "QCSimState::MeasureNoCollapse: Invalid simulation type for "
1625 "all the qubits without collapsing the state.");
1645 std::vector<bool> MeasureNoCollapseMany()
override {
1646 if (simulationType == SimulationType::kStatevector) {
1648 std::vector<bool> res(nrQubits);
1649 for (
size_t i = 0; i < nrQubits; ++i) res[i] = ((state >> i) & 1) == 1;
1651 }
else if (simulationType == SimulationType::kMatrixProductState) {
1652 const auto measured = mpsSimulator->MeasureNoCollapse();
1653 std::vector<bool> res(nrQubits);
1654 for (
size_t i = 0; i < nrQubits; ++i) res[i] = measured.at(i);
1656 }
else if (simulationType == SimulationType::kPauliPropagator) {
1658 std::iota(qubitsInt.begin(), qubitsInt.end(), 0);
1659 return pp->Sample(qubitsInt);
1660 }
else if (simulationType == SimulationType::kPathIntegral) {
1661 const auto measured = pathIntegralSimulator->MeasureNoCollapse();
1662 std::vector<bool> res(nrQubits);
1663 for (
size_t i = 0; i < nrQubits; ++i) res[i] = measured.get(i);
1667 throw std::runtime_error(
1668 "QCSimState::MeasureNoCollapseMany: Invalid simulation type for "
1669 "measuring all the qubits without collapsing the state.");
1675 SimulationType simulationType =
1676 SimulationType::kStatevector;
1678 std::unique_ptr<QC::QubitRegister<>> state;
1679 std::unique_ptr<QC::TensorNetworks::MPSSimulator>
1681 std::unique_ptr<QC::Clifford::StabilizerSimulator>
1683 std::unique_ptr<TensorNetworks::TensorNetwork>
1685 std::unique_ptr<QcsimPauliPropagator> pp;
1686 std::unique_ptr<PathIntegralSimulator>
1687 pathIntegralSimulator;
1689 size_t nrQubits = 0;
1690 bool limitSize =
false;
1691 bool limitEntanglement =
false;
1692 Eigen::Index chi = 10;
1693 double singularValueThreshold = 0.;
1694 bool enableMultithreading =
true;
1695 bool useMPSMeasureNoCollapse =
1698 int lookaheadDepth = 0;
1699 int lookaheadDepthWithHeuristic = 0;
1700 bool useOptimalMeetingPosition =
true;
1701 std::vector<std::shared_ptr<Circuits::IOperation<>>> upcomingGates;
1702 long long int upcomingGateIndex = 0;
1703 double growthFactorSwap = 1.;
1704 double growthFactorGate = 0.65;
1706 std::unique_ptr<Simulators::MPSDummySimulator> dummySim;
1709 class GateCounterObserver :
public ISimulatorObserver {
1711 GateCounterObserver(
long long int &indexRef) : index(indexRef) {}
1715 long long int &index;
1717 std::shared_ptr<GateCounterObserver> gateCounterObserver;
1719 std::mt19937_64 rng;
1720 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.