18#ifdef INCLUDED_BY_FACTORY
25#include "MPSSimulator.h"
26#include "QubitRegister.h"
49class QCSimState :
public ISimulator {
51 QCSimState() : rng(std::random_device{}()), uniformZeroOne(0, 1) {}
60 void Initialize()
override {
62 if (simulationType == SimulationType::kMatrixProductState) {
64 std::make_unique<QC::TensorNetworks::MPSSimulator>(nrQubits);
65 if (limitEntanglement && singularValueThreshold > 0.)
66 mpsSimulator->setLimitEntanglement(singularValueThreshold);
67 if (limitSize && chi > 0)
68 mpsSimulator->setLimitBondDimension(chi);
69 }
else if (simulationType == SimulationType::kStabilizer)
71 std::make_unique<QC::Clifford::StabilizerSimulator>(nrQubits);
72 else if (simulationType == SimulationType::kTensorNetwork) {
74 std::make_unique<TensorNetworks::TensorNetwork>(nrQubits);
77 const auto tensorContractor =
78 std::make_shared<TensorNetworks::ForestContractor>();
79 tensorNetwork->SetContractor(tensorContractor);
81 state = std::make_unique<QC::QubitRegister<>>(nrQubits);
98 void InitializeState(
size_t num_qubits,
99 std::vector<std::complex<double>> &litudes)
override {
103 nrQubits = num_qubits;
105 if (simulationType != SimulationType::kStatevector)
106 throw std::runtime_error(
"QCSimState::InitializeState: Invalid "
107 "simulation type for initializing the state.");
109 Eigen::VectorXcd amplitudesEigen(
110 Eigen::Map<Eigen::VectorXcd, Eigen::Unaligned>(amplitudes.data(),
112 state->setRegisterStorageFastNoNormalize(amplitudesEigen);
151 void InitializeState(
size_t num_qubits,
152 AER::Vector<std::complex<double>> &litudes)
override {
156 nrQubits = num_qubits;
158 if (simulationType != SimulationType::kStatevector)
159 throw std::runtime_error(
"QCSimState::InitializeState: Invalid "
160 "simulation type for initializing the state.");
162 Eigen::VectorXcd amplitudesEigen(
163 Eigen::Map<Eigen::VectorXcd, Eigen::Unaligned>(amplitudes.data(),
165 state->setRegisterStorageFastNoNormalize(amplitudesEigen);
180 void InitializeState(
size_t num_qubits,
181 Eigen::VectorXcd &litudes)
override {
185 nrQubits = num_qubits;
188 if (simulationType != SimulationType::kStatevector)
189 throw std::runtime_error(
"QCSimState::InitializeState: Invalid "
190 "simulation type for initializing the state.");
192 state = std::make_unique<QC::QubitRegister<>>(nrQubits, amplitudes);
193 state->SetMultithreading(enableMultithreading);
202 void Reset()
override {
204 mpsSimulator->Clear();
205 else if (cliffordSimulator)
206 cliffordSimulator->Reset();
207 else if (tensorNetwork)
208 tensorNetwork->Clear();
221 void Configure(
const char *key,
const char *value)
override {
222 if (std::string(
"method") == key) {
223 if (std::string(
"statevector") == value)
224 simulationType = SimulationType::kStatevector;
225 else if (std::string(
"matrix_product_state") == value)
226 simulationType = SimulationType::kMatrixProductState;
227 else if (std::string(
"stabilizer") == value)
228 simulationType = SimulationType::kStabilizer;
229 else if (std::string(
"tensor_network") == value)
230 simulationType = SimulationType::kTensorNetwork;
231 }
else if (std::string(
"matrix_product_state_truncation_threshold") ==
233 singularValueThreshold = std::stod(value);
234 if (singularValueThreshold > 0.) {
235 limitEntanglement =
true;
237 mpsSimulator->setLimitEntanglement(singularValueThreshold);
239 limitEntanglement =
false;
240 }
else if (std::string(
"matrix_product_state_max_bond_dimension") == key) {
241 chi = std::stoi(value);
245 mpsSimulator->setLimitBondDimension(chi);
248 }
else if (std::string(
"mps_sample_measure_algorithm") == key)
249 useMPSMeasureNoCollapse = std::string(
"mps_probabilities") == value;
260 if (std::string(
"method") == key) {
261 switch (simulationType) {
262 case SimulationType::kStatevector:
263 return "statevector";
264 case SimulationType::kMatrixProductState:
265 return "matrix_product_state";
266 case SimulationType::kStabilizer:
268 case SimulationType::kTensorNetwork:
269 return "tensor_network";
273 }
else if (std::string(
"matrix_product_state_truncation_threshold") ==
275 if (limitEntanglement && singularValueThreshold > 0.)
276 return std::to_string(singularValueThreshold);
277 }
else if (std::string(
"matrix_product_state_max_bond_dimension") == key) {
278 if (limitSize && limitSize > 0)
279 return std::to_string(chi);
280 }
else if (std::string(
"mps_sample_measure_algorithm") == key) {
281 return useMPSMeasureNoCollapse ?
"mps_probabilities"
282 :
"mps_apply_measure";
296 if ((simulationType == SimulationType::kStatevector && state) ||
297 (simulationType == SimulationType::kMatrixProductState &&
299 (simulationType == SimulationType::kStabilizer && cliffordSimulator) ||
300 (simulationType == SimulationType::kTensorNetwork && tensorNetwork))
303 const size_t oldNrQubits = nrQubits;
304 nrQubits += num_qubits;
323 void Clear()
override {
325 mpsSimulator =
nullptr;
326 cliffordSimulator =
nullptr;
327 tensorNetwork =
nullptr;
347 if (simulationType == SimulationType::kStatevector) {
348 for (
size_t qubit : qubits) {
349 if (state->MeasureQubit(
static_cast<unsigned int>(qubit)))
353 }
else if (simulationType == SimulationType::kStabilizer) {
354 for (
size_t qubit : qubits) {
355 if (cliffordSimulator->MeasureQubit(
static_cast<unsigned int>(qubit)))
359 }
else if (simulationType == SimulationType::kTensorNetwork) {
360 for (
size_t qubit : qubits) {
361 if (tensorNetwork->Measure(
static_cast<unsigned int>(qubit)))
374 const std::set<Eigen::Index> qubitsSet(qubits.begin(), qubits.end());
375 auto measured = mpsSimulator->MeasureQubits(qubitsSet);
384 NotifyObservers(qubits);
396 QC::Gates::PauliXGate xGate;
399 if (simulationType == SimulationType::kStatevector) {
400 for (
size_t qubit : qubits)
401 if (state->MeasureQubit(
static_cast<unsigned int>(qubit)))
402 state->ApplyGate(xGate,
static_cast<unsigned int>(qubit));
403 }
else if (simulationType == SimulationType::kStabilizer) {
404 for (
size_t qubit : qubits)
405 if (cliffordSimulator->MeasureQubit(
static_cast<unsigned int>(qubit)))
406 cliffordSimulator->ApplyX(
static_cast<unsigned int>(qubit));
407 }
else if (simulationType == SimulationType::kTensorNetwork) {
408 for (
size_t qubit : qubits)
409 if (tensorNetwork->Measure(
static_cast<unsigned int>(qubit)))
410 tensorNetwork->AddGate(xGate,
static_cast<unsigned int>(qubit));
412 for (
size_t qubit : qubits)
413 if (mpsSimulator->MeasureQubit(
static_cast<unsigned int>(qubit)))
414 mpsSimulator->ApplyGate(xGate,
static_cast<unsigned int>(qubit));
418 NotifyObservers(qubits);
433 if (simulationType == SimulationType::kMatrixProductState)
434 return mpsSimulator->getBasisStateProbability(
435 static_cast<unsigned int>(outcome));
436 else if (simulationType == SimulationType::kStabilizer)
437 return cliffordSimulator->getBasisStateProbability(
438 static_cast<unsigned int>(outcome));
439 else if (simulationType == SimulationType::kTensorNetwork)
440 return tensorNetwork->getBasisStateProbability(outcome);
442 return state->getBasisStateProbability(
static_cast<unsigned int>(outcome));
456 if (simulationType == SimulationType::kMatrixProductState)
457 return mpsSimulator->getBasisStateAmplitude(
458 static_cast<unsigned int>(outcome));
459 else if (simulationType == SimulationType::kStabilizer)
460 throw std::runtime_error(
461 "QCSimState::Amplitude: Invalid simulation type for obtaining the "
462 "amplitude of the specified outcome.");
463 else if (simulationType == SimulationType::kTensorNetwork)
464 throw std::runtime_error(
"QCSimState::Amplitude: Not supported for the "
465 "tensor network simulator.");
467 return state->getBasisStateAmplitude(
static_cast<unsigned int>(outcome));
482 if (simulationType == SimulationType::kTensorNetwork)
483 throw std::runtime_error(
"QCSimState::AllProbabilities: Invalid "
484 "simulation type for obtaining probabilities.");
485 else if (simulationType == SimulationType::kStabilizer)
486 return cliffordSimulator->AllProbabilities();
488 const Eigen::VectorXcd probs =
489 simulationType == SimulationType::kMatrixProductState
490 ? mpsSimulator->getRegisterStorage().cwiseAbs2()
491 : state->getRegisterStorage().cwiseAbs2();
493 std::vector<double> result(probs.size());
495 for (
int i = 0; i < probs.size(); ++i)
496 result[i] = probs[i].real();
514 if (simulationType == SimulationType::kStabilizer)
515 throw std::runtime_error(
"QCSimState::Probabilities: Invalid simulation "
516 "type for obtaining probabilities.");
517 else if (simulationType == SimulationType::kTensorNetwork) {
519 throw std::runtime_error(
"QCSimState::Probabilities: Not implemented yet "
520 "for the tensor network simulator.");
523 std::vector<double> result(qubits.size());
525 if (simulationType == SimulationType::kMatrixProductState) {
526 for (
int i = 0; i < static_cast<int>(qubits.size()); ++i)
527 result[i] = mpsSimulator->getBasisStateProbability(qubits[i]);
529 const Eigen::VectorXcd ® = state->getRegisterStorage();
531 for (
int i = 0; i < static_cast<int>(qubits.size()); ++i)
532 result[i] = std::norm(reg[qubits[i]]);
551 std::unordered_map<Types::qubit_t, Types::qubit_t>
553 size_t shots = 1000)
override {
554 if (qubits.empty() || shots == 0)
560 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
564 if (simulationType == SimulationType::kMatrixProductState) {
566 if (useMPSMeasureNoCollapse) {
568 std::unordered_set qset(qubits.begin(), qubits.end());
572 for (
size_t shot = 0; shot < shots; ++shot) {
578 for (
auto q : qubits) {
579 const size_t qubitMask = 1ULL << q;
580 if (measRaw & qubitMask)
591 auto savedState = mpsSimulator->getState();
592 for (
size_t shot = 0; shot < shots; ++shot) {
593 const size_t meas =
Measure(qubits);
595 mpsSimulator->setState(savedState);
598 }
else if (simulationType == SimulationType::kStabilizer) {
599 cliffordSimulator->SaveState();
600 for (
size_t shot = 0; shot < shots; ++shot) {
601 const size_t meas =
Measure(qubits);
603 cliffordSimulator->RestoreState();
605 cliffordSimulator->ClearSavedState();
606 }
else if (simulationType == SimulationType::kTensorNetwork) {
607 tensorNetwork->SaveState();
608 for (
size_t shot = 0; shot < shots; ++shot) {
609 const size_t meas =
Measure(qubits);
611 tensorNetwork->RestoreState();
613 tensorNetwork->ClearSavedState();
616 const auto &statev = state->getRegisterStorage();
620 for (
size_t shot = 0; shot < shots; ++shot) {
621 const double prob = 1. - uniformZeroOne(rng);
622 const size_t measRaw = alias.
Sample(prob);
626 for (
auto q : qubits) {
627 const size_t qubitMask = 1ULL << q;
628 if ((measRaw & qubitMask) != 0)
636 for (
size_t shot = 0; shot < shots; ++shot) {
641 for (
auto q : qubits) {
642 const size_t qubitMask = 1ULL << q;
643 if ((measRaw & qubitMask) != 0)
654 NotifyObservers(qubits);
670 double ExpectationValue(
const std::string &pauliStringOrig)
override {
671 if (pauliStringOrig.empty())
674 std::string pauliString = pauliStringOrig;
677 const auto pauliOp = toupper(pauliString[i]);
678 if (pauliOp !=
'I' && pauliOp !=
'Z')
685 if (simulationType == SimulationType::kStabilizer)
686 return cliffordSimulator->ExpectationValue(pauliString);
687 else if (simulationType == SimulationType::kTensorNetwork)
688 return tensorNetwork->ExpectationValue(pauliString);
691 static const QC::Gates::PauliXGate<> xgate;
692 static const QC::Gates::PauliYGate<> ygate;
693 static const QC::Gates::PauliZGate<> zgate;
695 std::vector<QC::Gates::AppliedGate<Eigen::MatrixXcd>> pauliStringVec;
696 pauliStringVec.reserve(pauliString.size());
698 for (
size_t q = 0; q < pauliString.size(); ++q) {
699 switch (toupper(pauliString[q])) {
701 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(
703 pauliStringVec.emplace_back(std::move(ag));
706 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(
708 pauliStringVec.emplace_back(std::move(ag));
711 QC::Gates::AppliedGate<Eigen::MatrixXcd> ag(
713 pauliStringVec.emplace_back(std::move(ag));
722 if (pauliStringVec.empty())
725 if (simulationType == SimulationType::kMatrixProductState)
726 return mpsSimulator->ExpectationValue(pauliStringVec).real();
728 return state->ExpectationValue(pauliStringVec).real();
738 SimulatorType GetType()
const override {
return SimulatorType::kQCSim; }
758 void Flush()
override {}
789 if (simulationType == SimulationType::kMatrixProductState)
790 mpsSimulator->SaveState();
791 else if (simulationType == SimulationType::kStabilizer)
792 cliffordSimulator->SaveState();
793 else if (simulationType == SimulationType::kTensorNetwork)
794 tensorNetwork->SaveState();
808 if (simulationType == SimulationType::kMatrixProductState)
809 mpsSimulator->RestoreState();
810 else if (simulationType == SimulationType::kStabilizer)
811 cliffordSimulator->RestoreState();
812 else if (simulationType == SimulationType::kTensorNetwork)
813 tensorNetwork->RestoreState();
815 state->RestoreState();
825 std::complex<double> AmplitudeRaw(
Types::qubit_t outcome)
override {
838 enableMultithreading = multithreading;
840 state->SetMultithreading(multithreading);
841 if (cliffordSimulator)
842 cliffordSimulator->SetMultithreading(multithreading);
844 tensorNetwork->SetMultithreading(multithreading);
866 bool IsQcsim()
const override {
return true; }
882 if (simulationType == SimulationType::kStatevector)
883 return state->MeasureNoCollapse();
884 else if (simulationType == SimulationType::kMatrixProductState) {
885 const auto measured = mpsSimulator->MeasureNoCollapse();
888 for (
const auto &meas : measured) {
896 throw std::runtime_error(
897 "QCSimState::MeasureNoCollapse: Invalid simulation type for measuring "
898 "all the qubits without collapsing the state.");
904 SimulationType simulationType =
905 SimulationType::kStatevector;
907 std::unique_ptr<QC::QubitRegister<>> state;
908 std::unique_ptr<QC::TensorNetworks::MPSSimulator>
910 std::unique_ptr<QC::Clifford::StabilizerSimulator>
912 std::unique_ptr<TensorNetworks::TensorNetwork>
916 bool limitSize =
false;
917 bool limitEntanglement =
false;
918 Eigen::Index chi = 10;
919 double singularValueThreshold = 0.;
920 bool enableMultithreading =
true;
921 bool useMPSMeasureNoCollapse =
925 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)
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.