Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
GpuDensityMatrix.h
Go to the documentation of this file.
1
4#pragma once
5
6#ifndef _GPU_DENSITY_MATRIX_H_
7#define _GPU_DENSITY_MATRIX_H_
8
9#ifdef __linux__
10
11#include <complex>
12#include <memory>
13#include <stdexcept>
14#include <string>
15#include <utility>
16#include <vector>
17
18#include "GpuDeviceContext.h"
19
20namespace Simulators
21{
22
23class GpuDensityMatrix
24{
25 public:
26 explicit GpuDensityMatrix(const std::shared_ptr<GpuLibrary> &lib, int device = -1) : lib(lib), obj(nullptr)
27 {
28 if (lib)
29 {
30 auto lock = lib->LockInitialization();
31 if (lib->SetGpuDevice(device == -1 ? lib->GetCreationDevice() : device))
32 obj = lib->CreateDensityMatrix();
33 }
34 }
35
36 int GetGpuDevice() const
37 {
38 return lib ? lib->DMGetGpuId(obj) : -1;
39 }
40
41 GpuDensityMatrix(const std::shared_ptr<GpuLibrary> &lib, void *obj) : lib(lib), obj(obj)
42 {
43 }
44
45 GpuDensityMatrix() = delete;
46 GpuDensityMatrix(const GpuDensityMatrix &) = delete;
47 GpuDensityMatrix &operator=(const GpuDensityMatrix &) = delete;
48
49 ~GpuDensityMatrix()
50 {
51 if (lib && obj)
52 lib->DestroyDensityMatrix(obj);
53 }
54
55 bool Create(unsigned int n)
56 {
57 return lib->DMCreate(obj, n);
58 }
59
60 bool CreateWithState(unsigned int n, const double *state)
61 {
62 return lib->DMCreateWithState(obj, n, state);
63 }
64
65 bool CreateWithBasisState(unsigned int n, unsigned long long state)
66 {
67 return lib->DMCreateWithBasisState(obj, n, state);
68 }
69
70 bool CreateWithMixtureOfBasisStates(unsigned int n, const std::vector<std::pair<unsigned long long, double>> &mixture)
71 {
72 std::vector<unsigned long long> states;
73 std::vector<double> weights;
74 states.reserve(mixture.size());
75 weights.reserve(mixture.size());
76 for (const auto &[state, weight] : mixture)
77 {
78 states.push_back(state);
79 weights.push_back(weight);
80 }
81 return lib->DMCreateWithMixtureOfBasisStates(obj, n, states.data(), weights.data(), static_cast<int>(states.size()));
82 }
83
84 bool Synchronize()
85 {
86 return lib->DMSynchronize(obj);
87 }
88
89 void Reset()
90 {
91 if (!lib->DMReset(obj))
92 throw std::runtime_error("GPU density-matrix reset failed");
93 }
94
95 bool SetSeed(uint64_t seed)
96 {
97 return lib->DMSetSeed(obj, seed);
98 }
99
100 bool IsCreated() const
101 {
102 return lib->DMIsCreated(obj);
103 }
104
105 bool IsDoublePrecision() const
106 {
107 return lib->DMIsDoublePrecision(obj);
108 }
109
110 void SetDataType(bool useDouble)
111 {
112 if (!lib->DMSetDataType(obj, useDouble))
113 throw std::runtime_error("GPU density-matrix precision configuration failed");
114 }
115
116 bool Measure(unsigned int q)
117 {
118 return lib->DMMeasureQubitCollapse(obj, q);
119 }
120
121 bool MeasureNoCollapse(unsigned int q)
122 {
123 return lib->DMMeasureQubitNoCollapse(obj, q);
124 }
125
126 bool MeasureQubits(std::vector<int> &qubits, std::vector<int> &bits, bool collapse = true)
127 {
128 if (qubits.size() != bits.size())
129 throw std::invalid_argument("Measurement vectors must have equal size");
130 return collapse ? lib->DMMeasureQubitsCollapse(obj, qubits.data(), bits.data(), static_cast<int>(bits.size()))
131 : lib->DMMeasureQubitsNoCollapse(obj, qubits.data(), bits.data(), static_cast<int>(bits.size()));
132 }
133
134 unsigned long long MeasureAll(bool collapse = true)
135 {
136 return collapse ? lib->DMMeasureAllQubitsCollapse(obj) : lib->DMMeasureAllQubitsNoCollapse(obj);
137 }
138
139 bool Sample(unsigned int n, long int *samples, unsigned int nBits, int *order)
140 {
141 return lib->DMSample(obj, n, samples, nBits, order);
142 }
143
144 bool SampleAll(unsigned int shots, long int *samples)
145 {
146 return lib->DMSampleAll(obj, shots, samples);
147 }
148
149 double Probability(long long outcome) const
150 {
151 return lib->DMBasisStateProbability(obj, outcome);
152 }
153
154 std::complex<double> GetElement(long long row, long long col) const
155 {
156 double re = 0., im = 0.;
157 if (!lib->DMGetElement(obj, row, col, &re, &im))
158 throw std::runtime_error("GPU density-matrix element query failed");
159 return {re, im};
160 }
161
162 void AllProbabilities(double *probabilities)
163 {
164 if (!lib->DMAllProbabilities(obj, probabilities))
165 throw std::runtime_error("GPU density-matrix probability enumeration failed");
166 }
167
168 double ExpectationValue(const std::string &pauli) const
169 {
170 return lib->DMExpectationValue(obj, pauli.c_str(), pauli.size());
171 }
172
173 double QubitProbability0(unsigned int q) const
174 {
175 return lib->DMQubitProbability0(obj, q);
176 }
177
178 double Trace() const
179 {
180 return lib->DMTrace(obj);
181 }
182
183 double Purity() const
184 {
185 return lib->DMPurity(obj);
186 }
187
188 bool IsHermitian(double eps = 1e-10) const
189 {
190 return lib->DMIsHermitian(obj, eps);
191 }
192
193 std::vector<std::complex<double>> PartialTrace(const std::vector<int> &qubits) const
194 {
195 const size_t dim = size_t{1} << qubits.size();
196 std::vector<double> raw(2 * dim * dim);
197 if (!lib->DMPartialTrace(obj, qubits.data(), static_cast<int>(qubits.size()), raw.data()))
198 throw std::runtime_error("GPU density-matrix partial trace failed");
199 std::vector<std::complex<double>> result(dim * dim);
200 for (size_t i = 0; i < result.size(); ++i)
201 result[i] = {raw[2 * i], raw[2 * i + 1]};
202 return result;
203 }
204
205 std::complex<double> HilbertSchmidtOverlap(const GpuDensityMatrix &other) const
206 {
207 double re = 0., im = 0.;
208 if (!lib->DMHilbertSchmidtOverlap(obj, other.obj, &re, &im))
209 throw std::runtime_error("GPU density-matrix overlap failed");
210 return {re, im};
211 }
212
213 double FidelityWithStatevector(const double *state) const
214 {
215 double result = 0.;
216 if (!lib->DMFidelityWithStatevector(obj, state, &result))
217 throw std::runtime_error("GPU density-matrix fidelity failed");
218 return result;
219 }
220
221 void SaveState()
222 {
223 if (!lib->DMSaveState(obj))
224 throw std::runtime_error("GPU density-matrix state save failed");
225 }
226
227 void RestoreState()
228 {
229 if (!lib->DMRestoreState(obj))
230 throw std::runtime_error("GPU density-matrix state restore failed");
231 }
232
233 void CleanSavedState()
234 {
235 if (!lib->DMCleanSavedState(obj))
236 throw std::runtime_error("GPU density-matrix saved-state cleanup failed");
237 }
238
239 std::unique_ptr<GpuDensityMatrix> Clone() const
240 {
241 void *cloned = lib->DMClone(obj);
242 if (!cloned)
243 return nullptr;
244 return std::make_unique<GpuDensityMatrix>(lib, cloned);
245 }
246
247 bool ApplyKraus(const std::vector<int> &qubits, int count, const double *operators)
248 {
249 return lib->DMApplyKraus(obj, qubits.size(), qubits.data(), count, operators);
250 }
251
252#define GPU_DM_CHECK(call, name) \
253 do \
254 { \
255 if (!(call)) \
256 throw std::runtime_error("GPU density-matrix " name " failed"); \
257 } while (false)
258#define GPU_DM_GATE1(name) \
259 void name(int q) \
260 { \
261 GPU_DM_CHECK(lib->DM##name(obj, q), #name); \
262 }
263#define GPU_DM_GATE2(name) \
264 void name(int a, int b) \
265 { \
266 GPU_DM_CHECK(lib->DM##name(obj, a, b), #name); \
267 }
268#define GPU_DM_ROT1(name) \
269 void name(int q, double x) \
270 { \
271 GPU_DM_CHECK(lib->DM##name(obj, q, x), #name); \
272 }
273#define GPU_DM_ROT2(name) \
274 void name(int a, int b, double x) \
275 { \
276 GPU_DM_CHECK(lib->DM##name(obj, a, b, x), #name); \
277 }
278 GPU_DM_GATE1(ApplyReset)
279
280 GPU_DM_ROT1(ApplyBitFlipNoise)
281
282 GPU_DM_ROT1(ApplyPhaseFlipNoise)
283
284 GPU_DM_ROT1(ApplyDepolarizingNoise)
285
286 GPU_DM_ROT1(ApplyAmplitudeDamping)
287
288 GPU_DM_ROT1(ApplyPhaseDamping)
289
290 GPU_DM_GATE1(ApplyNonSelectiveMeasurement)
291
292 GPU_DM_GATE1(ApplyX)
293
294 GPU_DM_GATE1(ApplyY)
295
296 GPU_DM_GATE1(ApplyZ)
297
298 GPU_DM_GATE1(ApplyH)
299
300 GPU_DM_GATE1(ApplyS)
301
302 GPU_DM_GATE1(ApplySDG)
303
304 GPU_DM_GATE1(ApplyT)
305
306 GPU_DM_GATE1(ApplyTDG)
307
308 GPU_DM_GATE1(ApplySX)
309
310 GPU_DM_GATE1(ApplySXDG)
311
312 GPU_DM_GATE1(ApplyK)
313
314 GPU_DM_ROT1(ApplyP) GPU_DM_ROT1(ApplyRx) GPU_DM_ROT1(ApplyRy) GPU_DM_ROT1(ApplyRz) void ApplyU(int q, double a, double b, double c, double d)
315 {
316 GPU_DM_CHECK(lib->DMApplyU(obj, q, a, b, c, d), "ApplyU");
317 }
318
319 GPU_DM_GATE2(ApplyCX)
320
321 GPU_DM_GATE2(ApplyCY)
322
323 GPU_DM_GATE2(ApplyCZ)
324
325 GPU_DM_GATE2(ApplyCH)
326
327 GPU_DM_GATE2(ApplyCSX)
328
329 GPU_DM_GATE2(ApplyCSXDG) GPU_DM_ROT2(ApplyCP) GPU_DM_ROT2(ApplyCRx) GPU_DM_ROT2(ApplyCRy) GPU_DM_ROT2(ApplyCRz) void ApplyCCX(int a, int b, int c)
330 {
331 GPU_DM_CHECK(lib->DMApplyCCX(obj, a, b, c), "ApplyCCX");
332 }
333 GPU_DM_GATE2(ApplySwap)
334
335 void ApplyCSwap(int a, int b, int c)
336 {
337 GPU_DM_CHECK(lib->DMApplyCSwap(obj, a, b, c), "ApplyCSwap");
338 }
339
340 void ApplyCU(int a, int b, double c, double d, double e, double f)
341 {
342 GPU_DM_CHECK(lib->DMApplyCU(obj, a, b, c, d, e, f), "ApplyCU");
343 }
344
345#undef GPU_DM_ROT2
346#undef GPU_DM_ROT1
347#undef GPU_DM_GATE2
348#undef GPU_DM_GATE1
349#undef GPU_DM_CHECK
350
351 private:
352 GpuDeviceContext lib;
353 void *obj = nullptr;
354};
355
356} // namespace Simulators
357#endif
358#endif
int ApplyK(void *sim, int qubit)
double Probability(void *sim, unsigned long long int outcome)
int RestoreState(void *sim)
int ApplyRx(void *sim, int qubit, double theta)
int ApplyReset(void *sim, const unsigned long int *qubits, unsigned long int nrQubits)
int ApplyX(void *sim, int qubit)
int ApplyU(void *sim, int qubit, double theta, double phi, double lambda, double gamma)
int ApplyCRy(void *sim, int controlQubit, int targetQubit, double theta)
int ApplyTDG(void *sim, int qubit)
int ApplyCSXDG(void *sim, int controlQubit, int targetQubit)
int ApplyS(void *sim, int qubit)
int ApplyCX(void *sim, int controlQubit, int targetQubit)
int ApplyCRz(void *sim, int controlQubit, int targetQubit, double theta)
double * AllProbabilities(void *sim)
unsigned long long int MeasureNoCollapse(void *sim)
int ApplyCP(void *sim, int controlQubit, int targetQubit, double theta)
int ApplySXDG(void *sim, int qubit)
int ApplySDG(void *sim, int qubit)
unsigned long long int Measure(void *sim, const unsigned long int *qubits, unsigned long int nrQubits)
int ApplyCSwap(void *sim, int controlQubit, int qubit1, int qubit2)
int ApplyCCX(void *sim, int controlQubit1, int controlQubit2, int targetQubit)
int ApplyY(void *sim, int qubit)
int ApplyZ(void *sim, int qubit)
int ApplyH(void *sim, int qubit)
int ApplyCY(void *sim, int controlQubit, int targetQubit)
int ApplyCU(void *sim, int controlQubit, int targetQubit, double theta, double phi, double lambda, double gamma)
int ApplySwap(void *sim, int qubit1, int qubit2)
int ApplyRy(void *sim, int qubit, double theta)
int ApplyP(void *sim, int qubit, double theta)
int ApplyCH(void *sim, int controlQubit, int targetQubit)
int ApplySX(void *sim, int qubit)
int ApplyCZ(void *sim, int controlQubit, int targetQubit)
int ApplyRz(void *sim, int qubit, double theta)
int ApplyT(void *sim, int qubit)
int ApplyCRx(void *sim, int controlQubit, int targetQubit, double theta)
int ApplyCSX(void *sim, int controlQubit, int targetQubit)
int SaveState(void *sim)
Bounded online routing based on current physical bond dimensions.