Maestro 0.3.1
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
GpuPauliPropagator.h
Go to the documentation of this file.
1
11
12#pragma once
13
14#ifndef _GPU_PAULI_PROPAGATOR_H
15#define _GPU_PAULI_PROPAGATOR_H 1
16
17#ifdef __linux__
18
19#include "GpuDeviceContext.h"
20
21#define _USE_MATH_DEFINES
22#include <math.h>
23
24namespace Simulators {
25
26class GpuPauliPropagator {
27 public:
28 explicit GpuPauliPropagator(const std::shared_ptr<GpuLibrary> &lib, int device = -1)
29 : device(device == -1 && lib ? lib->GetCreationDevice() : device), lib(lib), obj(nullptr) {}
30
31 int GetGpuDevice() const { return lib ? lib->PauliPropGetGpuId(obj) : -1; }
32
33 GpuPauliPropagator() = delete;
34 GpuPauliPropagator(const GpuPauliPropagator &) = delete;
35 GpuPauliPropagator &operator=(const GpuPauliPropagator &) = delete;
36 GpuPauliPropagator(GpuPauliPropagator &&) = default;
37 GpuPauliPropagator &operator=(GpuPauliPropagator &&) = default;
38
39 ~GpuPauliPropagator() {
40 if (lib && obj) lib->DestroyPauliPropSimulator(obj);
41 }
42
43 bool CreateSimulator(int numQubits) {
44 if (lib) {
45 auto lock = lib->LockInitialization();
46 if (!lib->SetGpuDevice(device)) return false;
47 if (obj) lib->DestroyPauliPropSimulator(obj);
48 obj = nullptr;
49 obj = lib->CreatePauliPropSimulator(numQubits);
50
51 return obj != nullptr;
52 }
53 return false;
54 }
55
56 int GetNrQubits() {
57 if (lib) {
58 return lib->PauliPropGetNrQubits(obj);
59 }
60 return 0;
61 }
62
63 bool SetSeed(uint64_t seed) {
64 return lib && obj && lib->PauliPropSetSeed(obj, seed);
65 }
66
67 bool SetWillUseSampling(bool willUseSampling) {
68 if (lib) {
69 return lib->PauliPropSetWillUseSampling(obj, willUseSampling) == 1;
70 }
71 return false;
72 }
73
74 bool GetWillUseSampling() {
75 if (lib) {
76 return lib->PauliPropGetWillUseSampling(obj) == 1;
77 }
78 return false;
79 }
80
81 double GetCoefficientTruncationCutoff() {
82 if (lib) {
83 return lib->PauliPropGetCoefficientTruncationCutoff(obj);
84 }
85 return 0.0;
86 }
87
88 void SetCoefficientTruncationCutoff(double cutoff) {
89 if (lib) {
90 lib->PauliPropSetCoefficientTruncationCutoff(obj, cutoff);
91 }
92 }
93
94 double GetWeightTruncationCutoff() {
95 if (lib) {
96 return lib->PauliPropGetWeightTruncationCutoff(obj);
97 }
98 return 0.0;
99 }
100
101 void SetWeightTruncationCutoff(double cutoff) {
102 if (lib) {
103 lib->PauliPropSetWeightTruncationCutoff(obj, cutoff);
104 }
105 }
106
107 int GetNumGatesBetweenTruncations() {
108 if (lib) {
109 return lib->PauliPropGetNumGatesBetweenTruncations(obj);
110 }
111 return 0;
112 }
113
114 void SetNumGatesBetweenTruncations(int numGates) {
115 if (lib) {
116 lib->PauliPropSetNumGatesBetweenTruncations(obj, numGates);
117 }
118 }
119
120 int GetNumGatesBetweenDeduplications() {
121 if (lib) {
122 return lib->PauliPropGetNumGatesBetweenDeduplications(obj);
123 }
124 return 0;
125 }
126
127 void SetNumGatesBetweenDeduplications(int numGates) {
128 if (lib) {
129 lib->PauliPropSetNumGatesBetweenDeduplications(obj, numGates);
130 }
131 }
132
133 bool ClearOperators() {
134 if (lib) {
135 return lib->PauliPropClearOperators(obj);
136 }
137 return false;
138 }
139
140 bool AllocateMemory(double percentage) {
141 if (lib) {
142 return lib->PauliPropAllocateMemory(obj, percentage);
143 }
144 return false;
145 }
146
147 double GetExpectationValue() {
148 if (lib) {
149 return lib->PauliPropGetExpectationValue(obj);
150 }
151 return 0.0;
152 }
153
154 bool Execute() {
155 if (lib) {
156 return lib->PauliPropExecute(obj);
157 }
158 return false;
159 }
160
161 double ExpectationValue(const std::string &pauliStr) {
162 SetInPauliExpansionUnique(pauliStr);
163 Execute();
164 return GetExpectationValue();
165 }
166
167 double ExpectationValueMultiple(const std::vector<std::string> &pauliStrs,
168 const std::vector<double> &coefficients) {
169 SetInPauliExpansionMultiple(pauliStrs, coefficients);
170 Execute();
171 return GetExpectationValue();
172 }
173
174 bool SetInPauliExpansionUnique(const std::string &pauliStr) {
175 if (lib) {
176 return lib->PauliPropSetInPauliExpansionUnique(obj, pauliStr.c_str());
177 }
178 return false;
179 }
180
181 bool SetInPauliExpansionMultiple(const std::vector<std::string> &pauliStrs,
182 const std::vector<double> &coefficients) {
183 if (lib && !pauliStrs.empty() && pauliStrs.size() == coefficients.size()) {
184 std::vector<char *> cStrs(pauliStrs.size());
185 for (size_t i = 0; i < pauliStrs.size(); ++i) {
186 cStrs[i] = const_cast<char *>(pauliStrs[i].c_str());
187 }
188 return lib->PauliPropSetInPauliExpansionMultiple(
189 obj, (const char **)cStrs.data(), coefficients.data(),
190 static_cast<int>(pauliStrs.size()));
191 }
192 return false;
193 }
194
195 bool ApplyX(int qubit) {
196 if (lib) {
197 return lib->PauliPropApplyX(obj, qubit);
198 }
199 return false;
200 }
201
202 bool ApplyY(int qubit) {
203 if (lib) {
204 return lib->PauliPropApplyY(obj, qubit);
205 }
206 return false;
207 }
208
209 bool ApplyZ(int qubit) {
210 if (lib) {
211 return lib->PauliPropApplyZ(obj, qubit);
212 }
213 return false;
214 }
215
216 bool ApplyH(int qubit) {
217 if (lib) {
218 return lib->PauliPropApplyH(obj, qubit);
219 }
220 return false;
221 }
222
223 bool ApplyS(int qubit) {
224 if (lib) {
225 return lib->PauliPropApplyS(obj, qubit);
226 }
227 return false;
228 }
229
230 bool ApplySQRTX(int qubit) {
231 if (lib) {
232 return lib->PauliPropApplySQRTX(obj, qubit);
233 }
234 return false;
235 }
236
237 bool ApplySQRTY(int qubit) {
238 if (lib) {
239 return lib->PauliPropApplySQRTY(obj, qubit);
240 }
241 return false;
242 }
243
244 bool ApplySQRTZ(int qubit) {
245 if (lib) {
246 return lib->PauliPropApplySQRTZ(obj, qubit);
247 }
248 return false;
249 }
250
251 bool ApplyCX(int controlQubit, int targetQubit) {
252 if (lib) {
253 return lib->PauliPropApplyCX(obj, controlQubit, targetQubit);
254 }
255 return false;
256 }
257
258 bool ApplyCY(int controlQubit, int targetQubit) {
259 if (lib) {
260 return lib->PauliPropApplyCY(obj, controlQubit, targetQubit);
261 }
262 return false;
263 }
264
265 bool ApplyCZ(int controlQubit, int targetQubit) {
266 if (lib) {
267 return lib->PauliPropApplyCZ(obj, controlQubit, targetQubit);
268 }
269 return false;
270 }
271
272 bool ApplySWAP(int qubit1, int qubit2) {
273 if (lib) {
274 return lib->PauliPropApplySWAP(obj, qubit1, qubit2);
275 }
276 return false;
277 }
278
279 bool ApplyISWAP(int qubit1, int qubit2) {
280 if (lib) {
281 return lib->PauliPropApplyISWAP(obj, qubit1, qubit2);
282 }
283 return false;
284 }
285
286 bool ApplyRX(int qubit, double angle) {
287 if (lib) {
288 return lib->PauliPropApplyRX(obj, qubit, angle);
289 }
290 return false;
291 }
292
293 bool ApplyRY(int qubit, double angle) {
294 if (lib) {
295 return lib->PauliPropApplyRY(obj, qubit, angle);
296 }
297 return false;
298 }
299
300 bool ApplyRZ(int qubit, double angle) {
301 if (lib) {
302 return lib->PauliPropApplyRZ(obj, qubit, angle);
303 }
304 return false;
305 }
306
307 bool ApplySDG(int qubit) {
308 if (!ApplyZ(qubit)) return false;
309 if (!ApplyS(qubit)) return false;
310
311 return true;
312 }
313
314 bool ApplyK(int qubit) {
315 if (!ApplyZ(qubit)) return false;
316 if (!ApplyS(qubit)) return false;
317 if (!ApplyH(qubit)) return false;
318 if (!ApplyS(qubit)) return false;
319
320 return true;
321 }
322
323 bool ApplySxDAG(int qubit) {
324 if (!ApplyS(qubit)) return false;
325 if (!ApplyH(qubit)) return false;
326 if (!ApplyS(qubit)) return false;
327 return true;
328 }
329
330 bool ApplyP(int qubit, double lambda) { return ApplyRZ(qubit, lambda); }
331
332 bool ApplyT(int qubit) { return ApplyRZ(qubit, M_PI_4); }
333
334 bool ApplyTDG(int qubit) { return ApplyRZ(qubit, -M_PI_4); }
335
336 bool ApplyU(int qubit, double theta, double phi, double lambda,
337 double gamma = 0.0) {
338 if (!ApplyRZ(qubit, lambda)) return false;
339 if (!ApplyRY(qubit, theta)) return false;
340 if (!ApplyRZ(qubit, phi)) return false;
341
342 return true;
343 }
344
345 bool ApplyCH(int controlQubit, int targetQubit) {
346 if (!ApplyH(targetQubit)) return false;
347 if (!ApplySDG(targetQubit)) return false;
348 if (!ApplyCX(controlQubit, targetQubit)) return false;
349 if (!ApplyH(targetQubit)) return false;
350 if (!ApplyT(targetQubit)) return false;
351 if (!ApplyCX(controlQubit, targetQubit)) return false;
352 if (!ApplyT(targetQubit)) return false;
353 if (!ApplyH(targetQubit)) return false;
354 if (!ApplyS(targetQubit)) return false;
355 if (!ApplyX(targetQubit)) return false;
356 if (!ApplyS(controlQubit)) return false;
357
358 return true;
359 }
360
361 bool ApplyCU(int controlQubit, int targetQubit, double theta, double phi,
362 double lambda, double gamma = 0.0) {
363 if (gamma != 0.0) {
364 if (!ApplyP(controlQubit, gamma)) return false;
365 }
366 const double lambdaPlusPhiHalf = 0.5 * (lambda + phi);
367 const double halfTheta = 0.5 * theta;
368 if (!ApplyP(targetQubit, 0.5 * (lambda - phi))) return false;
369 if (!ApplyP(controlQubit, lambdaPlusPhiHalf)) return false;
370 if (!ApplyCX(controlQubit, targetQubit)) return false;
371 if (!ApplyU(targetQubit, -halfTheta, 0, -lambdaPlusPhiHalf)) return false;
372 if (!ApplyCX(controlQubit, targetQubit)) return false;
373 if (!ApplyU(targetQubit, halfTheta, phi, 0)) return false;
374 return true;
375 }
376
377 bool ApplyCRX(int controlQubit, int targetQubit, double angle) {
378 const double halfAngle = angle * 0.5;
379 if (!ApplyH(targetQubit)) return false;
380 if (!ApplyCX(controlQubit, targetQubit)) return false;
381 if (!ApplyRZ(targetQubit, -halfAngle)) return false;
382 if (!ApplyCX(controlQubit, targetQubit)) return false;
383 if (!ApplyRZ(targetQubit, halfAngle)) return false;
384 if (!ApplyH(targetQubit)) return false;
385 return true;
386 }
387
388 bool ApplyCRY(int controlQubit, int targetQubit, double angle) {
389 const double halfAngle = angle * 0.5;
390 if (!ApplyRY(targetQubit, halfAngle)) return false;
391 if (!ApplyCX(controlQubit, targetQubit)) return false;
392 if (!ApplyRY(targetQubit, -halfAngle)) return false;
393 if (!ApplyCX(controlQubit, targetQubit)) return false;
394 return true;
395 }
396
397 bool ApplyCRZ(int controlQubit, int targetQubit, double angle) {
398 const double halfAngle = angle * 0.5;
399 if (!ApplyRZ(targetQubit, halfAngle)) return false;
400 if (!ApplyCX(controlQubit, targetQubit)) return false;
401 if (!ApplyRZ(targetQubit, -halfAngle)) return false;
402 if (!ApplyCX(controlQubit, targetQubit)) return false;
403 return true;
404 }
405
406 bool ApplyCP(int controlQubit, int targetQubit, double lambda) {
407 const double halfAngle = lambda * 0.5;
408 if (!ApplyP(controlQubit, halfAngle)) return false;
409 if (!ApplyCX(controlQubit, targetQubit)) return false;
410 if (!ApplyP(targetQubit, -halfAngle)) return false;
411 if (!ApplyCX(controlQubit, targetQubit)) return false;
412 if (!ApplyP(targetQubit, halfAngle)) return false;
413
414 return true;
415 }
416
417 bool ApplyCS(int controlQubit, int targetQubit) {
418 if (!ApplyT(controlQubit)) return false;
419 if (!ApplyT(targetQubit)) return false;
420 if (!ApplyCX(controlQubit, targetQubit)) return false;
421 if (!ApplyTDG(targetQubit)) return false;
422 if (!ApplyCX(controlQubit, targetQubit)) return false;
423
424 return true;
425 }
426
427 bool ApplyCSDAG(int controlQubit, int targetQubit) {
428 if (!ApplyCX(controlQubit, targetQubit)) return false;
429 if (!ApplyT(targetQubit)) return false;
430 if (!ApplyCX(controlQubit, targetQubit)) return false;
431 if (!ApplyTDG(controlQubit)) return false;
432 if (!ApplyTDG(targetQubit)) return false;
433
434 return true;
435 }
436
437 bool ApplyCSX(int controlQubit, int targetQubit) {
438 if (!ApplyH(targetQubit)) return false;
439 if (!ApplyCS(controlQubit, targetQubit)) return false;
440 if (!ApplyH(targetQubit)) return false;
441
442 return true;
443 }
444
445 bool ApplyCSXDAG(int controlQubit, int targetQubit) {
446 if (!ApplyH(targetQubit)) return false;
447 if (!ApplyCSDAG(controlQubit, targetQubit)) return false;
448 if (!ApplyH(targetQubit)) return false;
449
450 return true;
451 }
452
453 bool ApplyCSwap(int controlQubit, int targetQubit1, int targetQubit2) {
454 const size_t q1 = controlQubit; // control
455 const size_t q2 = targetQubit1;
456 const size_t q3 = targetQubit2;
457
458 if (!ApplyCX(q3, q2)) return false;
459 if (!ApplyCSX(q2, q3)) return false;
460 if (!ApplyCX(q1, q2)) return false;
461
462 if (!ApplyP(q3, M_PI)) return false;
463 if (!ApplyP(q2, -M_PI_2)) return false;
464
465 if (!ApplyCSX(q2, q3)) return false;
466 if (!ApplyCX(q1, q2)) return false;
467
468 if (!ApplyP(q3, M_PI)) return false;
469 if (!ApplyCSX(q1, q3)) return false;
470 if (!ApplyCX(q3, q2)) return false;
471
472 return true;
473 }
474
475 bool ApplyCCX(int controlQubit1, int controlQubit2, int targetQubit) {
476 const size_t q1 = controlQubit1; // control 1
477 const size_t q2 = controlQubit2; // control 2
478 const size_t q3 = targetQubit; // target
479
480 if (!ApplyCSX(q2, q3)) return false;
481 if (!ApplyCX(q1, q2)) return false;
482 if (!ApplyCSXDAG(q2, q3)) return false;
483 if (!ApplyCX(q1, q2)) return false;
484 if (!ApplyCSX(q1, q3)) return false;
485
486 return true;
487 }
488
489 // to implement all gates, add:
490 // see qasm paper for some decompositions
491 // for the three qubit gates, see the decompositions already done for mps
492 // qcsim
493 /*
494 kCSwapGateType, kCCXGateType,
495 */
496
497 bool AddNoiseX(int qubit, double probability) {
498 if (lib) {
499 return lib->PauliPropAddNoiseX(obj, qubit, probability);
500 }
501 return false;
502 }
503
504 bool AddNoiseY(int qubit, double probability) {
505 if (lib) {
506 return lib->PauliPropAddNoiseY(obj, qubit, probability);
507 }
508 return false;
509 }
510
511 bool AddNoiseZ(int qubit, double probability) {
512 if (lib) {
513 return lib->PauliPropAddNoiseZ(obj, qubit, probability);
514 }
515 return false;
516 }
517
518 bool AddNoiseXYZ(int qubit, double px, double py, double pz) {
519 if (lib) {
520 return lib->PauliPropAddNoiseXYZ(obj, qubit, px, py, pz);
521 }
522 return false;
523 }
524
525 bool AddAmplitudeDamping(int qubit, double dampingProb, double exciteProb) {
526 if (lib) {
527 return lib->PauliPropAddAmplitudeDamping(obj, qubit, dampingProb,
528 exciteProb);
529 }
530 return false;
531 }
532
533 double QubitProbability0(int qubit) {
534 if (lib) {
535 return lib->PauliPropQubitProbability0(obj, qubit);
536 }
537 return 0.0;
538 }
539
540 double Probability(unsigned long long int outcome) {
541 if (lib) {
542 return lib->PauliPropProbability(obj, outcome);
543 }
544 return 0.0;
545 }
546
547 bool MeasureQubit(int qubit) {
548 if (lib) {
549 return lib->PauliPropMeasureQubit(obj, qubit);
550 }
551 return false;
552 }
553
554 std::vector<bool> SampleQubits(const std::vector<int> &qubits) {
555 std::vector<bool> results;
556 if (lib && !qubits.empty()) {
557 std::vector<int> cQubits = qubits;
558 unsigned char *res = lib->PauliPropSampleQubits(
559 obj, qubits.data(), static_cast<int>(cQubits.size()));
560 if (!res) return results;
561
562 results.reserve(cQubits.size());
563 for (size_t i = 0; i < cQubits.size(); ++i) {
564 // results are encoded as bits
565 const bool bit = ((res[i / 8] >> (i % 8)) & 1) == 1;
566 results.push_back(bit);
567 }
568
569 lib->PauliPropFreeSampledQubits(res);
570 }
571 return results;
572 }
573
574 void SaveState() {
575 if (lib) {
576 lib->PauliPropSaveState(obj);
577 }
578 }
579
580 void RestoreState() {
581 if (lib) {
582 lib->PauliPropRestoreState(obj);
583 }
584 }
585
586 private:
587 int device; // Fixed even when native creation is delayed or repeated.
588 GpuDeviceContext lib;
589 void *obj;
590};
591
592} // namespace Simulators
593
594#endif
595#endif
int ApplyK(void *sim, int qubit)
double Probability(void *sim, unsigned long long int outcome)
int RestoreState(void *sim)
int ApplyX(void *sim, int qubit)
int ApplyU(void *sim, int qubit, double theta, double phi, double lambda, double gamma)
unsigned long int CreateSimulator(int simType, int simExecType)
int ApplyTDG(void *sim, int qubit)
int ApplyS(void *sim, int qubit)
int ApplyCX(void *sim, int controlQubit, int targetQubit)
int ApplyCP(void *sim, int controlQubit, int targetQubit, double theta)
int ApplySDG(void *sim, int qubit)
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 ApplyP(void *sim, int qubit, double theta)
int ApplyCH(void *sim, int controlQubit, int targetQubit)
int ApplyCZ(void *sim, int controlQubit, int targetQubit)
int ApplyT(void *sim, int qubit)
int ApplyCSX(void *sim, int controlQubit, int targetQubit)
int SaveState(void *sim)