Maestro 0.3.1
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
GpuMPO.h
Go to the documentation of this file.
1
4#pragma once
5
6#ifndef _GPU_MPO_H_
7#define _GPU_MPO_H_
8
9#ifdef __linux__
10
11#include <memory>
12#include <complex>
13#include <stdexcept>
14#include <string>
15#include <utility>
16#include <vector>
17
18#include "GpuDeviceContext.h"
19
20namespace Simulators {
21
22class GpuMPO {
23 public:
24 explicit GpuMPO(const std::shared_ptr<GpuLibrary>& lib, int device = -1)
25 : lib(lib), obj(nullptr) {
26 if (lib) {
27 auto lock = lib->LockInitialization();
28 if (lib->SetGpuDevice(device == -1 ? lib->GetCreationDevice() : device))
29 obj = lib->CreateMPO();
30 }
31 }
32
33 int GetGpuDevice() const { return lib ? lib->MPOGetGpuId(obj) : -1; }
34
35 GpuMPO(const std::shared_ptr<GpuLibrary>& lib, void* obj)
36 : lib(lib), obj(obj) {}
37 GpuMPO() = delete;
38 GpuMPO(const GpuMPO&) = delete;
39 GpuMPO& operator=(const GpuMPO&) = delete;
40 ~GpuMPO() { if (lib && obj) lib->DestroyMPO(obj); }
41
42 bool Create(unsigned int n) { return lib->MPOCreate(obj, n); }
43 bool CreateWithState(unsigned int n, const double* state) {
44 return lib->MPOCreateWithState(obj, n, state);
45 }
46 bool CreateWithBasisState(unsigned int n, unsigned long long state) {
47 return lib->MPOCreateWithBasisState(obj, n, state);
48 }
49 bool CreateWithBasisStateBits(unsigned int n,
50 const std::vector<unsigned char>& stateBits) {
51 return lib->MPOCreateWithBasisStateBits(obj, n, stateBits.data());
52 }
53 bool CreateWithMixtureOfBasisStates(
54 unsigned int n,
55 const std::vector<std::pair<unsigned long long, double>>& mixture) {
56 std::vector<unsigned long long> states;
57 std::vector<double> weights;
58 states.reserve(mixture.size());
59 weights.reserve(mixture.size());
60 for (const auto& [state, weight] : mixture) {
61 states.push_back(state);
62 weights.push_back(weight);
63 }
64 return lib->MPOCreateWithMixtureOfBasisStates(
65 obj, n, states.data(), weights.data(),
66 static_cast<int>(states.size()));
67 }
68 bool CreateWithMixtureOfBasisStatesBits(
69 unsigned int n, const std::vector<unsigned char>& stateBitsFlat,
70 const std::vector<double>& weights) {
71 return lib->MPOCreateWithMixtureOfBasisStatesBits(
72 obj, n, stateBitsFlat.data(), weights.data(),
73 static_cast<int>(weights.size()));
74 }
75 void Reset() {
76 if (!lib->MPOReset(obj))
77 throw std::runtime_error("GPU matrix-product-operator reset failed");
78 }
79 bool SetSeed(uint64_t seed) { return lib->MPOSetSeed(obj, seed); }
80 bool SetInitialQubitsMap(const std::vector<long long int>& initialMap) {
81 return lib->MPOSetInitialQubitsMap(obj, initialMap);
82 }
83 bool SetUseOptimalMeetingPosition(bool useOptimalMeetingPosition) {
84 return lib->MPOSetUseOptimalMeetingPosition(obj, useOptimalMeetingPosition);
85 }
86 bool GetUseOptimalMeetingPosition() const {
87 return lib->MPOGetUseOptimalMeetingPosition(obj);
88 }
89 bool SetCallbackContext(void* context) {
90 return lib->MPOSetCallbackContext(obj, context);
91 }
92 bool SetMeetingPositionCallback(
93 int64_t (*callback)(void*, const int64_t*)) {
94 return lib->MPOSetMeetingPositionCallback(obj, callback);
95 }
96 bool SetBondDimensionsCallback(void (*callback)(void*, const int64_t*)) {
97 return lib->MPOSetBondDimensionsCallback(obj, callback);
98 }
99 bool IsCreated() const { return lib->MPOIsCreated(obj); }
100 void SetDataType(bool useDouble) {
101 if (!lib->MPOSetDataType(obj, useDouble))
102 throw std::runtime_error(
103 "GPU matrix-product-operator precision configuration failed");
104 }
105 void SetCutoff(double singularValueThreshold) {
106 lib->MPOSetCutoff(obj, singularValueThreshold);
107 }
108 double GetCutoff() const { return lib->MPOGetCutoff(obj); }
109 // mode: 0 = RelativeToMax, 1 = DiscardedWeight (default). See
110 // TruncationMode in the GPU library's lib/truncationmode.hpp.
111 bool SetTruncationMode(int mode) {
112 return lib->MPOSetTruncationMode(obj, mode);
113 }
114 int GetTruncationMode() const { return lib->MPOGetTruncationMode(obj); }
115 bool SetGesvdJ(bool enable) { return lib->MPOSetGesvdJ(obj, enable); }
116 bool GetGesvdJ() const { return lib->MPOGetGesvdJ(obj); }
117 // Enabling any of J/P/R clears the other two selectors in the plugin.
118 bool SetGesvdP(bool enable) {
119 return obj && lib->MPOSetGesvdP(obj, enable);
120 }
121 bool GetGesvdP() const { return lib->MPOGetGesvdP(obj); }
122 bool SetGesvdR(bool enable) {
123 return obj && lib->MPOSetGesvdR(obj, enable);
124 }
125 bool GetGesvdR() const { return lib->MPOGetGesvdR(obj); }
126 int GetLastSvdAlgo() const { return lib->MPOGetLastSvdAlgo(obj); }
127
128 void SetMaxExtent(long int chi) { lib->MPOSetMaxExtent(obj, chi); }
129 long int GetMaxExtent() const { return lib->MPOGetMaxExtent(obj); }
130 std::vector<long long int> GetBondDimensions(size_t nrQubits) const {
131 if (nrQubits < 2) return {};
132 std::vector<long long int> bondDims(nrQubits - 1);
133 if (!lib->MPOGetBondDimensions(obj, bondDims.data())) return {};
134 return bondDims;
135 }
136 void ReCanonicalize(int centerSite = 0) {
137 if (!lib->MPOReCanonicalize(obj, centerSite)) throw std::runtime_error("GPU MPO canonicalization failed");
138 }
139 void Trim(double cutoff = -1., long int maxExtent = -1, int centerSite = 0) {
140 if (!lib->MPOTrim(obj, cutoff, maxExtent, centerSite)) throw std::runtime_error("GPU MPO trim failed");
141 }
142 bool Measure(unsigned int q) { return lib->MPOMeasureQubitCollapse(obj, q); }
143 bool MeasureNoCollapse(unsigned int q) { return lib->MPOMeasureQubitNoCollapse(obj, q); }
144 bool MeasureQubits(std::vector<int>& qubits, std::vector<int>& bits, bool collapse = true) {
145 if (qubits.size() != bits.size()) throw std::invalid_argument("Measurement vectors must have equal size");
146 return collapse ? lib->MPOMeasureQubitsCollapse(obj, qubits.data(), bits.data(), static_cast<int>(bits.size()))
147 : lib->MPOMeasureQubitsNoCollapse(obj, qubits.data(), bits.data(), static_cast<int>(bits.size()));
148 }
149 unsigned long long MeasureAll(bool collapse = true) { return collapse ? lib->MPOMeasureAllQubitsCollapse(obj) : lib->MPOMeasureAllQubitsNoCollapse(obj); }
150 bool Sample(unsigned int nSamples, long int* samples, unsigned int nBits,
151 int* bitOrdering) {
152 return lib->MPOSample(obj, nSamples, samples, nBits, bitOrdering);
153 }
154 bool SampleAll(unsigned int shots, long int* samples) {
155 return lib->MPOSampleAll(obj, shots, samples);
156 }
157 double Probability(long long outcome) const {
158 return lib->MPOBasisStateProbability(obj, outcome);
159 }
160 std::complex<double> GetElement(long long row, long long col) const {
161 double re = 0., im = 0.;
162 if (!lib->MPOGetElement(obj, row, col, &re, &im)) throw std::runtime_error("GPU MPO element query failed");
163 return {re, im};
164 }
165 void AllProbabilities(double* probabilities) {
166 if (!lib->MPOAllProbabilities(obj, probabilities))
167 throw std::runtime_error(
168 "GPU matrix-product-operator probability enumeration failed");
169 }
170 double ExpectationValue(const std::string& pauli) const {
171 return lib->MPOExpectationValue(obj, pauli.c_str(), pauli.size());
172 }
173 double QubitProbability0(unsigned int q) const { return lib->MPOQubitProbability0(obj, q); }
174 double Trace() const { return lib->MPOTrace(obj); }
175 double Purity() const { return lib->MPOPurity(obj); }
176 double HermiticityResidual() const { return lib->MPOHermiticityResidual(obj); }
177 bool IsHermitian(double eps = 1e-10) const { return lib->MPOIsHermitian(obj, eps); }
178 double TraceOfSquare() const { return lib->MPOTraceOfSquare(obj); }
179 void RestoreTrace() { if (!lib->MPORestoreTrace(obj)) throw std::runtime_error("GPU MPO trace restoration failed"); }
180 void Hermitize() { if (!lib->MPOHermitize(obj)) throw std::runtime_error("GPU MPO hermitization failed"); }
181 bool SetKrausCompletenessCheck(int mode) { return lib->MPOSetKrausCompletenessCheck(obj, mode); }
182 int GetKrausCompletenessCheck() const { return lib->MPOGetKrausCompletenessCheck(obj); }
183 std::vector<std::complex<double>> PartialTrace(const std::vector<int>& qubits) const {
184 const size_t dim = size_t{1} << qubits.size();
185 std::vector<double> raw(2 * dim * dim);
186 if (!lib->MPOPartialTrace(obj, qubits.data(), static_cast<int>(qubits.size()), raw.data())) throw std::runtime_error("GPU MPO partial trace failed");
187 std::vector<std::complex<double>> result(dim * dim);
188 for (size_t i = 0; i < result.size(); ++i) result[i] = {raw[2*i], raw[2*i+1]};
189 return result;
190 }
191 std::complex<double> HilbertSchmidtOverlap(const GpuMPO& other) const {
192 double re = 0., im = 0.;
193 if (!lib->MPOHilbertSchmidtOverlap(obj, other.obj, &re, &im)) throw std::runtime_error("GPU MPO overlap failed");
194 return {re, im};
195 }
196 double FidelityWithStatevector(const double* state) const {
197 double result = 0.;
198 if (!lib->MPOFidelityWithStatevector(obj, state, &result)) throw std::runtime_error("GPU MPO fidelity failed");
199 return result;
200 }
201 void SaveState() {
202 if (!lib->MPOSaveState(obj))
203 throw std::runtime_error("GPU matrix-product-operator state save failed");
204 }
205 void RestoreState() {
206 if (!lib->MPORestoreState(obj))
207 throw std::runtime_error(
208 "GPU matrix-product-operator state restore failed");
209 }
210 void CleanSavedState() {
211 if (!lib->MPOCleanSavedState(obj))
212 throw std::runtime_error(
213 "GPU matrix-product-operator saved-state cleanup failed");
214 }
215 std::unique_ptr<GpuMPO> Clone() const {
216 void* cloned = lib->MPOClone(obj);
217 if (!cloned) return nullptr;
218 return std::make_unique<GpuMPO>(lib, cloned);
219 }
220 bool ApplyKraus(const std::vector<int>& qubits, int count,
221 const double* operators) {
222 return lib->MPOApplyKraus(obj, qubits.size(), qubits.data(), count,
223 operators);
224 }
225 bool ApplyOneQubitMatrix(int qubit, const double* matrixInterleaved) {
226 return lib->MPOApplyOneQubitMatrix(obj, qubit, matrixInterleaved);
227 }
228 bool ApplyTwoQubitMatrix(int qubit1, int qubit2,
229 const double* matrixInterleaved) {
230 return lib->MPOApplyTwoQubitMatrix(obj, qubit1, qubit2,
231 matrixInterleaved);
232 }
233
234#define GPU_MPO_CHECK(call, name) \
235 do { \
236 if (!(call)) \
237 throw std::runtime_error("GPU matrix-product-operator " name \
238 " failed"); \
239 } while (false)
240#define GPU_MPO_GATE1(name) \
241 void name(int q) { GPU_MPO_CHECK(lib->MPO##name(obj, q), #name); }
242#define GPU_MPO_GATE2(name) \
243 void name(int a, int b) { GPU_MPO_CHECK(lib->MPO##name(obj, a, b), #name); }
244#define GPU_MPO_ROT1(name) \
245 void name(int q, double x) { \
246 GPU_MPO_CHECK(lib->MPO##name(obj, q, x), #name); \
247 }
248#define GPU_MPO_ROT2(name) \
249 void name(int a, int b, double x) { \
250 GPU_MPO_CHECK(lib->MPO##name(obj, a, b, x), #name); \
251 }
252 GPU_MPO_GATE1(ApplyReset)
253 GPU_MPO_ROT1(ApplyBitFlipNoise) GPU_MPO_ROT1(ApplyPhaseFlipNoise)
254 GPU_MPO_ROT1(ApplyDepolarizingNoise) GPU_MPO_ROT1(ApplyAmplitudeDamping)
255 GPU_MPO_ROT1(ApplyPhaseDamping) GPU_MPO_GATE1(ApplyNonSelectiveMeasurement)
256 GPU_MPO_GATE1(ApplyX) GPU_MPO_GATE1(ApplyY) GPU_MPO_GATE1(ApplyZ)
257 GPU_MPO_GATE1(ApplyH) GPU_MPO_GATE1(ApplyS) GPU_MPO_GATE1(ApplySDG)
258 GPU_MPO_GATE1(ApplyT) GPU_MPO_GATE1(ApplyTDG) GPU_MPO_GATE1(ApplySX)
259 GPU_MPO_GATE1(ApplySXDG) GPU_MPO_GATE1(ApplyK)
260 GPU_MPO_ROT1(ApplyP) GPU_MPO_ROT1(ApplyRx) GPU_MPO_ROT1(ApplyRy)
261 GPU_MPO_ROT1(ApplyRz)
262 void ApplyU(int q, double a, double b, double c, double d) {
263 GPU_MPO_CHECK(lib->MPOApplyU(obj, q, a, b, c, d), "ApplyU");
264 }
265 GPU_MPO_GATE2(ApplyCX) GPU_MPO_GATE2(ApplyCY) GPU_MPO_GATE2(ApplyCZ)
266 GPU_MPO_GATE2(ApplyCH) GPU_MPO_GATE2(ApplyCSX) GPU_MPO_GATE2(ApplyCSXDG)
267 GPU_MPO_ROT2(ApplyCP) GPU_MPO_ROT2(ApplyCRx) GPU_MPO_ROT2(ApplyCRy)
268 GPU_MPO_ROT2(ApplyCRz)
269 GPU_MPO_GATE2(ApplySwap)
270 void ApplyCU(int a, int b, double c, double d, double e, double f) {
271 GPU_MPO_CHECK(lib->MPOApplyCU(obj, a, b, c, d, e, f), "ApplyCU");
272 }
273#undef GPU_MPO_ROT2
274#undef GPU_MPO_ROT1
275#undef GPU_MPO_GATE2
276#undef GPU_MPO_GATE1
277#undef GPU_MPO_CHECK
278
279 private:
280 GpuDeviceContext lib;
281 void* obj = nullptr;
282};
283
284} // namespace Simulators
285#endif
286#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 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)