20#ifdef INCLUDED_BY_FACTORY
30#include "QubitRegister.h"
43class IndividualSimulator;
55class AerState :
public ISimulator
57 friend class IndividualSimulator;
68 std::random_device rd;
71 Configure(
"method",
"statevector");
81 void Initialize()
override
84 if (simulationType == SimulationType::kMatrixProductState && !configuration.IsSet(
"mps_sample_measure_algorithm"))
85 Configure(
"mps_sample_measure_algorithm",
"mps_probabilities");
99 if (simulationType == SimulationType::kMatrixProductState && !configuration.IsSet(
"fusion_enable"))
100 Configure(
"fusion_enable",
"false");
116 void InitializeState(
size_t num_qubits, std::vector<std::complex<double>> &litudes)
override
119 if (simulationType == SimulationType::kDensityMatrix)
120 InitializeDensityMatrixFromStatevector(num_qubits, amplitudes.data());
122 InitializeStatevectorBuffer(num_qubits, amplitudes.data());
156 void InitializeState(
size_t num_qubits, AER::Vector<std::complex<double>> &litudes)
override
159 if (simulationType == SimulationType::kDensityMatrix)
160 InitializeDensityMatrixFromStatevector(num_qubits, amplitudes.data());
162 InitializeStatevectorBuffer(num_qubits, amplitudes.data());
176 void InitializeState(
size_t num_qubits, Eigen::VectorXcd &litudes)
override
179 if (simulationType == SimulationType::kDensityMatrix)
180 InitializeDensityMatrixFromStatevector(num_qubits, amplitudes.data());
182 InitializeStatevectorBuffer(num_qubits, amplitudes.data());
191 void Reset()
override
207 void Configure(
const char *key,
const char *value)
override
210 throw std::invalid_argument(
"Null Aer configuration");
211 if (std::string(key) ==
"precision" || std::string(key) ==
"use_double_precision")
213 const bool useDouble = Configuration::ParsePrecision(key, value);
214 const std::string precision = useDouble ?
"double" :
"single";
216 if (state->is_initialized())
218 state->configure(
"precision", precision);
219 configuration.SetConfiguration(
"precision", precision);
222 if (std::string(
"seed") != key && configuration.WasApplied(key, value) && state->is_initialized())
236 if ((std::string(
"matrix_product_state_truncation_mode") == key || std::string(
"matrix_product_operator_truncation_mode") == key) &&
237 std::string(
"discarded_weight") != value)
238 throw std::invalid_argument(
"Aer backend only supports the discarded_weight truncation mode");
243 if (std::string(
"seed") != key && std::string(
"use_double_precision") != key && std::string(
"matrix_product_state_truncation_mode") != key &&
244 std::string(
"matrix_product_operator_truncation_mode") != key)
248 state->configure(key, value);
250 catch (
const std::exception &)
256 if (!configuration.WasApplied(key, value))
257 configuration.SetConfiguration(key, value);
259 if (std::string(
"seed") == key)
261 const uint64_t seed = std::stoull(value);
262 SeedAuxiliaryRng(seed);
265 state->set_seed(seed);
269 if (std::string(
"method") == key)
271 if (std::string(
"statevector") == value)
272 simulationType = SimulationType::kStatevector;
273 else if (std::string(
"matrix_product_state") == value)
274 simulationType = SimulationType::kMatrixProductState;
275 else if (std::string(
"stabilizer") == value)
276 simulationType = SimulationType::kStabilizer;
277 else if (std::string(
"tensor_network") == value)
278 simulationType = SimulationType::kTensorNetwork;
279 else if (std::string(
"extended_stabilizer") == value)
280 simulationType = SimulationType::kExtendedStabilizer;
281 else if (std::string(
"density_matrix") == value)
282 simulationType = SimulationType::kDensityMatrix;
284 simulationType = SimulationType::kOther;
299 if (std::string(key) ==
"precision" || std::string(key) ==
"use_double_precision")
301 const bool fixedDouble = simulationType == SimulationType::kMatrixProductState;
302 const bool useDouble = fixedDouble || !configuration.IsSet(
"precision") || configuration.GetConfiguration(
"precision") ==
"double";
303 return std::string(key) ==
"precision" ? (useDouble ?
"double" :
"single") : (useDouble ?
"1" :
"0");
305 if (std::string(
"method") == key)
307 switch (simulationType)
309 case SimulationType::kStatevector:
310 return "statevector";
311 case SimulationType::kMatrixProductState:
312 return "matrix_product_state";
313 case SimulationType::kStabilizer:
315 case SimulationType::kTensorNetwork:
316 return "tensor_network";
317 case SimulationType::kExtendedStabilizer:
318 return "extended_stabilizer";
319 case SimulationType::kDensityMatrix:
320 return "density_matrix";
326 return configuration.GetConfiguration(key);
338 const auto ids = state->allocate_qubits(num_qubits);
350 if (state->is_initialized())
351 return state->num_of_qubits();
363 void Clear()
override
368 if (simulationType == SimulationType::kMatrixProductState && !configuration.IsSet(
"mps_sample_measure_algorithm"))
369 Configure(
"mps_sample_measure_algorithm",
"mps_probabilities");
384 if (qubits.size() >
sizeof(
size_t) * 8)
385 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
386 "number of bits in the size_t type, the outcome will be undefined"
389 const size_t res = state->apply_measure(qubits);
391 NotifyObservers(qubits);
404 auto res = state->apply_measure_many(qubits);
406 NotifyObservers(qubits);
419 state->apply_reset(qubits);
421 NotifyObservers(qubits);
424 bool SupportsQuantumChannels()
const override
426 return simulationType == SimulationType::kDensityMatrix;
439 void ApplyQuantumChannel(
const Types::qubits_vector &targets,
const QuantumChannel &channel)
override
441 if (!SupportsQuantumChannels())
442 throw std::runtime_error(
"Aer exact quantum channels require density_matrix simulation");
443 if (targets.size() != channel.GetNumberOfQubits())
444 throw std::invalid_argument(
"The number of channel targets does not match its Kraus operators");
445 if (targets.empty() || targets.size() > 2)
446 throw std::invalid_argument(
"Maestro supports only one- and two-qubit local channels");
448 std::unordered_set<Types::qubit_t> uniqueTargets;
452 throw std::invalid_argument(
"Quantum-channel qubit is out of range");
453 if (!uniqueTargets.insert(target).second)
454 throw std::invalid_argument(
"Quantum-channel target qubits must be distinct");
457 std::vector<AER::cmatrix_t> aerKrausOperators;
458 aerKrausOperators.reserve(channel.GetKrausOperators().size());
459 for (
const Eigen::MatrixXcd &krausOperator : channel.GetKrausOperators())
461 AER::cmatrix_t aerOperator(
static_cast<size_t>(krausOperator.rows()),
static_cast<size_t>(krausOperator.cols()));
462 for (Eigen::Index row = 0; row < krausOperator.rows(); ++row)
463 for (Eigen::Index column = 0; column < krausOperator.cols(); ++column)
464 aerOperator(
static_cast<size_t>(row),
static_cast<size_t>(column)) = krausOperator(row, column);
465 aerKrausOperators.emplace_back(std::move(aerOperator));
470 const AER::reg_t aerTargets(targets.begin(), targets.end());
471 state->apply_kraus(aerTargets, aerKrausOperators);
472 NotifyObservers(targets);
488 return state->probability(outcome);
503 if (simulationType == SimulationType::kDensityMatrix)
504 throw std::runtime_error(
"AerState::Amplitude is not defined for density matrix simulation");
506 if (simulationType == SimulationType::kExtendedStabilizer)
508 const auto amplitudes = state->statevector();
509 return outcome < amplitudes.size() ? amplitudes[outcome] : complex_t{};
512 return state->amplitude(outcome);
528 std::complex<double> ProjectOnZero()
override
545 if (simulationType == SimulationType::kDensityMatrix)
548 std::iota(qubits.begin(), qubits.end(), 0);
549 return state->probabilities(qubits);
552 if (simulationType == SimulationType::kExtendedStabilizer)
554 const auto amplitudes = state->statevector();
555 std::vector<double> probabilities(amplitudes.size());
556 for (
size_t outcome = 0; outcome < amplitudes.size(); ++outcome)
557 probabilities[outcome] = std::norm(amplitudes[outcome]);
558 return probabilities;
561 return state->probabilities();
577 if (simulationType == SimulationType::kDensityMatrix)
579 std::vector<double> probabilities;
580 probabilities.reserve(qubits.size());
581 for (
const auto outcome : qubits)
582 probabilities.push_back(state->probability(outcome));
583 return probabilities;
586 if (simulationType == SimulationType::kExtendedStabilizer)
588 const auto amplitudes = state->statevector();
589 std::vector<double> probabilities;
590 probabilities.reserve(qubits.size());
591 for (
const auto outcome : qubits)
592 probabilities.push_back(outcome < amplitudes.size() ? std::norm(amplitudes[outcome]) : 0.0);
593 return probabilities;
596 return state->probabilities(qubits);
617 if (qubits.empty() || shots == 0)
621 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
622 "number of bits in the Types::qubit_t type, the outcome will be "
628 std::unordered_map<Types::qubit_t, Types::qubit_t> res;
629 for (
const auto &[bits, count] : state->sample_counts_many(qubits, shots))
632 const size_t width = std::min(bits.size(),
sizeof(
Types::qubit_t) * 8);
633 for (
size_t i = 0; i < width; ++i)
636 res[packed] += count;
639 NotifyObservers(qubits);
659 if (qubits.empty() || shots == 0)
661 std::unordered_map<std::vector<bool>,
Types::qubit_t> res = state->sample_counts_many(qubits, shots);
662 NotifyObservers(qubits);
677 double ExpectationValue(
const std::string &pauliStringOrig)
override
679 if (pauliStringOrig.empty())
682 std::string pauliString = pauliStringOrig;
687 const auto pauliOp = toupper(pauliString[i]);
688 if (pauliOp !=
'I' && pauliOp !=
'Z')
698 pauli.reserve(pauliString.size());
699 qubits.reserve(pauliString.size());
701 for (
size_t q = 0; q < pauliString.size(); ++q)
703 const char p = toupper(pauliString[q]);
715 std::reverse(pauli.begin(), pauli.end());
717 return state->expval_pauli(qubits, pauli);
727 SimulatorType GetType()
const override
729 return SimulatorType::kQiskitAer;
742 return simulationType;
753 void Flush()
override
770 if (simulationType == SimulationType::kDensityMatrix)
771 savedDensityMatrix = state->move_to_matrix();
773 savedAmplitudes = state->move_to_vector();
784 if (simulationType == SimulationType::kDensityMatrix)
786 const size_t numQubits =
static_cast<size_t>(log2(savedDensityMatrix.GetRows()));
787 InitializeDensityMatrixBuffer(numQubits, savedDensityMatrix.data());
791 const size_t numQubits =
static_cast<size_t>(log2(savedAmplitudes.size()));
792 InitializeStatevectorBuffer(numQubits, savedAmplitudes.data());
810 if (simulationType == SimulationType::kExtendedStabilizer)
812 savedExtendedStabilizerState = state->clone_extended_stabilizer_state();
816 if (simulationType == SimulationType::kStatevector || simulationType == SimulationType::kDensityMatrix)
819 if (simulationType == SimulationType::kDensityMatrix)
820 InitializeDensityMatrixBuffer(numQubits, savedDensityMatrix.data());
822 InitializeStatevectorBuffer(numQubits, savedAmplitudes.data());
828 if (state->is_initialized())
830 AER::Operations::Op op;
832 op.type = AER::Operations::OpType::save_state;
833 op.name =
"save_state";
834 op.save_type = AER::Operations::DataSubType::single;
835 op.string_params.push_back(
"s");
837 for (
size_t q = 0; q < numQubits; ++q)
838 op.qubits.push_back(q);
840 state->buffer_op(std::move(op));
844 AER::ExperimentResult &last_result = state->last_result();
846 if (last_result.status == AER::ExperimentResult::Status::completed)
848 savedState = std::move(last_result.data);
855 AER::ExperimentResult &last_result_prev = state->last_result();
857 if (last_result_prev.status == AER::ExperimentResult::Status::completed)
859 savedState = std::move(last_result_prev.data);
869 if (saved && simulationType == SimulationType::kMatrixProductState)
885 AER::Operations::Op op;
887 switch (simulationType)
889 case SimulationType::kStatevector: {
898 numQubits =
static_cast<size_t>(log2(savedAmplitudes.size()));
899 InitializeStatevectorBuffer(numQubits, savedAmplitudes.data());
904 case SimulationType::kDensityMatrix: {
906 numQubits =
static_cast<size_t>(log2(savedDensityMatrix.GetRows()));
907 InitializeDensityMatrixBuffer(numQubits, savedDensityMatrix.data());
912 case SimulationType::kExtendedStabilizer:
913 if (!savedExtendedStabilizerState)
914 throw std::runtime_error(
"AerState::RestoreState: no extended stabilizer state was saved");
915 state->restore_extended_stabilizer_state(savedExtendedStabilizerState);
917 case SimulationType::kMatrixProductState:
918 op.type = AER::Operations::OpType::set_mps;
920 op.mps =
static_cast<AER::DataMap<AER::SingleData, AER::mps_container_t>
>(savedState).value()[
"s"].value();
935 numQubits = op.mps.first.size();
937 case SimulationType::kStabilizer:
938 op.type = AER::Operations::OpType::set_stabilizer;
939 op.name =
"set_stabilizer";
940 op.clifford =
static_cast<AER::DataMap<AER::SingleData, json_t>
>(savedState).value()[
"s"].value();
955 numQubits = op.clifford.num_qubits();
957 case SimulationType::kTensorNetwork:
959 throw std::runtime_error(
"AerState::RestoreState: not implemented yet "
960 "for this type of simulator.");
963 op.save_type = AER::Operations::DataSubType::single;
964 op.string_params.push_back(
"s");
966 for (
size_t q = 0; q < numQubits; ++q)
967 op.qubits.push_back(q);
970 if (!state->is_initialized())
977 state->buffer_op(std::move(op));
988 std::complex<double> AmplitudeRaw(
Types::qubit_t outcome)
override
990 if (simulationType == SimulationType::kDensityMatrix)
991 throw std::runtime_error(
"AerState::AmplitudeRaw is not defined for density matrix "
994 return savedAmplitudes[outcome];
1007 enableMultithreading = multithreading;
1008 if (state && !state->is_initialized())
1010 const std::string nrThreads = std::to_string(enableMultithreading ? 0 : 1);
1011 state->configure(
"max_parallel_threads", nrThreads);
1012 state->configure(
"parallel_state_update", nrThreads);
1013 const std::string threadsLimit = std::to_string(12);
1015 state->configure(
"statevector_parallel_threshold", threadsLimit);
1017 configuration.SetConfiguration(std::string(
"max_parallel_threads"), nrThreads);
1018 configuration.SetConfiguration(std::string(
"parallel_state_update"), nrThreads);
1019 configuration.SetConfiguration(std::string(
"statevector_parallel_threshold"), threadsLimit);
1032 return enableMultithreading;
1068 if (simulationType == SimulationType::kStatevector)
1070 const double prob = 1. - uniformZeroOne(rng);
1075 accum += std::norm(savedAmplitudes[i]);
1086 throw std::runtime_error(
"AerState::MeasureNoCollapse: Invalid simulation type for measuring "
1087 "all the qubits without collapsing the state.");
1106 std::vector<bool> MeasureNoCollapseMany()
override
1108 if (simulationType == SimulationType::kStatevector)
1110 const size_t numQubits =
static_cast<size_t>(log2(savedAmplitudes.size()));
1111 std::vector<bool> res(numQubits,
false);
1115 for (
size_t i = 0; i < numQubits; ++i)
1117 if ((state & 1) == 1)
1124 throw std::runtime_error(
"AerState::MeasureNoCollapseMany: Invalid simulation type for "
1126 "all the qubits without collapsing the state.");
1133 return configuration;
1136 const std::unordered_map<std::string, std::string> &GetConfigMap()
const override
1138 return configuration.GetConfigMap();
1142 void InitializeStatevectorBuffer(
size_t numQubits, std::complex<double> *amplitudes)
1146 state->initialize_statevector(numQubits, amplitudes,
true);
1151 AER::Operations::Op op;
1152 op.type = AER::Operations::OpType::set_statevec;
1153 op.name =
"set_statevector";
1154 op.params.assign(amplitudes, amplitudes + (
size_t{1} << numQubits));
1155 for (
size_t q = 0; q < numQubits; ++q)
1156 op.qubits.push_back(q);
1157 state->buffer_op(std::move(op));
1161 void InitializeDensityMatrixBuffer(
size_t numQubits, std::complex<double> *values)
1165 state->initialize_density_matrix(numQubits, values,
true,
true);
1170 const size_t dimension =
size_t{1} << numQubits;
1171 AER::Operations::Op op;
1172 op.type = AER::Operations::OpType::set_densmat;
1173 op.name =
"set_density_matrix";
1174 op.mats.emplace_back(dimension, dimension);
1175 std::copy(values, values + dimension * dimension, op.mats.back().data());
1176 for (
size_t q = 0; q < numQubits; ++q)
1177 op.qubits.push_back(q);
1178 state->buffer_op(std::move(op));
1182 void InitializeDensityMatrixFromStatevector(
size_t numQubits,
const std::complex<double> *amplitudes)
1184 const size_t dimension = 1ULL << numQubits;
1185 AER::cmatrix_t densityMatrix(dimension, dimension);
1186 for (
size_t row = 0; row < dimension; ++row)
1187 for (
size_t column = 0; column < dimension; ++column)
1188 densityMatrix(row, column) = amplitudes[row] * std::conj(amplitudes[column]);
1190 InitializeDensityMatrixBuffer(numQubits, densityMatrix.data());
1193 SimulationType simulationType = SimulationType::kStatevector;
1194 std::unique_ptr<QiskitAerState> state = std::make_unique<QiskitAerState>();
1195 AER::Vector<complex_t> savedAmplitudes;
1196 AER::cmatrix_t savedDensityMatrix;
1197 std::shared_ptr<AER::QuantumState::Base> savedExtendedStabilizerState;
1199 bool enableMultithreading =
true;
1200 AER::Data savedState;
1202 std::mt19937_64 rng;
1203 uint64_t nextSeedStream = 0;
1204 std::uniform_real_distribution<double> uniformZeroOne{0., 1.};
1206 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)
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)
Bounded online routing based on current physical bond dimensions.
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
uint_fast64_t qubit_t
The type of a qubit.