20#ifdef INCLUDED_BY_FACTORY
48class GpuState :
public ISimulator {
57 void Initialize()
override {
59 auto initializationLock = GpuLibrary::GetInstance()->LockInitialization();
60 const int gpuDevice = configuration.IsSet(
"gpu_device")
61 ? Configuration::ParseGpuDevice(configuration.GetConfiguration(
"gpu_device"))
62 : SimulatorsFactory::ResolveGpuDevice();
63 configuration.SetConfiguration(
"gpu_device", std::to_string(gpuDevice));
64 if (!SimulatorsFactory::GetGpuLibrary(gpuDevice))
65 throw std::runtime_error(
"GpuState::Initialize: Unable to initialize GPU device " +
66 std::to_string(gpuDevice));
67 if (simulationType == SimulationType::kStatevector) {
68 state = SimulatorsFactory::CreateGpuLibStateVectorSim(gpuDevice);
72 for (
const auto& [key, value] : configuration.GetConfigMap())
73 if (key !=
"method") Configure(key.c_str(), value.c_str());
75 const bool res = state->Create(nrQubits);
77 throw std::runtime_error(
78 "GpuState::Initialize: Failed to create "
79 "and initialize the statevector state.");
81 throw std::runtime_error(
82 "GpuState::Initialize: Failed to create the statevector state.");
83 }
else if (simulationType == SimulationType::kDensityMatrix) {
84 densityMatrix = SimulatorsFactory::CreateGpuDensityMatrix(gpuDevice);
86 throw std::runtime_error(
87 "GpuState::Initialize: Failed to create the density matrix state.");
90 for (
const auto& [key, value] : configuration.GetConfigMap())
91 if (key !=
"method") Configure(key.c_str(), value.c_str());
92 if (!densityMatrix->Create(nrQubits))
93 throw std::runtime_error(
94 "GpuState::Initialize: Failed to initialize the density matrix state.");
95 }
else if (simulationType == SimulationType::kMatrixProductOperator) {
96 mpo = SimulatorsFactory::CreateGpuMPO(gpuDevice);
98 throw std::runtime_error(
99 "GpuState::Initialize: Failed to create the matrix product "
101 mpo->SetCallbackContext((
void*)
this);
103 mpo->SetBondDimensionsCallback(&GpuState::BondDimCallback);
107 for (
const auto& [key, value] : configuration.GetConfigMap())
108 if (key !=
"method") Configure(key.c_str(), value.c_str());
109 if (!mpo->Create(nrQubits))
110 throw std::runtime_error(
111 "GpuState::Initialize: Failed to initialize the matrix product "
114 if (!useOptimalMeetingPosition)
115 mpo->SetUseOptimalMeetingPosition(
false);
116 }
else if (simulationType == SimulationType::kMatrixProductState) {
117 mps = SimulatorsFactory::CreateGpuLibMPSSim(gpuDevice);
119 mps->SetCallbackContext((
void*)
this);
121 mps->SetBondDimensionsCallback(&GpuState::BondDimCallback);
125 for (
const auto& [key, value] : configuration.GetConfigMap())
126 if (key !=
"method") Configure(key.c_str(), value.c_str());
128 const bool res = mps->Create(nrQubits);
130 throw std::runtime_error(
131 "GpuState::Initialize: Failed to create "
132 "and initialize the MPS state.");
134 throw std::runtime_error(
135 "GpuState::Initialize: Failed to create the MPS state.");
137 if (!useOptimalMeetingPosition)
138 mps->SetUseOptimalMeetingPosition(
false);
139 }
else if (simulationType == SimulationType::kTensorNetwork) {
140 tn = SimulatorsFactory::CreateGpuLibTensorNetSim(gpuDevice);
144 for (
const auto& [key, value] : configuration.GetConfigMap())
145 if (key !=
"method") Configure(key.c_str(), value.c_str());
147 const bool res = tn->Create(nrQubits);
149 throw std::runtime_error(
150 "GpuState::Initialize: Failed to create "
151 "and initialize the tensor network state.");
153 throw std::runtime_error(
154 "GpuState::Initialize: Failed to create the tensor network "
156 }
else if (simulationType == SimulationType::kPauliPropagator) {
157 pp = SimulatorsFactory::CreateGpuPauliPropagatorSimulatorUnique(gpuDevice);
161 for (
const auto& [key, value] : configuration.GetConfigMap())
162 if (key !=
"method") Configure(key.c_str(), value.c_str());
164 const bool res = pp->CreateSimulator(nrQubits);
166 throw std::runtime_error(
167 "GpuState::Initialize: Failed to create "
168 "and initialize the Pauli propagator state.");
170 pp->SetWillUseSampling(
true);
171 if (!pp->AllocateMemory(0.9))
172 throw std::runtime_error(
173 "GpuState::Initialize: Failed to allocate memory for the "
174 "Pauli propagator state.");
176 throw std::runtime_error(
177 "GpuState::Initialize: Failed to create the Pauli propagator "
180 throw std::runtime_error(
181 "GpuState::Initialize: Invalid simulation "
182 "type for initializing the state.");
183 if (GetGpuDevice() != gpuDevice)
184 throw std::runtime_error(
"GpuState::Initialize: GPU plugin did not confirm the requested device; update the GPU library");
199 void InitializeState(
size_t num_qubits,
200 std::vector<std::complex<double>> &litudes)
override {
201 if (num_qubits == 0)
return;
203 nrQubits = num_qubits;
206 if (simulationType != SimulationType::kStatevector &&
207 simulationType != SimulationType::kDensityMatrix &&
208 simulationType != SimulationType::kMatrixProductOperator)
209 throw std::runtime_error(
210 "GpuState::InitializeState: Invalid simulation "
211 "type for initializing the state.");
214 simulationType == SimulationType::kDensityMatrix
215 ? densityMatrix->CreateWithState(
217 reinterpret_cast<const double *
>(amplitudes.data()))
218 : simulationType == SimulationType::kMatrixProductOperator
219 ? mpo->CreateWithState(
221 reinterpret_cast<const double *
>(amplitudes.data()))
222 : state->CreateWithState(
224 reinterpret_cast<const double *
>(amplitudes.data()));
226 throw std::runtime_error(
227 "GpuState::InitializeState: Failed to initialize the state.");
242 void InitializeState(
size_t num_qubits,
243 AER::Vector<std::complex<double>> &litudes)
override {
244 if (num_qubits == 0)
return;
246 nrQubits = num_qubits;
249 if (simulationType != SimulationType::kStatevector &&
250 simulationType != SimulationType::kDensityMatrix &&
251 simulationType != SimulationType::kMatrixProductOperator)
252 throw std::runtime_error(
253 "GpuState::InitializeState: Invalid simulation "
254 "type for initializing the state.");
257 simulationType == SimulationType::kDensityMatrix
258 ? densityMatrix->CreateWithState(
260 reinterpret_cast<const double *
>(amplitudes.data()))
261 : simulationType == SimulationType::kMatrixProductOperator
262 ? mpo->CreateWithState(
264 reinterpret_cast<const double *
>(amplitudes.data()))
265 : state->CreateWithState(
267 reinterpret_cast<const double *
>(amplitudes.data()));
269 throw std::runtime_error(
270 "GpuState::InitializeState: Failed to initialize the state.");
285 void InitializeState(
size_t num_qubits,
286 Eigen::VectorXcd &litudes)
override {
287 if (num_qubits == 0)
return;
289 nrQubits = num_qubits;
292 if (simulationType != SimulationType::kStatevector &&
293 simulationType != SimulationType::kDensityMatrix &&
294 simulationType != SimulationType::kMatrixProductOperator)
295 throw std::runtime_error(
296 "GpuState::InitializeState: Invalid simulation "
297 "type for initializing the state.");
300 simulationType == SimulationType::kDensityMatrix
301 ? densityMatrix->CreateWithState(
303 reinterpret_cast<const double *
>(amplitudes.data()))
304 : simulationType == SimulationType::kMatrixProductOperator
305 ? mpo->CreateWithState(
307 reinterpret_cast<const double *
>(amplitudes.data()))
308 : state->CreateWithState(
310 reinterpret_cast<const double *
>(amplitudes.data()));
312 throw std::runtime_error(
313 "GpuState::InitializeState: Failed to initialize the state.");
327 void InitializeToBasisState(
size_t num_qubits,
329 if (num_qubits == 0)
return;
331 nrQubits = num_qubits;
335 if (simulationType == SimulationType::kDensityMatrix)
336 created = densityMatrix->CreateWithBasisState(
337 nrQubits,
static_cast<unsigned long long>(basisState));
338 else if (simulationType == SimulationType::kMatrixProductOperator)
339 created = mpo->CreateWithBasisState(
340 nrQubits,
static_cast<unsigned long long>(basisState));
341 else if (simulationType == SimulationType::kMatrixProductState)
342 created = mps->CreateWithBasisState(
343 nrQubits,
static_cast<unsigned long long>(basisState));
345 for (
size_t q = 0; q < num_qubits; ++q)
349 throw std::runtime_error(
350 "GpuState::InitializeToBasisState: Failed to initialize the "
367 void InitializeToBasisState(
size_t num_qubits,
368 const std::vector<bool> &basisState)
override {
369 if (num_qubits == 0)
return;
371 nrQubits = num_qubits;
375 if (simulationType == SimulationType::kMatrixProductOperator ||
376 simulationType == SimulationType::kMatrixProductState) {
377 std::vector<unsigned char> stateBits(num_qubits, 0);
378 for (
size_t q = 0; q < num_qubits && q < basisState.size(); ++q)
379 stateBits[q] = basisState[q] ? 1 : 0;
380 created = simulationType == SimulationType::kMatrixProductOperator
381 ? mpo->CreateWithBasisStateBits(nrQubits, stateBits)
382 : mps->CreateWithBasisStateBits(nrQubits, stateBits);
384 for (
size_t q = 0; q < num_qubits && q < basisState.size(); ++q)
388 throw std::runtime_error(
389 "GpuState::InitializeToBasisState: Failed to initialize the "
403 void InitializeToMixtureOfBasisStates(
405 const std::vector<std::pair<Types::qubit_t, double>> &mixture)
407 if (num_qubits == 0)
return;
409 nrQubits = num_qubits;
412 if (simulationType != SimulationType::kDensityMatrix &&
413 simulationType != SimulationType::kMatrixProductOperator)
414 throw std::runtime_error(
415 "GpuState::InitializeToMixtureOfBasisStates: Invalid simulation "
416 "type for initializing to a mixture of basis states.");
418 std::vector<std::pair<unsigned long long, double>> converted;
419 converted.reserve(mixture.size());
420 for (
const auto &[basisState, weight] : mixture)
421 converted.emplace_back(
static_cast<unsigned long long>(basisState),
425 simulationType == SimulationType::kDensityMatrix
426 ? densityMatrix->CreateWithMixtureOfBasisStates(nrQubits,
428 : mpo->CreateWithMixtureOfBasisStates(nrQubits, converted);
431 throw std::runtime_error(
432 "GpuState::InitializeToMixtureOfBasisStates: Failed to initialize "
446 void InitializeToMixtureOfBasisStates(
448 const std::vector<std::pair<std::vector<bool>,
double>> &mixture)
450 if (num_qubits == 0)
return;
452 nrQubits = num_qubits;
455 if (simulationType != SimulationType::kMatrixProductOperator)
456 throw std::runtime_error(
457 "GpuState::InitializeToMixtureOfBasisStates: Invalid simulation "
458 "type for initializing to a mixture of basis states.");
460 std::vector<double> weights;
461 weights.reserve(mixture.size());
462 std::vector<unsigned char> stateBitsFlat;
463 stateBitsFlat.reserve(mixture.size() * num_qubits);
464 for (
const auto &[basisState, weight] : mixture) {
465 weights.push_back(weight);
466 for (
size_t q = 0; q < num_qubits; ++q)
467 stateBitsFlat.push_back(
468 (q < basisState.size() && basisState[q]) ? 1 : 0);
471 if (!mpo->CreateWithMixtureOfBasisStatesBits(nrQubits, stateBitsFlat,
473 throw std::runtime_error(
474 "GpuState::InitializeToMixtureOfBasisStates: Failed to initialize "
484 void Reset()
override {
487 else if (densityMatrix)
488 densityMatrix->Reset();
498 pp->ClearOperators();
500 upcomingGateIndex = 0;
510 bool SupportsMPSSwapOptimization()
const override {
return true; }
520 void SetInitialQubitsMap(
521 const std::vector<long long int> &initialMap)
override {
523 if (mps) mps->SetInitialQubitsMap(initialMap);
524 else mpo->SetInitialQubitsMap(initialMap);
525 if (!dummySim || dummySim->getNrQubits() != initialMap.size()) {
527 std::make_unique<Simulators::MPSDummySimulator>(initialMap.size());
528 dummySim->SetMaxBondDimension(
529 configuration.GetConfigurationAsInt(MaxBondDimensionConfigKey()));
531 dummySim->setGrowthFactorGate(growthFactorGate);
532 dummySim->setGrowthFactorSwap(growthFactorSwap);
533 dummySim->SetInitialQubitsMap(initialMap);
537 void SetUseOptimalMeetingPosition(
bool enable)
override {
538 useOptimalMeetingPosition = enable;
540 if (mps) mps->SetUseOptimalMeetingPosition(enable);
541 else mpo->SetUseOptimalMeetingPosition(enable);
547 gateCounterObserver =
548 std::make_shared<GateCounterObserver>(upcomingGateIndex);
549 RegisterObserver(gateCounterObserver);
556 mps->SetMeetingPositionCallback(&GpuState::FindBestMeetingPosition);
558 mpo->SetMeetingPositionCallback(&GpuState::FindBestMeetingPosition);
563 void SetLookaheadDepth(
int depth)
override {
564 lookaheadDepth = depth;
565 if (depth > 0 && !useOptimalMeetingPosition) {
566 if (mps) mps->SetUseOptimalMeetingPosition(
true);
567 else if (mpo) mpo->SetUseOptimalMeetingPosition(
true);
571 void SetLookaheadDepthWithHeuristic(
int depth)
override {
572 lookaheadDepthWithHeuristic = depth;
573 if (lookaheadDepth < depth) SetLookaheadDepth(depth);
576 void SetUpcomingGates(
579 upcomingGates = gates;
580 upcomingGateIndex = 0;
582 if (!mps && !mpo)
return;
587 gateCounterObserver =
588 std::make_shared<GateCounterObserver>(upcomingGateIndex);
589 RegisterObserver(gateCounterObserver);
596 mps->SetMeetingPositionCallback(&GpuState::FindBestMeetingPosition);
598 mpo->SetMeetingPositionCallback(&GpuState::FindBestMeetingPosition);
609 long long int GetGatesCounter()
const override {
return upcomingGateIndex; }
620 void SetGatesCounter(
long long int counter)
override {
621 upcomingGateIndex = counter;
632 void IncrementGatesCounter()
override { ++upcomingGateIndex; }
634 double getGrowthFactorSwap()
const override {
return growthFactorSwap; }
635 double getGrowthFactorGate()
const override {
return growthFactorGate; }
637 void setGrowthFactorSwap(
double factor)
override {
638 growthFactorSwap = factor;
639 if (dummySim) dummySim->setGrowthFactorSwap(factor);
642 void setGrowthFactorGate(
double factor)
override {
643 growthFactorGate = factor;
644 if (dummySim) dummySim->setGrowthFactorGate(factor);
655 void Configure(
const char *key,
const char *value)
override {
656 if (!key || !value)
return;
657 if (std::string(
"gpu_device") == key) {
658 const int device = Configuration::ParseGpuDevice(value);
659 if ((state || densityMatrix || mpo || mps || tn || pp) &&
660 device != Configuration::ParseGpuDevice(configuration.GetConfiguration(key)))
661 throw std::invalid_argument(
"gpu_device cannot change after initialization; clear the simulator first");
662 configuration.SetConfiguration(key, std::to_string(device));
665 const auto svdGroup = Configuration::GpuSvdSettingGroup(key);
666 if (!svdGroup.empty()) {
667 const bool enabled = Configuration::ParseGpuSvdFlag(value);
668 const bool gesvd = svdGroup == key;
669 const char algorithm = std::string(key).back();
670 const auto apply = [algorithm, enabled](
auto& backend) {
671 if (!backend)
return true;
672 if (algorithm ==
'j')
return backend->SetGesvdJ(enabled);
673 if (algorithm ==
'p')
return backend->SetGesvdP(enabled);
674 return backend->SetGesvdR(enabled);
676 const auto applyGesvd = [enabled](
auto& backend) {
679 if (!enabled || !backend)
return true;
680 return backend->SetGesvdJ(
false) && backend->SetGesvdP(
false) &&
681 backend->SetGesvdR(
false);
684 if (svdGroup ==
"matrix_product_state_use_gesvd")
685 applied = gesvd ? applyGesvd(mps) : apply(mps);
686 else if (svdGroup ==
"matrix_product_operator_use_gesvd")
687 applied = gesvd ? applyGesvd(mpo) : apply(mpo);
688 else if (svdGroup ==
"tensor_network_use_gesvd")
689 applied = gesvd ? applyGesvd(tn) : apply(tn);
691 throw std::runtime_error(std::string(
"GPU library cannot apply ") + key +
692 "; an updated GPU plugin may be required");
693 configuration.SetConfiguration(key, value);
696 if (std::string(
"method") == key) {
697 if (std::string(
"statevector") == value)
698 simulationType = SimulationType::kStatevector;
699 else if (std::string(
"matrix_product_state") == value)
700 simulationType = SimulationType::kMatrixProductState;
701 else if (std::string(
"density_matrix") == value)
702 simulationType = SimulationType::kDensityMatrix;
703 else if (std::string(
"matrix_product_operator") == value)
704 simulationType = SimulationType::kMatrixProductOperator;
705 else if (std::string(
"tensor_network") == value)
706 simulationType = SimulationType::kTensorNetwork;
707 else if (std::string(
"pauli_propagator") == value)
708 simulationType = SimulationType::kPauliPropagator;
711 if ((simulationType == SimulationType::kMatrixProductState ||
712 simulationType == SimulationType::kMatrixProductOperator) &&
713 !configuration.IsSet(
"matrix_product_state_max_bond_dimension"))
714 configuration.SetConfiguration(
715 "matrix_product_state_max_bond_dimension",
"128");
716 if (simulationType == SimulationType::kMatrixProductOperator) {
717 const auto bondDimension =
718 configuration.GetConfiguration(MaxBondDimensionConfigKey());
719 configuration.SetConfiguration(
720 "matrix_product_state_max_bond_dimension", bondDimension);
721 configuration.SetConfiguration(
722 "matrix_product_operator_max_bond_dimension", bondDimension);
726 if (std::string(
"use_double_precision") == key && densityMatrix &&
727 densityMatrix->IsCreated())
728 throw std::runtime_error(
729 "GpuState::Configure: Density-matrix precision must be configured "
730 "before initialization.");
732 if (std::string(
"use_double_precision") == key && mpo && mpo->IsCreated())
733 throw std::runtime_error(
734 "GpuState::Configure: Matrix-product-operator precision must be "
735 "configured before initialization.");
737 if (!configuration.WasApplied(key, value))
738 configuration.SetConfiguration(key, value);
740 if (std::string(
"seed") == key) {
741 const uint64_t seed = std::stoull(value);
743 if (state) state->SetSeed(seed);
744 if (densityMatrix) densityMatrix->SetSeed(seed);
745 if (mpo) mpo->SetSeed(seed);
746 if (mps) mps->SetSeed(seed);
747 if (tn) tn->SetSeed(seed);
748 if (pp) pp->SetSeed(seed);
752 if (std::string(
"matrix_product_state_truncation_threshold") == key ||
753 std::string(
"matrix_product_operator_truncation_threshold") == key) {
762 const double singularValueThreshold = std::stod(value);
763 if (singularValueThreshold > 0.) {
764 if (mps) mps->SetCutoff(singularValueThreshold);
765 if (tn) tn->SetCutoff(singularValueThreshold);
766 if (mpo) mpo->SetCutoff(singularValueThreshold);
768 }
else if (std::string(
"matrix_product_state_truncation_mode") == key ||
769 std::string(
"matrix_product_operator_truncation_mode") == key) {
773 int truncationMode = -1;
774 if (std::string(
"relative_max") == value)
776 else if (std::string(
"discarded_weight") == value)
778 if (truncationMode >= 0) {
779 if (mps) mps->SetTruncationMode(truncationMode);
780 if (tn) tn->SetTruncationMode(truncationMode);
781 if (mpo) mpo->SetTruncationMode(truncationMode);
783 }
else if (std::string(
"matrix_product_state_max_bond_dimension") == key ||
784 std::string(
"matrix_product_operator_max_bond_dimension") ==
786 const long long int chi = std::stoi(value);
787 if (simulationType == SimulationType::kMatrixProductOperator) {
789 const std::string bondDimension(value);
790 for (
const char* alias : {
"matrix_product_state_max_bond_dimension",
791 "matrix_product_operator_max_bond_dimension"})
792 if (!configuration.WasApplied(alias, bondDimension))
793 configuration.SetConfiguration(alias, bondDimension);
796 if (mps) mps->SetMaxExtent(chi);
797 if (tn) tn->SetMaxExtent(chi);
798 if (mpo) mpo->SetMaxExtent(chi);
799 if (dummySim) dummySim->SetMaxBondDimension(chi);
802 }
else if (std::string(
"matrix_product_operator_kraus_completeness_check") == key) {
804 if (std::string(value) ==
"ignore") mode = 0;
805 else if (std::string(value) ==
"warn") mode = 1;
806 else if (std::string(value) ==
"strict") mode = 2;
807 if (mpo && mode >= 0 && !mpo->SetKrausCompletenessCheck(mode))
808 throw std::runtime_error(
"Invalid GPU MPO Kraus completeness mode");
809 }
else if (std::string(
"use_double_precision") == key) {
810 const bool useDoublePrecision =
811 (std::string(
"1") == value || std::string(
"true") == value);
812 if (mps) mps->SetDataType(useDoublePrecision);
813 if (tn) tn->SetDataType(useDoublePrecision);
814 if (state) state->SetDataType(useDoublePrecision);
815 if (densityMatrix) densityMatrix->SetDataType(useDoublePrecision);
816 if (mpo) mpo->SetDataType(useDoublePrecision);
820 if (std::string(
"pauli_propagator_coefficient_threshold") == key) {
821 const double coefficientThreshold = std::stod(value);
822 pp->SetCoefficientTruncationCutoff(coefficientThreshold);
823 }
else if (std::string(
"pauli_propagator_pauli_weight_threshold") ==
825 const double pauliWeightThreshold = std::stod(value);
826 pp->SetWeightTruncationCutoff(pauliWeightThreshold);
827 }
else if (std::string(
"pauli_propagator_steps_between_trims") == key) {
828 const int stepsBetweenTrims = std::stoi(value);
829 pp->SetNumGatesBetweenTruncations(stepsBetweenTrims);
830 }
else if (std::string(
"pauli_propagator_num_gates_between_deduplications") ==
832 const int numGatesBetweenDeduplications = std::stoi(value);
833 pp->SetNumGatesBetweenDeduplications(numGatesBetweenDeduplications);
847 const auto svdGroup = Configuration::GpuSvdSettingGroup(key);
848 if (!svdGroup.empty()) {
849 if (svdGroup == key) {
850 const auto readGesvd = [](
const auto& backend) {
851 return !backend->GetGesvdJ() && !backend->GetGesvdP() &&
852 !backend->GetGesvdR();
854 if (svdGroup ==
"matrix_product_state_use_gesvd" && mps)
855 return readGesvd(mps) ?
"true" :
"false";
856 if (svdGroup ==
"matrix_product_operator_use_gesvd" && mpo)
857 return readGesvd(mpo) ?
"true" :
"false";
858 if (svdGroup ==
"tensor_network_use_gesvd" && tn)
859 return readGesvd(tn) ?
"true" :
"false";
861 const char algorithm = std::string(key).back();
862 const auto read = [algorithm](
const auto& backend) {
863 if (algorithm ==
'j')
return backend->GetGesvdJ();
864 if (algorithm ==
'p')
return backend->GetGesvdP();
865 return backend->GetGesvdR();
867 if (svdGroup ==
"matrix_product_state_use_gesvd" && mps)
868 return read(mps) ?
"true" :
"false";
869 if (svdGroup ==
"matrix_product_operator_use_gesvd" && mpo)
870 return read(mpo) ?
"true" :
"false";
871 if (svdGroup ==
"tensor_network_use_gesvd" && tn)
872 return read(tn) ?
"true" :
"false";
874 if (std::string(
"method") == key) {
875 switch (simulationType) {
876 case SimulationType::kStatevector:
877 return "statevector";
878 case SimulationType::kMatrixProductState:
879 return "matrix_product_state";
880 case SimulationType::kDensityMatrix:
881 return "density_matrix";
882 case SimulationType::kMatrixProductOperator:
883 return "matrix_product_operator";
884 case SimulationType::kTensorNetwork:
885 return "tensor_network";
886 case SimulationType::kPauliPropagator:
887 return "pauli_propagator";
893 return configuration.GetConfiguration(key);
904 if ((simulationType == SimulationType::kStatevector && state) ||
905 (simulationType == SimulationType::kDensityMatrix && densityMatrix) ||
906 (simulationType == SimulationType::kMatrixProductOperator && mpo) ||
907 (simulationType == SimulationType::kMatrixProductState && mps) ||
908 (simulationType == SimulationType::kPauliPropagator && pp))
911 const size_t oldNrQubits = nrQubits;
912 nrQubits += num_qubits;
932 void Clear()
override {
934 densityMatrix =
nullptr;
941 upcomingGateIndex = 0;
942 upcomingGates.clear();
959 if (qubits.size() >
sizeof(
size_t) * 8)
961 <<
"Warning: The number of qubits to measure is larger than the "
962 "number of bits in the size_t type, the outcome will be undefined"
969 if (simulationType == SimulationType::kStatevector) {
971 for (
size_t qubit : qubits) {
972 if (state->MeasureQubitCollapse(
static_cast<int>(qubit))) res |= mask;
975 }
else if (simulationType == SimulationType::kDensityMatrix) {
976 for (
size_t qubit : qubits) {
977 if (densityMatrix->Measure(
static_cast<unsigned int>(qubit))) res |= mask;
980 }
else if (simulationType == SimulationType::kMatrixProductOperator) {
981 for (
size_t qubit : qubits) {
982 if (mpo->Measure(
static_cast<unsigned int>(qubit))) res |= mask;
985 }
else if (simulationType == SimulationType::kMatrixProductState) {
987 for (
size_t qubit : qubits) {
988 if (mps->Measure(
static_cast<unsigned int>(qubit))) res |= mask;
991 }
else if (simulationType == SimulationType::kTensorNetwork) {
993 for (
size_t qubit : qubits) {
994 if (tn->Measure(
static_cast<unsigned int>(qubit))) res |= mask;
997 }
else if (simulationType == SimulationType::kPauliPropagator) {
999 for (
size_t qubit : qubits) {
1000 if (pp->MeasureQubit(
static_cast<int>(qubit))) res |= mask;
1006 NotifyObservers(qubits);
1018 std::vector<bool> res(qubits.size(),
false);
1021 if (simulationType == SimulationType::kStatevector) {
1022 for (
size_t i = 0; i < qubits.size(); ++i)
1023 res[i] = state->MeasureQubitCollapse(
static_cast<int>(qubits[i]));
1024 }
else if (simulationType == SimulationType::kDensityMatrix) {
1025 for (
size_t i = 0; i < qubits.size(); ++i)
1026 res[i] = densityMatrix->Measure(qubits[i]);
1027 }
else if (simulationType == SimulationType::kMatrixProductOperator) {
1028 for (
size_t i = 0; i < qubits.size(); ++i)
1029 res[i] = mpo->Measure(
static_cast<unsigned int>(qubits[i]));
1030 }
else if (simulationType == SimulationType::kMatrixProductState) {
1031 for (
size_t i = 0; i < qubits.size(); ++i)
1032 res[i] = mps->Measure(
static_cast<unsigned int>(qubits[i]));
1033 }
else if (simulationType == SimulationType::kTensorNetwork) {
1034 for (
size_t i = 0; i < qubits.size(); ++i)
1035 res[i] = tn->Measure(
static_cast<unsigned int>(qubits[i]));
1036 }
else if (simulationType == SimulationType::kPauliPropagator) {
1037 for (
size_t i = 0; i < qubits.size(); ++i)
1038 res[i] = pp->MeasureQubit(
static_cast<int>(qubits[i]));
1041 NotifyObservers(qubits);
1054 if (simulationType == SimulationType::kStatevector) {
1055 for (
size_t qubit : qubits)
1056 if (state->MeasureQubitCollapse(
static_cast<int>(qubit)))
1057 state->ApplyX(
static_cast<int>(qubit));
1058 }
else if (simulationType == SimulationType::kDensityMatrix) {
1059 for (
size_t qubit : qubits) densityMatrix->ApplyReset(qubit);
1060 }
else if (simulationType == SimulationType::kMatrixProductOperator) {
1061 for (
size_t qubit : qubits)
1062 mpo->ApplyReset(
static_cast<int>(qubit));
1063 }
else if (simulationType == SimulationType::kMatrixProductState) {
1064 for (
size_t qubit : qubits)
1065 if (mps->Measure(
static_cast<unsigned int>(qubit)))
1066 mps->ApplyX(
static_cast<unsigned int>(qubit));
1067 }
else if (simulationType == SimulationType::kTensorNetwork) {
1068 for (
size_t qubit : qubits)
1069 if (tn->Measure(
static_cast<unsigned int>(qubit)))
1070 tn->ApplyX(
static_cast<unsigned int>(qubit));
1071 }
else if (simulationType == SimulationType::kPauliPropagator) {
1072 for (
size_t qubit : qubits)
1073 if (pp->MeasureQubit(
static_cast<int>(qubit)))
1074 pp->ApplyX(
static_cast<int>(qubit));
1078 NotifyObservers(qubits);
1081 bool SupportsQuantumChannels()
const override {
1082 return simulationType == SimulationType::kDensityMatrix ||
1083 simulationType == SimulationType::kMatrixProductOperator;
1087 const QuantumChannel& channel)
override {
1088 if (!densityMatrix && !mpo)
1089 throw std::runtime_error(
1090 "GPU quantum channels require an initialized density matrix or "
1091 "matrix product operator");
1092 if (targets.size() != channel.GetNumberOfQubits() || targets.empty() ||
1094 throw std::invalid_argument(
1095 "GPU density matrices and matrix product operators support one- "
1096 "and two-qubit local channels");
1097 std::vector<int> gpuTargets;
1098 gpuTargets.reserve(targets.size());
1099 for (
auto target : targets) {
1100 if (target >= nrQubits ||
1101 std::find(gpuTargets.begin(), gpuTargets.end(), target) !=
1103 throw std::invalid_argument(
"Invalid GPU quantum-channel target");
1104 gpuTargets.push_back(
static_cast<int>(target));
1106 const auto& kraus = channel.GetKrausOperators();
1107 std::vector<double> interleaved;
1108 interleaved.reserve(kraus.size() * kraus.front().size() * 2);
1109 for (
const auto& op : kraus)
1110 for (Eigen::Index i = 0; i < op.size(); ++i) {
1111 interleaved.push_back(op.data()[i].real());
1112 interleaved.push_back(op.data()[i].imag());
1114 const bool applied =
1116 ? densityMatrix->ApplyKraus(gpuTargets, kraus.size(),
1118 : mpo->ApplyKraus(gpuTargets, kraus.size(), interleaved.data());
1120 throw std::runtime_error(
1121 "GPU density-matrix/matrix-product-operator channel application "
1123 NotifyObservers(targets);
1126 std::complex<double> DensityMatrixTrace()
const override {
1127 if (densityMatrix)
return densityMatrix->Trace();
1128 if (mpo)
return mpo->Trace();
1129 throw std::runtime_error(
"GPU mixed-state diagnostics require density_matrix or matrix_product_operator");
1131 double DensityMatrixPurity()
const override {
1132 if (densityMatrix)
return densityMatrix->Purity();
1133 if (mpo)
return mpo->Purity();
1134 throw std::runtime_error(
"GPU mixed-state diagnostics require density_matrix or matrix_product_operator");
1136 std::complex<double> DensityMatrixTraceOfSquare()
const override {
1137 if (mpo)
return mpo->TraceOfSquare();
1138 if (densityMatrix) {
1139 const double tr = densityMatrix->Trace();
1140 return densityMatrix->Purity() * tr * tr;
1142 throw std::runtime_error(
"GPU mixed-state diagnostics require density_matrix or matrix_product_operator");
1144 std::complex<double> DensityMatrixOverlap(
const IState &other)
const override {
1145 const auto *rhs =
dynamic_cast<const GpuState *
>(&other);
1146 if (!rhs)
throw std::invalid_argument(
"Density-matrix overlap requires matching GPU backends");
1147 if (densityMatrix && rhs->densityMatrix)
1148 return densityMatrix->HilbertSchmidtOverlap(*rhs->densityMatrix);
1149 if (mpo && rhs->mpo)
return mpo->HilbertSchmidtOverlap(*rhs->mpo);
1150 throw std::invalid_argument(
"Density-matrix overlap requires two density matrices or two MPOs");
1152 double DensityMatrixHermiticityResidual()
const override {
1153 if (mpo)
return mpo->HermiticityResidual();
1154 if (densityMatrix)
return densityMatrix->IsHermitian() ? 0. : std::numeric_limits<double>::infinity();
1155 throw std::runtime_error(
"GPU mixed-state diagnostics require density_matrix or matrix_product_operator");
1157 bool IsDensityMatrixHermitian(
double eps = 1e-10)
const override {
1158 if (densityMatrix)
return densityMatrix->IsHermitian(eps);
1159 if (mpo)
return mpo->IsHermitian(eps);
1160 throw std::runtime_error(
"GPU mixed-state diagnostics require density_matrix or matrix_product_operator");
1163 std::vector<int> keep(qubits.begin(), qubits.end());
1164 const auto values = densityMatrix ? densityMatrix->PartialTrace(keep) :
1165 mpo ? mpo->PartialTrace(keep) :
throw std::runtime_error(
"GPU partial trace requires a mixed-state backend");
1166 const Eigen::Index dim =
static_cast<Eigen::Index
>(
size_t{1} << keep.size());
1167 return Eigen::Map<const Eigen::MatrixXcd>(values.data(), dim, dim);
1169 double FidelityWithStatevector(
const Eigen::VectorXcd &psi)
const override {
1170 std::vector<double> raw(2 *
static_cast<size_t>(psi.size()));
1171 for (Eigen::Index i = 0; i < psi.size(); ++i) { raw[2*i] = psi[i].real(); raw[2*i+1] = psi[i].imag(); }
1172 if (densityMatrix)
return densityMatrix->FidelityWithStatevector(raw.data());
1173 if (mpo)
return mpo->FidelityWithStatevector(raw.data());
1174 throw std::runtime_error(
"GPU mixed-state fidelity requires density_matrix or matrix_product_operator");
1176 void RestoreDensityMatrixTrace()
override {
1177 if (!mpo)
throw std::runtime_error(
"Trace restoration is only available for GPU MPO");
1178 mpo->RestoreTrace();
1180 void HermitizeDensityMatrix()
override {
1181 if (!mpo)
throw std::runtime_error(
"Hermitization is only available for GPU MPO");
1184 void TrimMatrixProductOperator()
override {
1185 if (!mpo)
throw std::runtime_error(
"GPU MPO is not initialized");
1188 void ReCanonicalizeMatrixProductOperator()
override {
1189 if (!mpo)
throw std::runtime_error(
"GPU MPO is not initialized");
1190 mpo->ReCanonicalize();
1205 if (simulationType == SimulationType::kStatevector)
1206 return state->BasisStateProbability(outcome);
1207 else if (simulationType == SimulationType::kDensityMatrix)
1208 return densityMatrix->Probability(outcome);
1209 else if (simulationType == SimulationType::kMatrixProductOperator)
1210 return mpo->Probability(outcome);
1211 else if (simulationType == SimulationType::kMatrixProductState ||
1212 simulationType == SimulationType::kTensorNetwork) {
1214 return std::norm(ampl);
1215 }
else if (simulationType == SimulationType::kPauliPropagator) {
1216 return pp->Probability(outcome);
1236 if (simulationType == SimulationType::kStatevector)
1237 state->Amplitude(outcome, &real, &imag);
1238 else if (simulationType == SimulationType::kDensityMatrix)
1239 throw std::runtime_error(
1240 "GpuState::Amplitude: Amplitudes are not defined for density matrices.");
1241 else if (simulationType == SimulationType::kMatrixProductOperator)
1242 throw std::runtime_error(
1243 "GpuState::Amplitude: Amplitudes are not defined for matrix "
1244 "product operators.");
1245 else if (simulationType == SimulationType::kMatrixProductState ||
1246 simulationType == SimulationType::kTensorNetwork) {
1247 std::vector<long int> fixedValues(nrQubits);
1248 for (
size_t i = 0; i < nrQubits; ++i)
1249 fixedValues[i] = (outcome & (1ULL << i)) ? 1 : 0;
1250 if (simulationType == SimulationType::kMatrixProductState)
1251 mps->Amplitude(nrQubits, fixedValues.data(), &real, &imag);
1252 else if (simulationType == SimulationType::kTensorNetwork)
1253 tn->Amplitude(nrQubits, fixedValues.data(), &real, &imag);
1254 }
else if (simulationType == SimulationType::kPauliPropagator) {
1256 throw std::runtime_error(
1257 "GpuState::Amplitude: Invalid simulation type for amplitude "
1261 return std::complex<double>(real, imag);
1277 std::complex<double> ProjectOnZero()
override {
1278 if (simulationType == SimulationType::kMatrixProductState)
1279 return mps->ProjectOnZero();
1295 if (nrQubits == 0)
return {};
1296 const size_t numStates = 1ULL << nrQubits;
1297 std::vector<double> result(numStates);
1299 if (simulationType == SimulationType::kStatevector)
1300 state->AllProbabilities(result.data());
1301 else if (simulationType == SimulationType::kDensityMatrix)
1302 densityMatrix->AllProbabilities(result.data());
1303 else if (simulationType == SimulationType::kMatrixProductOperator)
1304 mpo->AllProbabilities(result.data());
1305 else if (simulationType == SimulationType::kMatrixProductState ||
1306 simulationType == SimulationType::kTensorNetwork) {
1310 result[i] = std::norm(std::complex<double>(val.real(), val.imag()));
1312 }
else if (simulationType == SimulationType::kPauliPropagator) {
1315 result[i] = pp->Probability(i);
1335 std::vector<double> result(qubits.size());
1337 if (simulationType == SimulationType::kStatevector) {
1338 for (
size_t i = 0; i < qubits.size(); ++i)
1339 result[i] = state->BasisStateProbability(qubits[i]);
1340 }
else if (simulationType == SimulationType::kDensityMatrix) {
1341 for (
size_t i = 0; i < qubits.size(); ++i)
1342 result[i] = densityMatrix->Probability(qubits[i]);
1343 }
else if (simulationType == SimulationType::kMatrixProductOperator) {
1344 for (
size_t i = 0; i < qubits.size(); ++i)
1345 result[i] = mpo->Probability(qubits[i]);
1346 }
else if (simulationType == SimulationType::kMatrixProductState ||
1347 simulationType == SimulationType::kTensorNetwork) {
1348 for (
size_t i = 0; i < qubits.size(); ++i) {
1350 result[i] = std::norm(ampl);
1352 }
else if (simulationType == SimulationType::kPauliPropagator) {
1353 for (
size_t i = 0; i < qubits.size(); ++i)
1354 result[i] = pp->Probability(qubits[i]);
1376 std::unordered_map<Types::qubit_t, Types::qubit_t>
SampleCounts(
1378 if (qubits.empty() || shots == 0)
return {};
1382 <<
"Warning: The number of qubits to measure is larger than the "
1383 "number of bits in the Types::qubit_t type, the outcome will be "
1387 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
1391 if (simulationType == SimulationType::kStatevector) {
1392 std::vector<long int> samples(shots);
1393 state->SampleAll(shots, samples.data());
1395 for (
auto outcome : samples) {
1400 for (
size_t i = 0; i < qubits.size(); ++i) {
1401 if (outcome & (1ULL << qubits[i])) translatedOutcome |= mask;
1404 ++result[translatedOutcome];
1406 }
else if (simulationType == SimulationType::kDensityMatrix) {
1407 std::vector<long int> samples(shots);
1408 if (!densityMatrix->SampleAll(shots, samples.data())) {
1410 throw std::runtime_error(
1411 "GpuState::SampleCounts: Density-matrix sampling failed.");
1413 for (
auto outcome : samples) {
1415 for (
size_t i = 0; i < qubits.size(); ++i)
1416 if (outcome & (1ULL << qubits[i])) translatedOutcome |= 1ULL << i;
1417 ++result[translatedOutcome];
1419 }
else if (simulationType == SimulationType::kMatrixProductOperator) {
1420 std::vector<long int> samples(shots);
1421 if (!mpo->SampleAll(shots, samples.data())) {
1423 throw std::runtime_error(
1424 "GpuState::SampleCounts: Matrix-product-operator sampling "
1427 for (
auto outcome : samples) {
1429 for (
size_t i = 0; i < qubits.size(); ++i)
1430 if (outcome & (1ULL << qubits[i])) translatedOutcome |= 1ULL << i;
1431 ++result[translatedOutcome];
1433 }
else if (simulationType == SimulationType::kMatrixProductState) {
1434 std::unordered_map<std::vector<bool>, int64_t> *map =
1435 mps->GetMapForSample();
1437 std::vector<unsigned int> qubitsIndices(qubits.begin(), qubits.end());
1439 mps->Sample(shots, qubitsIndices.size(), qubitsIndices.data(), map);
1440 const auto positions = SampleBitPositions(qubits);
1443 for (
const auto &[meas, cnt] : *map) {
1447 if (meas[positions[q]]) outcome |= mask;
1451 result[outcome] += cnt;
1454 mps->FreeMapForSample(map);
1455 }
else if (simulationType == SimulationType::kTensorNetwork) {
1456 std::unordered_map<std::vector<bool>, int64_t> *map =
1457 tn->GetMapForSample();
1458 std::vector<unsigned int> qubitsIndices(qubits.begin(), qubits.end());
1459 tn->Sample(shots, qubitsIndices.size(), qubitsIndices.data(), map);
1460 const auto positions = SampleBitPositions(qubits);
1462 for (
const auto &[meas, cnt] : *map) {
1466 if (meas[positions[q]]) outcome |= mask;
1469 result[outcome] += cnt;
1471 tn->FreeMapForSample(map);
1472 }
else if (simulationType == SimulationType::kPauliPropagator) {
1473 std::vector<int> qb(qubits.begin(), qubits.end());
1474 for (
size_t shot = 0; shot < shots; ++shot) {
1476 auto res = pp->SampleQubits(qb);
1477 for (
size_t i = 0; i < qubits.size(); ++i) {
1478 if (res[i]) meas |= (1ULL << i);
1485 NotifyObservers(qubits);
1503 std::unordered_map<std::vector<bool>,
Types::qubit_t> SampleCountsMany(
1505 if (qubits.empty() || shots == 0)
return {};
1511 if (simulationType == SimulationType::kStatevector) {
1512 std::vector<long int> samples(shots);
1513 state->SampleAll(shots, samples.data());
1515 std::vector<bool> outcomeVec(qubits.size());
1516 for (
auto outcome : samples) {
1517 for (
size_t i = 0; i < qubits.size(); ++i)
1518 outcomeVec[i] = ((outcome >> qubits[i]) & 1) == 1;
1519 ++result[outcomeVec];
1521 }
else if (simulationType == SimulationType::kDensityMatrix) {
1522 std::vector<long int> samples(shots);
1523 if (!densityMatrix->SampleAll(shots, samples.data())) {
1525 throw std::runtime_error(
1526 "GpuState::SampleCountsMany: Density-matrix sampling failed.");
1528 std::vector<bool> outcomeVec(qubits.size());
1529 for (
auto outcome : samples) {
1530 for (
size_t i = 0; i < qubits.size(); ++i)
1531 outcomeVec[i] = ((outcome >> qubits[i]) & 1) != 0;
1532 ++result[outcomeVec];
1534 }
else if (simulationType == SimulationType::kMatrixProductOperator) {
1535 std::vector<long int> samples(shots);
1536 if (!mpo->SampleAll(shots, samples.data())) {
1538 throw std::runtime_error(
1539 "GpuState::SampleCountsMany: Matrix-product-operator sampling "
1542 std::vector<bool> outcomeVec(qubits.size());
1543 for (
auto outcome : samples) {
1544 for (
size_t i = 0; i < qubits.size(); ++i)
1545 outcomeVec[i] = ((outcome >> qubits[i]) & 1) != 0;
1546 ++result[outcomeVec];
1548 }
else if (simulationType == SimulationType::kMatrixProductState) {
1549 std::unordered_map<std::vector<bool>, int64_t> *map =
1550 mps->GetMapForSample();
1552 std::vector<unsigned int> qubitsIndices(qubits.begin(), qubits.end());
1553 mps->Sample(shots, qubitsIndices.size(), qubitsIndices.data(), map);
1554 const auto positions = SampleBitPositions(qubits);
1557 for (
const auto &[meas, cnt] : *map) {
1558 std::vector<bool> ordered(qubits.size());
1559 for (
size_t q = 0; q < qubits.size(); ++q) ordered[q] = meas[positions[q]];
1560 result[ordered] += cnt;
1563 mps->FreeMapForSample(map);
1564 }
else if (simulationType == SimulationType::kTensorNetwork) {
1565 std::unordered_map<std::vector<bool>, int64_t> *map =
1566 tn->GetMapForSample();
1567 std::vector<unsigned int> qubitsIndices(qubits.begin(), qubits.end());
1568 tn->Sample(shots, qubitsIndices.size(), qubitsIndices.data(), map);
1569 const auto positions = SampleBitPositions(qubits);
1571 for (
const auto &[meas, cnt] : *map) {
1572 std::vector<bool> ordered(qubits.size());
1573 for (
size_t q = 0; q < qubits.size(); ++q) ordered[q] = meas[positions[q]];
1574 result[ordered] += cnt;
1576 tn->FreeMapForSample(map);
1577 }
else if (simulationType == SimulationType::kPauliPropagator) {
1578 std::vector<int> qb(qubits.begin(), qubits.end());
1579 for (
size_t shot = 0; shot < shots; ++shot) {
1580 const auto res = pp->SampleQubits(qb);
1586 NotifyObservers(qubits);
1602 double ExpectationValue(
const std::string &pauliString)
override {
1603 double result = 0.0;
1605 if (simulationType == SimulationType::kStatevector)
1606 result = state->ExpectationValue(pauliString);
1607 else if (simulationType == SimulationType::kDensityMatrix)
1608 result = densityMatrix->ExpectationValue(pauliString);
1609 else if (simulationType == SimulationType::kMatrixProductOperator)
1610 result = mpo->ExpectationValue(pauliString);
1611 else if (simulationType == SimulationType::kMatrixProductState)
1612 result = mps->ExpectationValue(pauliString);
1613 else if (simulationType == SimulationType::kTensorNetwork)
1614 result = tn->ExpectationValue(pauliString);
1615 else if (simulationType == SimulationType::kPauliPropagator)
1616 result = pp->ExpectationValue(pauliString);
1618 throw std::runtime_error(
1619 "GpuState::ExpectationValue: Invalid simulation type for expectation "
1620 "value calculation.");
1632 int GetGpuDevice()
const override {
1633 if (state)
return state->GetGpuDevice();
1634 if (densityMatrix)
return densityMatrix->GetGpuDevice();
1635 if (mpo)
return mpo->GetGpuDevice();
1636 if (mps)
return mps->GetGpuDevice();
1637 if (tn)
return tn->GetGpuDevice();
1638 if (pp)
return pp->GetGpuDevice();
1642 SimulatorType GetType()
const override {
return SimulatorType::kGpuSim; }
1662 void Flush()
override {}
1675 if (simulationType == SimulationType::kStatevector)
1676 state->SaveStateDestructive();
1677 else if (simulationType == SimulationType::kPauliPropagator)
1680 throw std::runtime_error(
1681 "GpuState::SaveStateToInternalDestructive: Invalid simulation type "
1682 "for saving the state destructively.");
1692 if (simulationType == SimulationType::kStatevector)
1693 state->RestoreStateFreeSaved();
1694 else if (simulationType == SimulationType::kPauliPropagator)
1697 throw std::runtime_error(
1698 "GpuState::RestoreInternalDestructiveSavedState: Invalid simulation "
1699 "type for restoring the state destructively.");
1711 if (simulationType == SimulationType::kStatevector)
1713 else if (simulationType == SimulationType::kDensityMatrix)
1714 densityMatrix->SaveState();
1715 else if (simulationType == SimulationType::kMatrixProductOperator)
1717 else if (simulationType == SimulationType::kMatrixProductState)
1719 else if (simulationType == SimulationType::kTensorNetwork)
1721 else if (simulationType == SimulationType::kPauliPropagator)
1733 if (simulationType == SimulationType::kStatevector)
1734 state->RestoreStateNoFreeSaved();
1735 else if (simulationType == SimulationType::kDensityMatrix)
1736 densityMatrix->RestoreState();
1737 else if (simulationType == SimulationType::kMatrixProductOperator)
1738 mpo->RestoreState();
1739 else if (simulationType == SimulationType::kMatrixProductState)
1740 mps->RestoreState();
1741 else if (simulationType == SimulationType::kTensorNetwork)
1743 else if (simulationType == SimulationType::kPauliPropagator)
1754 std::complex<double> AmplitudeRaw(
Types::qubit_t outcome)
override {
1789 bool IsQcsim()
const override {
return false; }
1808 if (simulationType == SimulationType::kStatevector)
1809 return state->MeasureAllQubitsNoCollapse();
1810 else if (simulationType == SimulationType::kDensityMatrix) {
1811 std::vector<long int> samples(1);
1812 if (!densityMatrix->SampleAll(1, samples.data()))
1813 throw std::runtime_error(
1814 "GpuState::MeasureNoCollapse: Density-matrix sampling failed.");
1816 }
else if (simulationType == SimulationType::kMatrixProductOperator) {
1817 std::vector<long int> samples(1);
1818 if (!mpo->SampleAll(1, samples.data()))
1819 throw std::runtime_error(
1820 "GpuState::MeasureNoCollapse: Matrix-product-operator sampling "
1823 }
else if (simulationType == SimulationType::kMatrixProductState ||
1824 simulationType == SimulationType::kTensorNetwork ||
1825 simulationType == SimulationType::kPauliPropagator) {
1828 <<
"Warning: The number of qubits to measure is larger than the "
1829 "number of bits in the Types::qubit_t type, the outcome will be "
1834 std::iota(fixedValues.begin(), fixedValues.end(), 0);
1836 if (res.empty())
return 0;
1841 throw std::runtime_error(
1842 "GpuState::MeasureNoCollapse: Invalid simulation type for measuring "
1843 "all the qubits without collapsing the state.");
1862 std::vector<bool> MeasureNoCollapseMany()
override {
1863 if (simulationType == SimulationType::kStatevector) {
1864 const auto meas = state->MeasureAllQubitsNoCollapse();
1865 std::vector<bool> result(nrQubits,
false);
1866 for (
size_t i = 0; i < nrQubits; ++i) result[i] = ((meas >> i) & 1) == 1;
1868 }
else if (simulationType == SimulationType::kDensityMatrix) {
1869 std::vector<long int> samples(1);
1870 if (!densityMatrix->SampleAll(1, samples.data()))
1871 throw std::runtime_error(
1872 "GpuState::MeasureNoCollapseMany: Density-matrix sampling failed.");
1873 std::vector<bool> result(nrQubits,
false);
1874 for (
size_t i = 0; i < nrQubits; ++i)
1875 result[i] = ((samples.front() >> i) & 1) != 0;
1877 }
else if (simulationType == SimulationType::kMatrixProductOperator) {
1878 std::vector<long int> samples(1);
1879 if (!mpo->SampleAll(1, samples.data()))
1880 throw std::runtime_error(
1881 "GpuState::MeasureNoCollapseMany: Matrix-product-operator "
1882 "sampling failed.");
1883 std::vector<bool> result(nrQubits,
false);
1884 for (
size_t i = 0; i < nrQubits; ++i)
1885 result[i] = ((samples.front() >> i) & 1) != 0;
1887 }
else if (simulationType == SimulationType::kMatrixProductState ||
1888 simulationType == SimulationType::kTensorNetwork ||
1889 simulationType == SimulationType::kPauliPropagator) {
1891 std::iota(fixedValues.begin(), fixedValues.end(), 0);
1892 const auto res = SampleCountsMany(fixedValues, 1);
1893 if (res.empty())
return std::vector<bool>(nrQubits,
false);
1898 throw std::runtime_error(
1899 "GpuState::MeasureNoCollapseMany: Invalid simulation type for "
1901 "all the qubits without collapsing the state.");
1903 return std::vector<bool>(nrQubits,
false);
1912 size_t GetCurrentMaxBondDimension()
const override {
return curMaxBondDim; }
1917 const std::unordered_map<std::string, std::string>& GetConfigMap()
1919 return configuration.GetConfigMap();
1926 auto sorted = qubits;
1927 std::sort(sorted.begin(), sorted.end());
1928 sorted.erase(std::unique(sorted.begin(), sorted.end()), sorted.end());
1929 std::vector<size_t> positions;
1930 positions.reserve(qubits.size());
1931 for (
const auto q : qubits)
1932 positions.push_back(std::lower_bound(sorted.begin(), sorted.end(), q) - sorted.begin());
1938 const char* MaxBondDimensionConfigKey()
const {
1939 return simulationType == SimulationType::kMatrixProductOperator &&
1940 configuration.IsSet(
1941 "matrix_product_operator_max_bond_dimension")
1942 ?
"matrix_product_operator_max_bond_dimension"
1943 :
"matrix_product_state_max_bond_dimension";
1946 static int64_t FindBestMeetingPosition(
void* thisPtr,
const int64_t* bondDims) {
1947 GpuState* self =
static_cast<GpuState*
>(thisPtr);
1949 return self->FindBestMeetingPositionFunc(bondDims);
1952 int64_t FindBestMeetingPositionFunc(
const int64_t* bondDims)
1956 if (lookaheadDepth <= 0 || lookaheadDepth == std::numeric_limits<int>::max())
1959 if (!dummySim || dummySim->getNrQubits() != nQ) {
1960 dummySim = std::make_unique<Simulators::MPSDummySimulator>(nQ);
1961 dummySim->SetMaxBondDimension(
1962 configuration.GetConfigurationAsInt(MaxBondDimensionConfigKey()));
1963 dummySim->setGrowthFactorGate(growthFactorGate);
1964 dummySim->setGrowthFactorSwap(growthFactorSwap);
1967 dummySim->setTotalSwappingCost(0);
1970 std::vector<double> bondDimsD(bondDims, bondDims + nrQubits - 1);
1971 dummySim->SetCurrentBondDimensions(bondDimsD);
1974#ifdef LOG_CALLBACK_INFO
1975 std::cerr <<
"Bond dimensions before swapping and applying the gate:";
1976 for (
size_t i = 0; i < nrQubits - 1; ++i) {
1977 std::cerr << bondDims[i] <<
" ";
1979 std::cerr << std::endl;
1982 if (upcomingGates.size() <=
static_cast<size_t>(upcomingGateIndex)) {
1986 const auto &op = upcomingGates[upcomingGateIndex];
1987 const auto qbits = op->AffectedQubits();
1989 if (qbits.size() != 2) {
1990 std::cerr <<
"Error: Meeting position callback called for a gate "
1991 "that does not have exactly 2 qubits."
1997#ifdef LOG_CALLBACK_INFO
1998 const auto& qmap = dummySim->getQubitsMap();
2000 std::cerr <<
"Applying 2-qubit gate on physical qubits " << qmap[qbits[0]]
2001 <<
" and " << qmap[qbits[1]] << std::endl;
2003 std::cerr <<
"Finding best meeting position for upcoming gates starting at index "
2004 << upcomingGateIndex <<
" with lookahead depth " << lookaheadDepth
2005 <<
" and heuristic depth " << lookaheadDepthWithHeuristic
2008 std::cerr <<
"Affected qubits: ";
2009 for (
const auto& q : qbits) std::cerr << q <<
" ";
2010 std::cerr << std::endl;
2013 double bestCost = std::numeric_limits<double>::infinity();
2014 int64_t res = dummySim->FindBestMeetingPosition(
2015 upcomingGates, upcomingGateIndex, lookaheadDepth,
2016 lookaheadDepthWithHeuristic, 0, bestCost);
2018#ifdef LOG_CALLBACK_INFO
2019 std::cerr <<
"Swapping the two qubits on position: " << res <<
" and "
2020 << (res + 1) << std::endl;
2023 dummySim->SwapQubitsToPosition(qbits[0], qbits[1], res);
2024 dummySim->ApplyGate(op);
2029#ifdef LOG_CALLBACK_INFO
2030 const auto& expectedBondDims = dummySim->getCurrentBondDimensions();
2031 std::cerr <<
"Expected bond dimensions after swapping and applying "
2033 for (
size_t i = 0; i < expectedBondDims.size(); ++i) {
2034 std::cerr << expectedBondDims[i] <<
" ";
2036 std::cerr << std::endl;
2038 std::cerr <<
"Best meeting position: " << res
2039 <<
" with estimated cost: " << bestCost << std::endl;
2046 static void BondDimCallback(
void* thisPtr,
const int64_t* bondDims) {
2047 GpuState* self =
static_cast<GpuState*
>(thisPtr);
2049 return self->BondDimCallbackFunc(bondDims);
2052 void BondDimCallbackFunc(
const int64_t* bondDims)
2056 for (
int i = 0; i < static_cast<int>(nQ) - 1; ++i)
2057 if (
static_cast<size_t>(bondDims[i]) > curMaxBondDim) curMaxBondDim =
static_cast<size_t>(bondDims[i]);
2062 SimulationType simulationType =
2063 SimulationType::kStatevector;
2064 uint64_t nextSeedStream = 0;
2066 std::unique_ptr<GpuLibStateVectorSim>
2068 std::unique_ptr<GpuDensityMatrix>
2070 std::unique_ptr<GpuMPO>
2072 std::unique_ptr<GpuLibMPSSim> mps;
2073 std::unique_ptr<GpuLibTNSim> tn;
2074 std::unique_ptr<GpuPauliPropagator>
2077 size_t nrQubits = 0;
2079 int lookaheadDepth = 0;
2080 int lookaheadDepthWithHeuristic = 0;
2081 bool useOptimalMeetingPosition =
true;
2082 std::vector<std::shared_ptr<Circuits::IOperation<>>> upcomingGates;
2083 long long int upcomingGateIndex = 0;
2084 double growthFactorSwap = 1.;
2085 double growthFactorGate = 0.65;
2087 std::unique_ptr<Simulators::MPSDummySimulator> dummySim;
2090 class GateCounterObserver :
public ISimulatorObserver {
2092 GateCounterObserver(
long long int &indexRef) : index(indexRef) {}
2096 long long int &index;
2099 std::shared_ptr<GateCounterObserver> gateCounterObserver;
2100 size_t curMaxBondDim = 0;
2102 Configuration configuration;
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)
int ApplyX(void *sim, int qubit)
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)
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
uint_fast64_t qubit_t
The type of a qubit.