Maestro 0.3.1
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
AerState.h
Go to the documentation of this file.
1
12
13#pragma once
14
15#ifndef _AER_STATE_H_
16#define _AER_STATE_H_
17
18#ifndef NO_QISKIT_AER
19
20#ifdef INCLUDED_BY_FACTORY
21
22#include <algorithm>
23#include <iomanip>
24#include <limits>
25#include <numeric>
26#include <sstream>
27#include <stdexcept>
28
29#include "QubitRegister.h"
30#include "Simulator.h"
31
32#include "QiskitAerState.h"
33#include "Configuration.h"
34
35namespace Simulators {
36// TODO: Maybe use the pimpl idiom
37// https://en.cppreference.com/w/cpp/language/pimpl to hide the implementation
38// for good but during development this should be good enough
39namespace Private {
40
41class IndividualSimulator;
42
53class AerState : public ISimulator {
54 friend class IndividualSimulator;
56 public:
63 AerState() {
64 std::random_device rd;
65
66 rng.seed(rd());
67 Configure("method", "statevector");
68 }
69
77 void Initialize() override {
78 SetMultithreading(enableMultithreading);
79 if (simulationType == SimulationType::kMatrixProductState && !configuration.IsSet("mps_sample_measure_algorithm"))
80 Configure("mps_sample_measure_algorithm", "mps_probabilities");
81
82 // Gate fusion must be off for MPS. Aer intends this itself -- AerState::transpile_ops()
83 // has `case Method::matrix_product_state: fusion_pass_.active = false;` -- but the very
84 // next statement is `fusion_pass_.set_config(configs_)`, and Fusion::set_config does an
85 // unconditional `active = config.fusion_enable`, whose default is true. The MPS disable is
86 // therefore dead code and fusion runs anyway (see qiskit-aer/src/transpile/fusion.hpp and
87 // src/controllers/state_controller.hpp). Aer's other execution path, transpile_fusion() in
88 // simulators/circuit_executor.hpp, guards against exactly this with an early return.
89 // Fixed in our fork as well, but kept here so a build against an unpatched Aer behaves.
90 // It is not a small effect: fusing gates into wider unitaries forces the MPS to bring more
91 // qubits together and do bigger SVDs, and on a 16 qubit brickwork circuit at bond dimension
92 // 128 it costs about 7x (1.5s -> 10.7s). Only set it when the caller has not, so an explicit
93 // "fusion_enable" from a configuration still wins.
94 if (simulationType == SimulationType::kMatrixProductState && !configuration.IsSet("fusion_enable"))
95 Configure("fusion_enable", "false");
96
97 state->initialize();
98 }
99
111 void InitializeState(size_t num_qubits,
112 std::vector<std::complex<double>> &amplitudes) override {
113 Clear();
114 if (simulationType == SimulationType::kDensityMatrix)
115 InitializeDensityMatrixFromStatevector(num_qubits, amplitudes.data());
116 else
117 state->initialize_statevector(num_qubits, amplitudes.data(), true);
118 }
119
131 /*
132 void InitializeState(size_t num_qubits, std::vector<std::complex<double>,
133 avoid_init_allocator<std::complex<double>>>& amplitudes) override
134 {
135 Clear();
136 state->initialize_statevector(num_qubits, amplitudes.data(), true);
137 }
138 */
139
151 void InitializeState(size_t num_qubits,
152 AER::Vector<std::complex<double>> &amplitudes) override {
153 Clear();
154 if (simulationType == SimulationType::kDensityMatrix)
155 InitializeDensityMatrixFromStatevector(num_qubits, amplitudes.data());
156 else
157 state->initialize_statevector(num_qubits, amplitudes.move_to_buffer(),
158 false);
159 }
160
172 void InitializeState(size_t num_qubits,
173 Eigen::VectorXcd &amplitudes) override {
174 Clear();
175 if (simulationType == SimulationType::kDensityMatrix)
176 InitializeDensityMatrixFromStatevector(num_qubits, amplitudes.data());
177 else
178 state->initialize_statevector(num_qubits, amplitudes.data(), true);
179 }
180
187 void Reset() override {
188 const auto numQubits = GetNumberOfQubits();
189 Clear();
190 AllocateQubits(numQubits);
191 state->initialize();
192 }
193
202 void Configure(const char* key, const char* value) override {
203 if (std::string("seed") != key && configuration.WasApplied(key, value) &&
204 state->is_initialized())
205 return;
206
207 // Validate BEFORE storing below: Qiskit Aer's own MPS/MPO truncation always
208 // implements the discarded-weight (Aer/iTensor) convention natively -- see
209 // reduce_zeros() in qiskit-aer/src/simulators/matrix_product_state/svd.cpp.
210 // Unlike the QCSim and GPU backends (see Simulators/QCSimState.h,
211 // Simulators/GpuState.h), there is no relative-to-max mode to switch to
212 // here, so requesting anything else is rejected outright. Checked here,
213 // ahead of the store below, so a rejected value never lingers in
214 // `configuration` -- otherwise it would still show up via
215 // GetConfiguration(), or get silently replayed later by Clone()'s
216 // generic configuration-replay loop, throwing again from an unrelated
217 // call site.
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");
223
224 if (!configuration.WasApplied(key, value))
225 configuration.SetConfiguration(key, value);
226
227 if (std::string("seed") == key) {
228 const uint64_t seed = std::stoull(value);
229 nextSeedStream = 0;
230 rng.seed(seed);
231 state->set_seed(seed);
232 return;
233 }
234
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;
248 else
249 simulationType = SimulationType::kOther;
250 }
251
252 // Already validated above; this key is a no-op once accepted (Aer has no
253 // other mode to switch to), so don't forward it to state->configure().
254 if (std::string("matrix_product_state_truncation_mode") == key ||
255 std::string("matrix_product_operator_truncation_mode") == key)
256 return;
257
258 if (std::string("use_double_precision") != key)
259 state->configure(key, value);
260 }
261
269 std::string GetConfiguration(const char *key) const override {
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:
277 return "stabilizer";
278 case SimulationType::kTensorNetwork:
279 return "tensor_network";
280 case SimulationType::kExtendedStabilizer:
281 return "extended_stabilizer";
282 case SimulationType::kDensityMatrix:
283 return "density_matrix";
284 default:
285 return "other";
286 }
287 }
288
289 return configuration.GetConfiguration(key);
290 }
291
299 size_t AllocateQubits(size_t num_qubits) override {
300 const auto ids = state->allocate_qubits(num_qubits);
301 return ids[0];
302 }
303
310 size_t GetNumberOfQubits() const override {
311 if (state->is_initialized()) return state->num_of_qubits();
312
313 return 0;
314 }
315
323 void Clear() override {
324 state->clear();
325 SetMultithreading(enableMultithreading);
326
327 if (simulationType == SimulationType::kMatrixProductState && !configuration.IsSet("mps_sample_measure_algorithm"))
328 Configure("mps_sample_measure_algorithm", "mps_probabilities");
329 }
330
341 size_t Measure(const Types::qubits_vector &qubits) override {
342 if (qubits.size() > sizeof(size_t) * 8)
343 std::cerr
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"
346 << std::endl;
347
348 const size_t res = state->apply_measure(qubits);
349
350 NotifyObservers(qubits);
351
352 return res;
353 }
354
361 std::vector<bool> MeasureMany(const Types::qubits_vector &qubits) override {
362 auto res = state->apply_measure_many(qubits);
363
364 NotifyObservers(qubits);
365
366 return res;
367 }
368
375 void ApplyReset(const Types::qubits_vector &qubits) override {
376 state->apply_reset(qubits);
377
378 NotifyObservers(qubits);
379 }
380
381 bool SupportsQuantumChannels() const override {
382 return simulationType == SimulationType::kDensityMatrix;
383 }
384
395 void ApplyQuantumChannel(const Types::qubits_vector &targets,
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");
406
407 std::unordered_set<Types::qubit_t> uniqueTargets;
408 for (const Types::qubit_t target : targets) {
409 if (target >= GetNumberOfQubits())
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");
414 }
415
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));
429 }
430
431 // Both QCSim and Aer treat targets[0] as local matrix bit zero (LSB), so
432 // channel target order is preserved and matrices need no permutation.
433 const AER::reg_t aerTargets(targets.begin(), targets.end());
434 state->apply_kraus(aerTargets, aerKrausOperators);
435 NotifyObservers(targets);
436 }
437
449 double Probability(Types::qubit_t outcome) override {
450 return state->probability(outcome);
451 }
452
463 std::complex<double> Amplitude(Types::qubit_t outcome) override {
464 if (simulationType == SimulationType::kDensityMatrix)
465 throw std::runtime_error(
466 "AerState::Amplitude is not defined for density matrix simulation");
467
468 if (simulationType == SimulationType::kExtendedStabilizer) {
469 const auto amplitudes = state->statevector();
470 return outcome < amplitudes.size() ? amplitudes[outcome] : complex_t{};
471 }
472
473 return state->amplitude(outcome);
474 }
475
489 std::complex<double> ProjectOnZero() override {
490 return Amplitude(0);
491 }
492
493
504 std::vector<double> AllProbabilities() override {
505 if (simulationType == SimulationType::kDensityMatrix) {
507 std::iota(qubits.begin(), qubits.end(), 0);
508 return state->probabilities(qubits);
509 }
510
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;
517 }
518
519 return state->probabilities();
520 }
521
533 std::vector<double> Probabilities(
534 const Types::qubits_vector &qubits) override {
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;
541 }
542
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;
551 }
552
553 return state->probabilities(qubits);
554 }
555
572 std::unordered_map<Types::qubit_t, Types::qubit_t> SampleCounts(
573 const Types::qubits_vector &qubits, size_t shots = 1000) override {
574 if (qubits.empty() || shots == 0) return {};
575
576 if (qubits.size() > sizeof(Types::qubit_t) * 8)
577 std::cerr
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 "
580 "undefined"
581 << std::endl;
582
583 // Aer MPS can return native samples sorted by qubit index. Use the
584 // ordered sampling adapter for both public result formats.
585 std::unordered_map<Types::qubit_t, Types::qubit_t> res;
586 for (const auto& [bits, count] : state->sample_counts_many(qubits, shots)) {
587 Types::qubit_t packed = 0;
588 const size_t width = std::min(bits.size(), sizeof(Types::qubit_t) * 8);
589 for (size_t i = 0; i < width; ++i)
590 if (bits[i]) packed |= Types::qubit_t(1) << i;
591 res[packed] += count;
592 }
593
594 NotifyObservers(qubits);
595
596 return res;
597 }
598
612 std::unordered_map<std::vector<bool>, Types::qubit_t> SampleCountsMany(
613 const Types::qubits_vector &qubits, size_t shots = 1000) override {
614 if (qubits.empty() || shots == 0) return {};
615 std::unordered_map<std::vector<bool>, Types::qubit_t> res =
616 state->sample_counts_many(qubits, shots);
617 NotifyObservers(qubits);
618 return res;
619 }
620
632 double ExpectationValue(const std::string &pauliStringOrig) override {
633 if (pauliStringOrig.empty()) return 1.0;
634
635 std::string pauliString = pauliStringOrig;
636 if (pauliString.size() > GetNumberOfQubits()) {
637 for (size_t i = GetNumberOfQubits(); i < pauliString.size(); ++i) {
638 const auto pauliOp = toupper(pauliString[i]);
639 if (pauliOp != 'I' && pauliOp != 'Z') return 0.0;
640 }
641
642 pauliString.resize(GetNumberOfQubits());
643 }
644
645 AER::reg_t qubits;
646 std::string pauli;
647
648 pauli.reserve(pauliString.size());
649 qubits.reserve(pauliString.size());
650
651 for (size_t q = 0; q < pauliString.size(); ++q) {
652 const char p = toupper(pauliString[q]);
653 if (p == 'I') continue;
654
655 pauli.push_back(p);
656 qubits.push_back(q);
657 }
658
659 if (qubits.empty()) return 1.0;
660
661 // qiskit aer expects the pauli string in reverse order
662 std::reverse(pauli.begin(), pauli.end());
663
664 return state->expval_pauli(qubits, pauli);
665 }
666
674 SimulatorType GetType() const override { return SimulatorType::kQiskitAer; }
675
684 SimulationType GetSimulationType() const override { return simulationType; }
685
694 void Flush() override {
695 state->flush_ops();
696 // state->set_random_seed(); // avoid reusing the old seed
697 }
698
708 void SaveStateToInternalDestructive() override {
709 if (simulationType == SimulationType::kDensityMatrix)
710 savedDensityMatrix = state->move_to_matrix();
711 else
712 savedAmplitudes = state->move_to_vector();
713 }
714
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(),
726 true, true);
727 return;
728 }
729
730 const size_t numQubits = static_cast<size_t>(log2(savedAmplitudes.size()));
731 state->initialize_statevector(numQubits, savedAmplitudes.move_to_buffer(),
732 false);
733 }
734
743 void SaveState() override {
744 if (!state) return;
745
746 const auto numQubits = GetNumberOfQubits();
747
748 if (simulationType == SimulationType::kExtendedStabilizer) {
749 savedExtendedStabilizerState = state->clone_extended_stabilizer_state();
750 return;
751 }
752
753 if (simulationType == SimulationType::kStatevector ||
754 simulationType == SimulationType::kDensityMatrix) {
756 if (simulationType == SimulationType::kDensityMatrix)
757 state->initialize_density_matrix(numQubits, savedDensityMatrix.data(),
758 true, true);
759 else
760 state->initialize_statevector(numQubits, savedAmplitudes.data(), true);
761 return;
762 }
763
764 bool saved = false;
765
766 if (state->is_initialized()) {
767 AER::Operations::Op op;
768
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");
773
774 for (size_t q = 0; q < numQubits; ++q) op.qubits.push_back(q);
775
776 state->buffer_op(std::move(op));
777 Flush();
778
779 // get the state from the last result
780 AER::ExperimentResult &last_result = state->last_result();
781 // state should be in last_result.data
782 if (last_result.status == AER::ExperimentResult::Status::completed) {
783 savedState = std::move(last_result.data);
784 saved = true;
785 }
786 } else {
787 // try get the state from the last result
788 AER::ExperimentResult &last_result_prev = state->last_result();
789 // state should be in last_result.data
790 if (last_result_prev.status == AER::ExperimentResult::Status::completed) {
791 savedState = std::move(last_result_prev.data);
792 saved = true;
793 }
794 }
795
796 // this is a hack, for statevector and matrix product state if the last op
797 // is executed, it can destroy the state! see also the workaround for
798 // statevector for the stabilizer at least for now it doesn't seem to do
799 // that
800 // TODO: check everything!!!!
801 if (saved && simulationType == SimulationType::kMatrixProductState)
802 RestoreState();
803 }
804
813 void RestoreState() override {
814 auto numQubits = GetNumberOfQubits();
815
816 AER::Operations::Op op;
817
818 switch (simulationType) {
819 case SimulationType::kStatevector: {
820 // op.type = AER::Operations::OpType::set_statevec;
821 // op.name = "set_statevec";
822
823 // const auto& vec = static_cast<AER::DataMap<AER::SingleData,
824 // AER::Vector<complex_t>>>(savedState).value()["s"].value();
825
826 // this is a hack until I figure it out
827 Clear();
828 numQubits = static_cast<size_t>(log2(savedAmplitudes.size()));
829 state->initialize_statevector(numQubits, savedAmplitudes.data(), true);
830
831 return;
832 } break;
833 case SimulationType::kDensityMatrix: {
834 Clear();
835 numQubits = static_cast<size_t>(
836 log2(savedDensityMatrix.GetRows()));
837 state->initialize_density_matrix(numQubits, savedDensityMatrix.data(),
838 true, true);
839
840 return;
841 } break;
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);
847 return;
848 case SimulationType::kMatrixProductState:
849 op.type = AER::Operations::OpType::set_mps;
850 op.name = "set_mps";
851 op.mps =
852 static_cast<AER::DataMap<AER::SingleData, AER::mps_container_t>>(
853 savedState)
854 .value()["s"]
855 .value();
856
857 /*
858 {
859 auto& value = static_cast<AER::DataMap<AER::SingleData,
860 AER::mps_container_t>>(savedState).value(); if (!value.empty())
861 {
862 if (value.find("s") != value.end())
863 op.mps = value["s"].value();
864 else if (value.find("matrix_product_state") !=
865 value.end()) op.mps = value["matrix_product_state"].value();
866 }
867 }
868 */
869
870 numQubits = op.mps.first.size();
871 break;
872 case SimulationType::kStabilizer:
873 op.type = AER::Operations::OpType::set_stabilizer;
874 op.name = "set_stabilizer";
875 op.clifford =
876 static_cast<AER::DataMap<AER::SingleData, json_t>>(savedState)
877 .value()["s"]
878 .value();
879
880 /*
881 {
882 auto& value = static_cast<AER::DataMap<AER::SingleData,
883 json_t>>(savedState).value(); if (!value.empty())
884 {
885 if (value.find("s") != value.end())
886 op.clifford = value["s"].value();
887 else if (value.find("stabilizer") != value.end())
888 op.clifford = value["stabilizer"].value();
889 }
890 }
891 */
892
893 numQubits = op.clifford.num_qubits();
894 break;
895 case SimulationType::kTensorNetwork:
896 default:
897 throw std::runtime_error(
898 "AerState::RestoreState: not implemented yet "
899 "for this type of simulator.");
900 }
901
902 op.save_type = AER::Operations::DataSubType::single;
903 op.string_params.push_back("s");
904
905 for (size_t q = 0; q < numQubits; ++q) op.qubits.push_back(q);
906
907 // WHY?
908 if (!state->is_initialized()) {
909 Clear();
910 AllocateQubits(numQubits);
911 state->initialize();
912 }
913
914 state->buffer_op(std::move(op));
915 Flush();
916 }
917
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 "
929 "simulation");
930
931 return savedAmplitudes[outcome];
932 }
933
942 void SetMultithreading(bool multithreading = true) override {
943 enableMultithreading = multithreading;
944 if (state && !state->is_initialized()) {
945 const std::string nrThreads =
946 std::to_string(enableMultithreading
947 ? 0
948 : 1); // 0 means auto/all available, 1 limits to 1
949 state->configure("max_parallel_threads", nrThreads);
950 state->configure("parallel_state_update", nrThreads);
951 const std::string threadsLimit =
952 std::to_string(12); // set one less, multithreading is started if the
953 // value is bigger than this
954 state->configure("statevector_parallel_threshold", threadsLimit);
955
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);
959 }
960 }
961
969 bool GetMultithreading() const override { return enableMultithreading; }
970
981 bool IsQcsim() const override { return false; }
982
1000 if (simulationType == SimulationType::kStatevector) {
1001 const double prob =
1002 1. - uniformZeroOne(rng); // this excludes 0 as probabiliy
1003 double accum = 0;
1004 Types::qubit_t state = 0;
1005 for (Types::qubit_t i = 0; i < savedAmplitudes.size(); ++i) {
1006 accum += std::norm(savedAmplitudes[i]);
1007 if (prob <= accum) {
1008 state = i;
1009 break;
1010 }
1011 }
1012
1013 return state;
1014 }
1015
1016 throw std::runtime_error(
1017 "AerState::MeasureNoCollapse: Invalid simulation type for measuring "
1018 "all the qubits without collapsing the state.");
1019
1020 return 0;
1021 }
1022
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);
1042
1044
1045 for (size_t i = 0; i < numQubits; ++i) {
1046 if ((state & 1) == 1) res[i] = true;
1047 state >>= 1;
1048 }
1049
1050 return res;
1051 }
1052 throw std::runtime_error(
1053 "AerState::MeasureNoCollapseMany: Invalid simulation type for "
1054 "measuring "
1055 "all the qubits without collapsing the state.");
1056
1057 return {};
1058 }
1059
1060 const Configuration& GetConfiguration() const {
1061 return configuration;
1062 }
1063
1064 const std::unordered_map<std::string, std::string>& GetConfigMap()
1065 const override {
1066 return configuration.GetConfigMap();
1067 }
1068
1069 protected:
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]);
1078
1079 state->initialize_density_matrix(numQubits, densityMatrix.data(), true,
1080 true);
1081 }
1082
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;
1090
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.};
1097
1098 Configuration configuration;
1099};
1100
1101} // namespace Private
1102} // namespace Simulators
1103
1104#endif
1105
1106#endif
1107
1108#endif // !_AER_STATE_H_
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)
int IsQcsim(void *sim)
int SaveState(void *sim)
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
Definition Types.h:22
uint_fast64_t qubit_t
The type of a qubit.
Definition Types.h:21