Maestro 0.3.11
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{
26
27class AerStateFake
28{
29 public:
30 virtual ~AerStateFake() = default;
31
32 bool initialized_;
33 uint_t num_of_qubits_;
34 RngEngine rng_;
35 int seed_ = std::random_device()();
36 std::shared_ptr<QuantumState::Base> state_;
37 json_t configs_;
38 ExperimentResult last_result_;
39};
40
41} // namespace AER
42
43namespace Simulators
44{
45// TODO: Maybe use the pimpl idiom
46// https://en.cppreference.com/w/cpp/language/pimpl to hide the implementation
47// for good but during development this should be good enough
48namespace Private
49{
50
59class QiskitAerState : public AER::AerState
60{
61 public:
62 const std::shared_ptr<AER::QuantumState::Base> &get_state() const
63 {
64 const AER::AerStateFake *fakeState = (AER::AerStateFake *)(void *)this;
65 return fakeState->state_;
66 }
67
68 // AerState's buffer export extracts double-precision result storage even
69 // when the actual state stores floats. Convert the concrete float state
70 // before clearing it so saved states and clones retain their amplitudes.
71 AER::Vector<complex_t> move_to_vector() override
72 {
73 flush_ops();
74 const auto single = std::dynamic_pointer_cast<AER::Statevector::State<AER::QV::QubitVector<float>>>(get_state());
75 if (!single)
76 return AER::AerState::move_to_vector();
77 auto values = single->move_to_vector();
78 AER::Vector<complex_t> result(values.size(), false);
79 for (size_t i = 0; i < values.size(); ++i)
80 result[i] = values[i];
81 clear();
82 return result;
83 }
84
85 AER::cmatrix_t move_to_matrix() override
86 {
87 flush_ops();
88 const auto single = std::dynamic_pointer_cast<AER::DensityMatrix::State<AER::QV::DensityMatrix<float>>>(get_state());
89 if (!single)
90 return AER::AerState::move_to_matrix();
91 auto values = single->move_to_matrix();
92 AER::cmatrix_t result(values.GetRows(), values.GetColumns());
93 for (size_t i = 0; i < values.GetRows() * values.GetColumns(); ++i)
94 result.data()[i] = values.data()[i];
95 clear();
96 return result;
97 }
98
99 double expval_pauli(const reg_t &qubits, const std::string &pauli)
100 {
101 if (qubits.empty() || pauli.empty())
102 return 1.;
103
104 const auto &state = get_state();
105 if (!state)
106 return 0.;
107
108 flush_ops();
109
110 return state->expval_pauli(qubits, pauli);
111 }
112
113 AER::Vector<complex_t> statevector()
114 {
115 const auto &state = get_state();
116 if (!state)
117 return {};
118
119 flush_ops();
120
121 AER::Operations::Op op;
122 op.type = AER::Operations::OpType::save_statevec;
123 op.name = "save_statevector";
124 op.save_type = AER::Operations::DataSubType::single;
125 op.string_params.push_back("statevector");
126 for (uint_t qubit = 0; qubit < num_of_qubits(); ++qubit)
127 op.qubits.push_back(qubit);
128
129 AER::AerStateFake *fakeState = (AER::AerStateFake *)(void *)this;
130 fakeState->last_result_ = AER::ExperimentResult();
131 state->apply_op(op, fakeState->last_result_, fakeState->rng_);
132
133 return std::move(
134 static_cast<AER::DataMap<AER::SingleData, AER::Vector<complex_t>>>(std::move(fakeState->last_result_.data)).value()["statevector"].value());
135 }
136
137 std::shared_ptr<AER::QuantumState::Base> clone_extended_stabilizer_state()
138 {
139 flush_ops();
140 const auto extendedState = std::dynamic_pointer_cast<AER::ExtendedStabilizer::State>(get_state());
141 if (!extendedState)
142 throw std::runtime_error("QiskitAerState: current state is not an extended stabilizer state");
143 return std::make_shared<AER::ExtendedStabilizer::State>(*extendedState);
144 }
145
146 void restore_extended_stabilizer_state(const std::shared_ptr<AER::QuantumState::Base> &savedState)
147 {
148 const auto extendedState = std::dynamic_pointer_cast<AER::ExtendedStabilizer::State>(savedState);
149 if (!extendedState)
150 throw std::runtime_error("QiskitAerState: saved state is not an extended stabilizer state");
151
152 AER::AerStateFake *fakeState = (AER::AerStateFake *)(void *)this;
153 fakeState->state_ = std::make_shared<AER::ExtendedStabilizer::State>(*extendedState);
154 fakeState->num_of_qubits_ = extendedState->qreg().get_n_qubits();
155 fakeState->initialized_ = true;
156 fakeState->last_result_ = AER::ExperimentResult();
157 clear_ops();
158 }
159
160 std::vector<bool> apply_measure_many(const reg_t &qubits)
161 {
162 const auto &state = get_state();
163 if (!state)
164 return {};
165
166 flush_ops();
167
168 AER::Operations::Op op;
169 op.type = AER::Operations::OpType::measure;
170 op.name = "measure";
171 op.qubits = qubits;
172 op.memory = qubits;
173 op.registers = qubits;
174
175 AER::AerStateFake *fakeState = (AER::AerStateFake *)(void *)this;
176 fakeState->last_result_ = AER::ExperimentResult();
177 state->apply_op(op, fakeState->last_result_, fakeState->rng_);
178
179 std::vector<bool> bitstring(qubits.size(), false);
180 uint_t mem_size = state->creg().memory_size();
181 for (size_t q = 0; q < qubits.size(); ++q)
182 {
183 const auto qubit = qubits[q];
184 if (state->creg().creg_memory()[mem_size - qubit - 1] == '1')
185 bitstring[q] = true;
186 }
187 return bitstring;
188 }
189
190 std::unordered_map<std::vector<bool>, uint_t> sample_counts_many(const reg_t &qubits, uint_t shots)
191 {
192 const auto &state = get_state();
193 if (!state)
194 return {};
195
196 flush_ops();
197
198 AER::AerStateFake *fakeState = (AER::AerStateFake *)(void *)this;
199
200 // Aer's MPS backend returns samples sorted by ascending qubit index
201 // regardless of the order of `qubits` (see sort_measured_values in
202 // matrix_product_state_internal.cpp), while the statevector backend
203 // returns them in the order of `qubits`. To get consistent behavior
204 // across backends we sort the qubits ourselves and then remap the
205 // bits back to the caller-requested order.
206 reg_t sorted_qubits = qubits;
207 std::vector<size_t> order(qubits.size());
208 std::iota(order.begin(), order.end(), 0);
209 std::sort(order.begin(), order.end(), [&qubits](size_t a, size_t b) { return qubits[a] < qubits[b]; });
210 for (size_t i = 0; i < qubits.size(); ++i)
211 sorted_qubits[i] = qubits[order[i]];
212
213 std::vector<AER::SampleVector> samples = state->sample_measure(sorted_qubits, shots, fakeState->rng_);
214 std::unordered_map<std::vector<bool>, uint_t> ret;
215
216 std::vector<bool> bitstring(qubits.size());
217 for (const auto &sample : samples)
218 {
219 for (size_t i = 0; i < qubits.size(); ++i)
220 bitstring[order[i]] = sample[i] == 1;
221
222 ++ret[bitstring];
223 }
224 return ret;
225 }
226};
227
228} // namespace Private
229} // namespace Simulators
230
231#endif
232#endif
233#endif
Bounded online routing based on current physical bond dimensions.