Maestro 0.3.1
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
QiskitAerState.h
Go to the documentation of this file.
1
12
13#pragma once
14
15#ifndef _QISKIT_AER_STATE_H_
16#define _QISKIT_AER_STATE_H_
17
18#ifndef NO_QISKIT_AER
19
20#ifdef INCLUDED_BY_FACTORY
21
22#include "controllers/state_controller.hpp"
23
24namespace AER {
25
26class AerStateFake {
27 public:
28 virtual ~AerStateFake() = default;
29
30 bool initialized_;
31 uint_t num_of_qubits_;
32 RngEngine rng_;
33 int seed_ = std::random_device()();
34 std::shared_ptr<QuantumState::Base> state_;
35 json_t configs_;
36 ExperimentResult last_result_;
37};
38
39} // namespace AER
40
41namespace Simulators {
42// TODO: Maybe use the pimpl idiom
43// https://en.cppreference.com/w/cpp/language/pimpl to hide the implementation
44// for good but during development this should be good enough
45namespace Private {
46
55class QiskitAerState : public AER::AerState {
56 public:
57 const std::shared_ptr<AER::QuantumState::Base> &get_state() const {
58 const AER::AerStateFake *fakeState = (AER::AerStateFake *)(void *)this;
59 return fakeState->state_;
60 }
61
62 double expval_pauli(const reg_t &qubits, const std::string &pauli) {
63 if (qubits.empty() || pauli.empty()) return 1.;
64
65 const auto &state = get_state();
66 if (!state) return 0.;
67
68 flush_ops();
69
70 return state->expval_pauli(qubits, pauli);
71 }
72
73 AER::Vector<complex_t> statevector() {
74 const auto &state = get_state();
75 if (!state) return {};
76
77 flush_ops();
78
79 AER::Operations::Op op;
80 op.type = AER::Operations::OpType::save_statevec;
81 op.name = "save_statevector";
82 op.save_type = AER::Operations::DataSubType::single;
83 op.string_params.push_back("statevector");
84 for (uint_t qubit = 0; qubit < num_of_qubits(); ++qubit)
85 op.qubits.push_back(qubit);
86
87 AER::AerStateFake *fakeState = (AER::AerStateFake *)(void *)this;
88 fakeState->last_result_ = AER::ExperimentResult();
89 state->apply_op(op, fakeState->last_result_, fakeState->rng_);
90
91 return std::move(
92 static_cast<AER::DataMap<AER::SingleData, AER::Vector<complex_t>>>(
93 std::move(fakeState->last_result_.data))
94 .value()["statevector"]
95 .value());
96 }
97
98 std::shared_ptr<AER::QuantumState::Base> clone_extended_stabilizer_state() {
99 flush_ops();
100 const auto extendedState =
101 std::dynamic_pointer_cast<AER::ExtendedStabilizer::State>(get_state());
102 if (!extendedState)
103 throw std::runtime_error(
104 "QiskitAerState: current state is not an extended stabilizer state");
105 return std::make_shared<AER::ExtendedStabilizer::State>(*extendedState);
106 }
107
108 void restore_extended_stabilizer_state(
109 const std::shared_ptr<AER::QuantumState::Base> &savedState) {
110 const auto extendedState =
111 std::dynamic_pointer_cast<AER::ExtendedStabilizer::State>(savedState);
112 if (!extendedState)
113 throw std::runtime_error(
114 "QiskitAerState: saved state is not an extended stabilizer state");
115
116 AER::AerStateFake *fakeState = (AER::AerStateFake *)(void *)this;
117 fakeState->state_ =
118 std::make_shared<AER::ExtendedStabilizer::State>(*extendedState);
119 fakeState->num_of_qubits_ = extendedState->qreg().get_n_qubits();
120 fakeState->initialized_ = true;
121 fakeState->last_result_ = AER::ExperimentResult();
122 clear_ops();
123 }
124
125 std::vector<bool> apply_measure_many(const reg_t &qubits) {
126 const auto &state = get_state();
127 if (!state) return {};
128
129 flush_ops();
130
131 AER::Operations::Op op;
132 op.type = AER::Operations::OpType::measure;
133 op.name = "measure";
134 op.qubits = qubits;
135 op.memory = qubits;
136 op.registers = qubits;
137
138 AER::AerStateFake *fakeState = (AER::AerStateFake *)(void *)this;
139 fakeState->last_result_ = AER::ExperimentResult();
140 state->apply_op(op, fakeState->last_result_, fakeState->rng_);
141
142 std::vector<bool> bitstring(qubits.size(), false);
143 uint_t mem_size = state->creg().memory_size();
144 for (size_t q = 0; q < qubits.size(); ++q) {
145 const auto qubit = qubits[q];
146 if (state->creg().creg_memory()[mem_size - qubit - 1] == '1')
147 bitstring[q] = true;
148 }
149 return bitstring;
150 }
151
152 std::unordered_map<std::vector<bool>, uint_t> sample_counts_many(
153 const reg_t &qubits, uint_t shots) {
154 const auto &state = get_state();
155 if (!state) return {};
156
157 flush_ops();
158
159 AER::AerStateFake *fakeState = (AER::AerStateFake *)(void *)this;
160
161 // Aer's MPS backend returns samples sorted by ascending qubit index
162 // regardless of the order of `qubits` (see sort_measured_values in
163 // matrix_product_state_internal.cpp), while the statevector backend
164 // returns them in the order of `qubits`. To get consistent behavior
165 // across backends we sort the qubits ourselves and then remap the
166 // bits back to the caller-requested order.
167 reg_t sorted_qubits = qubits;
168 std::vector<size_t> order(qubits.size());
169 std::iota(order.begin(), order.end(), 0);
170 std::sort(order.begin(), order.end(),
171 [&qubits](size_t a, size_t b) { return qubits[a] < qubits[b]; });
172 for (size_t i = 0; i < qubits.size(); ++i)
173 sorted_qubits[i] = qubits[order[i]];
174
175 std::vector<AER::SampleVector> samples =
176 state->sample_measure(sorted_qubits, shots, fakeState->rng_);
177 std::unordered_map<std::vector<bool>, uint_t> ret;
178
179 std::vector<bool> bitstring(qubits.size());
180 for (const auto &sample : samples) {
181 for (size_t i = 0; i < qubits.size(); ++i)
182 bitstring[order[i]] = sample[i] == 1;
183
184 ++ret[bitstring];
185 }
186 return ret;
187 }
188};
189
190} // namespace Private
191} // namespace Simulators
192
193#endif
194#endif
195#endif