20#ifdef INCLUDED_BY_FACTORY
29#include "QubitRegister.h"
41class IndividualSimulator;
53class AerState :
public ISimulator {
54 friend class IndividualSimulator;
64 std::random_device rd;
67 Configure(
"method",
"statevector");
77 void Initialize()
override {
79 if (simulationType == SimulationType::kMatrixProductState && !configuration.IsSet(
"mps_sample_measure_algorithm"))
80 Configure(
"mps_sample_measure_algorithm",
"mps_probabilities");
94 if (simulationType == SimulationType::kMatrixProductState && !configuration.IsSet(
"fusion_enable"))
95 Configure(
"fusion_enable",
"false");
111 void InitializeState(
size_t num_qubits,
112 std::vector<std::complex<double>> &litudes)
override {
114 if (simulationType == SimulationType::kDensityMatrix)
115 InitializeDensityMatrixFromStatevector(num_qubits, amplitudes.data());
117 state->initialize_statevector(num_qubits, amplitudes.data(),
true);
151 void InitializeState(
size_t num_qubits,
152 AER::Vector<std::complex<double>> &litudes)
override {
154 if (simulationType == SimulationType::kDensityMatrix)
155 InitializeDensityMatrixFromStatevector(num_qubits, amplitudes.data());
157 state->initialize_statevector(num_qubits, amplitudes.move_to_buffer(),
172 void InitializeState(
size_t num_qubits,
173 Eigen::VectorXcd &litudes)
override {
175 if (simulationType == SimulationType::kDensityMatrix)
176 InitializeDensityMatrixFromStatevector(num_qubits, amplitudes.data());
178 state->initialize_statevector(num_qubits, amplitudes.data(),
true);
187 void Reset()
override {
202 void Configure(
const char* key,
const char* value)
override {
203 if (std::string(
"seed") != key && configuration.WasApplied(key, value) &&
204 state->is_initialized())
218 if ((std::string(
"matrix_product_state_truncation_mode") == key ||
219 std::string(
"matrix_product_operator_truncation_mode") == key) &&
220 std::string(
"discarded_weight") != value)
221 throw std::invalid_argument(
222 "Aer backend only supports the discarded_weight truncation mode");
224 if (!configuration.WasApplied(key, value))
225 configuration.SetConfiguration(key, value);
227 if (std::string(
"seed") == key) {
228 const uint64_t seed = std::stoull(value);
231 state->set_seed(seed);
235 if (std::string(
"method") == key) {
236 if (std::string(
"statevector") == value)
237 simulationType = SimulationType::kStatevector;
238 else if (std::string(
"matrix_product_state") == value)
239 simulationType = SimulationType::kMatrixProductState;
240 else if (std::string(
"stabilizer") == value)
241 simulationType = SimulationType::kStabilizer;
242 else if (std::string(
"tensor_network") == value)
243 simulationType = SimulationType::kTensorNetwork;
244 else if (std::string(
"extended_stabilizer") == value)
245 simulationType = SimulationType::kExtendedStabilizer;
246 else if (std::string(
"density_matrix") == value)
247 simulationType = SimulationType::kDensityMatrix;
249 simulationType = SimulationType::kOther;
254 if (std::string(
"matrix_product_state_truncation_mode") == key ||
255 std::string(
"matrix_product_operator_truncation_mode") == key)
258 if (std::string(
"use_double_precision") != key)
259 state->configure(key, value);
270 if (std::string(
"method") == key) {
271 switch (simulationType) {
272 case SimulationType::kStatevector:
273 return "statevector";
274 case SimulationType::kMatrixProductState:
275 return "matrix_product_state";
276 case SimulationType::kStabilizer:
278 case SimulationType::kTensorNetwork:
279 return "tensor_network";
280 case SimulationType::kExtendedStabilizer:
281 return "extended_stabilizer";
282 case SimulationType::kDensityMatrix:
283 return "density_matrix";
289 return configuration.GetConfiguration(key);
300 const auto ids = state->allocate_qubits(num_qubits);
311 if (state->is_initialized())
return state->num_of_qubits();
323 void Clear()
override {
327 if (simulationType == SimulationType::kMatrixProductState && !configuration.IsSet(
"mps_sample_measure_algorithm"))
328 Configure(
"mps_sample_measure_algorithm",
"mps_probabilities");
342 if (qubits.size() >
sizeof(
size_t) * 8)
344 <<
"Warning: The number of qubits to measure is larger than the "
345 "number of bits in the size_t type, the outcome will be undefined"
348 const size_t res = state->apply_measure(qubits);
350 NotifyObservers(qubits);
362 auto res = state->apply_measure_many(qubits);
364 NotifyObservers(qubits);
376 state->apply_reset(qubits);
378 NotifyObservers(qubits);
381 bool SupportsQuantumChannels()
const override {
382 return simulationType == SimulationType::kDensityMatrix;
396 const QuantumChannel &channel)
override {
397 if (!SupportsQuantumChannels())
398 throw std::runtime_error(
399 "Aer exact quantum channels require density_matrix simulation");
400 if (targets.size() != channel.GetNumberOfQubits())
401 throw std::invalid_argument(
402 "The number of channel targets does not match its Kraus operators");
403 if (targets.empty() || targets.size() > 2)
404 throw std::invalid_argument(
405 "Maestro supports only one- and two-qubit local channels");
407 std::unordered_set<Types::qubit_t> uniqueTargets;
410 throw std::invalid_argument(
"Quantum-channel qubit is out of range");
411 if (!uniqueTargets.insert(target).second)
412 throw std::invalid_argument(
413 "Quantum-channel target qubits must be distinct");
416 std::vector<AER::cmatrix_t> aerKrausOperators;
417 aerKrausOperators.reserve(channel.GetKrausOperators().size());
418 for (
const Eigen::MatrixXcd &krausOperator :
419 channel.GetKrausOperators()) {
420 AER::cmatrix_t aerOperator(
421 static_cast<size_t>(krausOperator.rows()),
422 static_cast<size_t>(krausOperator.cols()));
423 for (Eigen::Index row = 0; row < krausOperator.rows(); ++row)
424 for (Eigen::Index column = 0; column < krausOperator.cols(); ++column)
425 aerOperator(
static_cast<size_t>(row),
426 static_cast<size_t>(column)) =
427 krausOperator(row, column);
428 aerKrausOperators.emplace_back(std::move(aerOperator));
433 const AER::reg_t aerTargets(targets.begin(), targets.end());
434 state->apply_kraus(aerTargets, aerKrausOperators);
435 NotifyObservers(targets);
450 return state->probability(outcome);
464 if (simulationType == SimulationType::kDensityMatrix)
465 throw std::runtime_error(
466 "AerState::Amplitude is not defined for density matrix simulation");
468 if (simulationType == SimulationType::kExtendedStabilizer) {
469 const auto amplitudes = state->statevector();
470 return outcome < amplitudes.size() ? amplitudes[outcome] : complex_t{};
473 return state->amplitude(outcome);
489 std::complex<double> ProjectOnZero()
override {
505 if (simulationType == SimulationType::kDensityMatrix) {
507 std::iota(qubits.begin(), qubits.end(), 0);
508 return state->probabilities(qubits);
511 if (simulationType == SimulationType::kExtendedStabilizer) {
512 const auto amplitudes = state->statevector();
513 std::vector<double> probabilities(amplitudes.size());
514 for (
size_t outcome = 0; outcome < amplitudes.size(); ++outcome)
515 probabilities[outcome] = std::norm(amplitudes[outcome]);
516 return probabilities;
519 return state->probabilities();
535 if (simulationType == SimulationType::kDensityMatrix) {
536 std::vector<double> probabilities;
537 probabilities.reserve(qubits.size());
538 for (
const auto outcome : qubits)
539 probabilities.push_back(state->probability(outcome));
540 return probabilities;
543 if (simulationType == SimulationType::kExtendedStabilizer) {
544 const auto amplitudes = state->statevector();
545 std::vector<double> probabilities;
546 probabilities.reserve(qubits.size());
547 for (
const auto outcome : qubits)
548 probabilities.push_back(
549 outcome < amplitudes.size() ? std::norm(amplitudes[outcome]) : 0.0);
550 return probabilities;
553 return state->probabilities(qubits);
572 std::unordered_map<Types::qubit_t, Types::qubit_t>
SampleCounts(
574 if (qubits.empty() || shots == 0)
return {};
578 <<
"Warning: The number of qubits to measure is larger than the "
579 "number of bits in the Types::qubit_t type, the outcome will be "
585 std::unordered_map<Types::qubit_t, Types::qubit_t> res;
586 for (
const auto& [bits, count] : state->sample_counts_many(qubits, shots)) {
588 const size_t width = std::min(bits.size(),
sizeof(
Types::qubit_t) * 8);
589 for (
size_t i = 0; i < width; ++i)
591 res[packed] += count;
594 NotifyObservers(qubits);
612 std::unordered_map<std::vector<bool>,
Types::qubit_t> SampleCountsMany(
614 if (qubits.empty() || shots == 0)
return {};
616 state->sample_counts_many(qubits, shots);
617 NotifyObservers(qubits);
632 double ExpectationValue(
const std::string &pauliStringOrig)
override {
633 if (pauliStringOrig.empty())
return 1.0;
635 std::string pauliString = pauliStringOrig;
638 const auto pauliOp = toupper(pauliString[i]);
639 if (pauliOp !=
'I' && pauliOp !=
'Z')
return 0.0;
648 pauli.reserve(pauliString.size());
649 qubits.reserve(pauliString.size());
651 for (
size_t q = 0; q < pauliString.size(); ++q) {
652 const char p = toupper(pauliString[q]);
653 if (p ==
'I')
continue;
659 if (qubits.empty())
return 1.0;
662 std::reverse(pauli.begin(), pauli.end());
664 return state->expval_pauli(qubits, pauli);
674 SimulatorType GetType()
const override {
return SimulatorType::kQiskitAer; }
694 void Flush()
override {
709 if (simulationType == SimulationType::kDensityMatrix)
710 savedDensityMatrix = state->move_to_matrix();
712 savedAmplitudes = state->move_to_vector();
722 if (simulationType == SimulationType::kDensityMatrix) {
723 const size_t numQubits =
static_cast<size_t>(
724 log2(savedDensityMatrix.GetRows()));
725 state->initialize_density_matrix(numQubits, savedDensityMatrix.data(),
730 const size_t numQubits =
static_cast<size_t>(log2(savedAmplitudes.size()));
731 state->initialize_statevector(numQubits, savedAmplitudes.move_to_buffer(),
748 if (simulationType == SimulationType::kExtendedStabilizer) {
749 savedExtendedStabilizerState = state->clone_extended_stabilizer_state();
753 if (simulationType == SimulationType::kStatevector ||
754 simulationType == SimulationType::kDensityMatrix) {
756 if (simulationType == SimulationType::kDensityMatrix)
757 state->initialize_density_matrix(numQubits, savedDensityMatrix.data(),
760 state->initialize_statevector(numQubits, savedAmplitudes.data(),
true);
766 if (state->is_initialized()) {
767 AER::Operations::Op op;
769 op.type = AER::Operations::OpType::save_state;
770 op.name =
"save_state";
771 op.save_type = AER::Operations::DataSubType::single;
772 op.string_params.push_back(
"s");
774 for (
size_t q = 0; q < numQubits; ++q) op.qubits.push_back(q);
776 state->buffer_op(std::move(op));
780 AER::ExperimentResult &last_result = state->last_result();
782 if (last_result.status == AER::ExperimentResult::Status::completed) {
783 savedState = std::move(last_result.data);
788 AER::ExperimentResult &last_result_prev = state->last_result();
790 if (last_result_prev.status == AER::ExperimentResult::Status::completed) {
791 savedState = std::move(last_result_prev.data);
801 if (saved && simulationType == SimulationType::kMatrixProductState)
816 AER::Operations::Op op;
818 switch (simulationType) {
819 case SimulationType::kStatevector: {
828 numQubits =
static_cast<size_t>(log2(savedAmplitudes.size()));
829 state->initialize_statevector(numQubits, savedAmplitudes.data(),
true);
833 case SimulationType::kDensityMatrix: {
835 numQubits =
static_cast<size_t>(
836 log2(savedDensityMatrix.GetRows()));
837 state->initialize_density_matrix(numQubits, savedDensityMatrix.data(),
842 case SimulationType::kExtendedStabilizer:
843 if (!savedExtendedStabilizerState)
844 throw std::runtime_error(
845 "AerState::RestoreState: no extended stabilizer state was saved");
846 state->restore_extended_stabilizer_state(savedExtendedStabilizerState);
848 case SimulationType::kMatrixProductState:
849 op.type = AER::Operations::OpType::set_mps;
852 static_cast<AER::DataMap<AER::SingleData, AER::mps_container_t>
>(
870 numQubits = op.mps.first.size();
872 case SimulationType::kStabilizer:
873 op.type = AER::Operations::OpType::set_stabilizer;
874 op.name =
"set_stabilizer";
876 static_cast<AER::DataMap<AER::SingleData, json_t>
>(savedState)
893 numQubits = op.clifford.num_qubits();
895 case SimulationType::kTensorNetwork:
897 throw std::runtime_error(
898 "AerState::RestoreState: not implemented yet "
899 "for this type of simulator.");
902 op.save_type = AER::Operations::DataSubType::single;
903 op.string_params.push_back(
"s");
905 for (
size_t q = 0; q < numQubits; ++q) op.qubits.push_back(q);
908 if (!state->is_initialized()) {
914 state->buffer_op(std::move(op));
925 std::complex<double> AmplitudeRaw(
Types::qubit_t outcome)
override {
926 if (simulationType == SimulationType::kDensityMatrix)
927 throw std::runtime_error(
928 "AerState::AmplitudeRaw is not defined for density matrix "
931 return savedAmplitudes[outcome];
943 enableMultithreading = multithreading;
944 if (state && !state->is_initialized()) {
945 const std::string nrThreads =
946 std::to_string(enableMultithreading
949 state->configure(
"max_parallel_threads", nrThreads);
950 state->configure(
"parallel_state_update", nrThreads);
951 const std::string threadsLimit =
954 state->configure(
"statevector_parallel_threshold", threadsLimit);
956 configuration.SetConfiguration(std::string(
"max_parallel_threads"), nrThreads);
957 configuration.SetConfiguration(std::string(
"parallel_state_update"), nrThreads);
958 configuration.SetConfiguration(std::string(
"statevector_parallel_threshold"), threadsLimit);
981 bool IsQcsim()
const override {
return false; }
1000 if (simulationType == SimulationType::kStatevector) {
1002 1. - uniformZeroOne(rng);
1006 accum += std::norm(savedAmplitudes[i]);
1007 if (prob <= accum) {
1016 throw std::runtime_error(
1017 "AerState::MeasureNoCollapse: Invalid simulation type for measuring "
1018 "all the qubits without collapsing the state.");
1037 std::vector<bool> MeasureNoCollapseMany()
override {
1038 if (simulationType == SimulationType::kStatevector) {
1039 const size_t numQubits =
1040 static_cast<size_t>(log2(savedAmplitudes.size()));
1041 std::vector<bool> res(numQubits,
false);
1045 for (
size_t i = 0; i < numQubits; ++i) {
1046 if ((state & 1) == 1) res[i] =
true;
1052 throw std::runtime_error(
1053 "AerState::MeasureNoCollapseMany: Invalid simulation type for "
1055 "all the qubits without collapsing the state.");
1061 return configuration;
1064 const std::unordered_map<std::string, std::string>& GetConfigMap()
1066 return configuration.GetConfigMap();
1070 void InitializeDensityMatrixFromStatevector(
1071 size_t numQubits,
const std::complex<double>* amplitudes) {
1072 const size_t dimension = 1ULL << numQubits;
1073 AER::cmatrix_t densityMatrix(dimension, dimension);
1074 for (
size_t row = 0; row < dimension; ++row)
1075 for (
size_t column = 0; column < dimension; ++column)
1076 densityMatrix(row, column) =
1077 amplitudes[row] * std::conj(amplitudes[column]);
1079 state->initialize_density_matrix(numQubits, densityMatrix.data(),
true,
1083 SimulationType simulationType =
1084 SimulationType::kStatevector;
1085 std::unique_ptr<QiskitAerState> state =
1086 std::make_unique<QiskitAerState>();
1087 AER::Vector<complex_t> savedAmplitudes;
1088 AER::cmatrix_t savedDensityMatrix;
1089 std::shared_ptr<AER::QuantumState::Base> savedExtendedStabilizerState;
1091 bool enableMultithreading =
true;
1092 AER::Data savedState;
1094 std::mt19937_64 rng;
1095 uint64_t nextSeedStream = 0;
1096 std::uniform_real_distribution<double> uniformZeroOne{0., 1.};
1098 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)
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
uint_fast64_t qubit_t
The type of a qubit.