Maestro 0.3.11
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{
26
27class GpuPauliPropagator
28{
29 public:
30 explicit GpuPauliPropagator(const std::shared_ptr<GpuLibrary> &lib, int device = -1)
31 : device(device == -1 && lib ? lib->GetCreationDevice() : device), lib(lib), obj(nullptr)
32 {
33 }
34
35 int GetGpuDevice() const
36 {
37 return lib ? lib->PauliPropGetGpuId(obj) : -1;
38 }
39
40 GpuPauliPropagator() = delete;
41 GpuPauliPropagator(const GpuPauliPropagator &) = delete;
42 GpuPauliPropagator &operator=(const GpuPauliPropagator &) = delete;
43 GpuPauliPropagator(GpuPauliPropagator &&) = default;
44 GpuPauliPropagator &operator=(GpuPauliPropagator &&) = default;
45
46 ~GpuPauliPropagator()
47 {
48 if (lib && obj)
49 lib->DestroyPauliPropSimulator(obj);
50 }
51
52 bool CreateSimulator(int numQubits)
53 {
54 if (lib)
55 {
56 auto lock = lib->LockInitialization();
57 if (!lib->SetGpuDevice(device))
58 return false;
59 if (obj)
60 lib->DestroyPauliPropSimulator(obj);
61 obj = nullptr;
62 obj = lib->CreatePauliPropSimulator(numQubits);
63
64 return obj != nullptr;
65 }
66 return false;
67 }
68
69 int GetNrQubits()
70 {
71 if (lib)
72 {
73 return lib->PauliPropGetNrQubits(obj);
74 }
75 return 0;
76 }
77
78 bool SetSeed(uint64_t seed)
79 {
80 return lib && obj && lib->PauliPropSetSeed(obj, seed);
81 }
82
83 bool SetWillUseSampling(bool willUseSampling)
84 {
85 if (lib)
86 {
87 return lib->PauliPropSetWillUseSampling(obj, willUseSampling) == 1;
88 }
89 return false;
90 }
91
92 bool GetWillUseSampling()
93 {
94 if (lib)
95 {
96 return lib->PauliPropGetWillUseSampling(obj) == 1;
97 }
98 return false;
99 }
100
101 double GetCoefficientTruncationCutoff()
102 {
103 if (lib)
104 {
105 return lib->PauliPropGetCoefficientTruncationCutoff(obj);
106 }
107 return 0.0;
108 }
109
110 void SetCoefficientTruncationCutoff(double cutoff)
111 {
112 if (lib)
113 {
114 lib->PauliPropSetCoefficientTruncationCutoff(obj, cutoff);
115 }
116 }
117
118 double GetWeightTruncationCutoff()
119 {
120 if (lib)
121 {
122 return lib->PauliPropGetWeightTruncationCutoff(obj);
123 }
124 return 0.0;
125 }
126
127 void SetWeightTruncationCutoff(double cutoff)
128 {
129 if (lib)
130 {
131 lib->PauliPropSetWeightTruncationCutoff(obj, cutoff);
132 }
133 }
134
135 int GetNumGatesBetweenTruncations()
136 {
137 if (lib)
138 {
139 return lib->PauliPropGetNumGatesBetweenTruncations(obj);
140 }
141 return 0;
142 }
143
144 void SetNumGatesBetweenTruncations(int numGates)
145 {
146 if (lib)
147 {
148 lib->PauliPropSetNumGatesBetweenTruncations(obj, numGates);
149 }
150 }
151
152 int GetNumGatesBetweenDeduplications()
153 {
154 if (lib)
155 {
156 return lib->PauliPropGetNumGatesBetweenDeduplications(obj);
157 }
158 return 0;
159 }
160
161 void SetNumGatesBetweenDeduplications(int numGates)
162 {
163 if (lib)
164 {
165 lib->PauliPropSetNumGatesBetweenDeduplications(obj, numGates);
166 }
167 }
168
169 bool ClearOperators()
170 {
171 if (lib)
172 {
173 return lib->PauliPropClearOperators(obj);
174 }
175 return false;
176 }
177
178 bool AllocateMemory(double percentage)
179 {
180 if (lib)
181 {
182 return lib->PauliPropAllocateMemory(obj, percentage);
183 }
184 return false;
185 }
186
187 double GetExpectationValue()
188 {
189 if (lib)
190 {
191 return lib->PauliPropGetExpectationValue(obj);
192 }
193 return 0.0;
194 }
195
196 bool Execute()
197 {
198 if (lib)
199 {
200 return lib->PauliPropExecute(obj);
201 }
202 return false;
203 }
204
205 double ExpectationValue(const std::string &pauliStr)
206 {
207 SetInPauliExpansionUnique(pauliStr);
208 Execute();
209 return GetExpectationValue();
210 }
211
212 double ExpectationValueMultiple(const std::vector<std::string> &pauliStrs, const std::vector<double> &coefficients)
213 {
214 SetInPauliExpansionMultiple(pauliStrs, coefficients);
215 Execute();
216 return GetExpectationValue();
217 }
218
219 bool SetInPauliExpansionUnique(const std::string &pauliStr)
220 {
221 if (lib)
222 {
223 return lib->PauliPropSetInPauliExpansionUnique(obj, pauliStr.c_str());
224 }
225 return false;
226 }
227
228 bool SetInPauliExpansionMultiple(const std::vector<std::string> &pauliStrs, const std::vector<double> &coefficients)
229 {
230 if (lib && !pauliStrs.empty() && pauliStrs.size() == coefficients.size())
231 {
232 std::vector<char *> cStrs(pauliStrs.size());
233 for (size_t i = 0; i < pauliStrs.size(); ++i)
234 {
235 cStrs[i] = const_cast<char *>(pauliStrs[i].c_str());
236 }
237 return lib->PauliPropSetInPauliExpansionMultiple(obj, (const char **)cStrs.data(), coefficients.data(), static_cast<int>(pauliStrs.size()));
238 }
239 return false;
240 }
241
242 bool ApplyX(int qubit)
243 {
244 if (lib)
245 {
246 return lib->PauliPropApplyX(obj, qubit);
247 }
248 return false;
249 }
250
251 bool ApplyY(int qubit)
252 {
253 if (lib)
254 {
255 return lib->PauliPropApplyY(obj, qubit);
256 }
257 return false;
258 }
259
260 bool ApplyZ(int qubit)
261 {
262 if (lib)
263 {
264 return lib->PauliPropApplyZ(obj, qubit);
265 }
266 return false;
267 }
268
269 bool ApplyH(int qubit)
270 {
271 if (lib)
272 {
273 return lib->PauliPropApplyH(obj, qubit);
274 }
275 return false;
276 }
277
278 bool ApplyS(int qubit)
279 {
280 if (lib)
281 {
282 return lib->PauliPropApplyS(obj, qubit);
283 }
284 return false;
285 }
286
287 bool ApplySQRTX(int qubit)
288 {
289 if (lib)
290 {
291 return lib->PauliPropApplySQRTX(obj, qubit);
292 }
293 return false;
294 }
295
296 bool ApplySQRTY(int qubit)
297 {
298 if (lib)
299 {
300 return lib->PauliPropApplySQRTY(obj, qubit);
301 }
302 return false;
303 }
304
305 bool ApplySQRTZ(int qubit)
306 {
307 if (lib)
308 {
309 return lib->PauliPropApplySQRTZ(obj, qubit);
310 }
311 return false;
312 }
313
314 bool ApplyCX(int controlQubit, int targetQubit)
315 {
316 if (lib)
317 {
318 return lib->PauliPropApplyCX(obj, controlQubit, targetQubit);
319 }
320 return false;
321 }
322
323 bool ApplyCY(int controlQubit, int targetQubit)
324 {
325 if (lib)
326 {
327 return lib->PauliPropApplyCY(obj, controlQubit, targetQubit);
328 }
329 return false;
330 }
331
332 bool ApplyCZ(int controlQubit, int targetQubit)
333 {
334 if (lib)
335 {
336 return lib->PauliPropApplyCZ(obj, controlQubit, targetQubit);
337 }
338 return false;
339 }
340
341 bool ApplySWAP(int qubit1, int qubit2)
342 {
343 if (lib)
344 {
345 return lib->PauliPropApplySWAP(obj, qubit1, qubit2);
346 }
347 return false;
348 }
349
350 bool ApplyISWAP(int qubit1, int qubit2)
351 {
352 if (lib)
353 {
354 return lib->PauliPropApplyISWAP(obj, qubit1, qubit2);
355 }
356 return false;
357 }
358
359 bool ApplyRX(int qubit, double angle)
360 {
361 if (lib)
362 {
363 return lib->PauliPropApplyRX(obj, qubit, angle);
364 }
365 return false;
366 }
367
368 bool ApplyRY(int qubit, double angle)
369 {
370 if (lib)
371 {
372 return lib->PauliPropApplyRY(obj, qubit, angle);
373 }
374 return false;
375 }
376
377 bool ApplyRZ(int qubit, double angle)
378 {
379 if (lib)
380 {
381 return lib->PauliPropApplyRZ(obj, qubit, angle);
382 }
383 return false;
384 }
385
386 bool ApplySDG(int qubit)
387 {
388 if (!ApplyZ(qubit))
389 return false;
390 if (!ApplyS(qubit))
391 return false;
392
393 return true;
394 }
395
396 bool ApplyK(int qubit)
397 {
398 if (!ApplyZ(qubit))
399 return false;
400 if (!ApplyS(qubit))
401 return false;
402 if (!ApplyH(qubit))
403 return false;
404 if (!ApplyS(qubit))
405 return false;
406
407 return true;
408 }
409
410 bool ApplySxDAG(int qubit)
411 {
412 if (!ApplyS(qubit))
413 return false;
414 if (!ApplyH(qubit))
415 return false;
416 if (!ApplyS(qubit))
417 return false;
418 return true;
419 }
420
421 bool ApplyP(int qubit, double lambda)
422 {
423 return ApplyRZ(qubit, lambda);
424 }
425
426 bool ApplyT(int qubit)
427 {
428 return ApplyRZ(qubit, M_PI_4);
429 }
430
431 bool ApplyTDG(int qubit)
432 {
433 return ApplyRZ(qubit, -M_PI_4);
434 }
435
436 bool ApplyU(int qubit, double theta, double phi, double lambda, double gamma = 0.0)
437 {
438 if (!ApplyRZ(qubit, lambda))
439 return false;
440 if (!ApplyRY(qubit, theta))
441 return false;
442 if (!ApplyRZ(qubit, phi))
443 return false;
444
445 return true;
446 }
447
448 bool ApplyCH(int controlQubit, int targetQubit)
449 {
450 if (!ApplyH(targetQubit))
451 return false;
452 if (!ApplySDG(targetQubit))
453 return false;
454 if (!ApplyCX(controlQubit, targetQubit))
455 return false;
456 if (!ApplyH(targetQubit))
457 return false;
458 if (!ApplyT(targetQubit))
459 return false;
460 if (!ApplyCX(controlQubit, targetQubit))
461 return false;
462 if (!ApplyT(targetQubit))
463 return false;
464 if (!ApplyH(targetQubit))
465 return false;
466 if (!ApplyS(targetQubit))
467 return false;
468 if (!ApplyX(targetQubit))
469 return false;
470 if (!ApplyS(controlQubit))
471 return false;
472
473 return true;
474 }
475
476 bool ApplyCU(int controlQubit, int targetQubit, double theta, double phi, double lambda, double gamma = 0.0)
477 {
478 if (gamma != 0.0)
479 {
480 if (!ApplyP(controlQubit, gamma))
481 return false;
482 }
483 const double lambdaPlusPhiHalf = 0.5 * (lambda + phi);
484 const double halfTheta = 0.5 * theta;
485 if (!ApplyP(targetQubit, 0.5 * (lambda - phi)))
486 return false;
487 if (!ApplyP(controlQubit, lambdaPlusPhiHalf))
488 return false;
489 if (!ApplyCX(controlQubit, targetQubit))
490 return false;
491 if (!ApplyU(targetQubit, -halfTheta, 0, -lambdaPlusPhiHalf))
492 return false;
493 if (!ApplyCX(controlQubit, targetQubit))
494 return false;
495 if (!ApplyU(targetQubit, halfTheta, phi, 0))
496 return false;
497 return true;
498 }
499
500 bool ApplyCRX(int controlQubit, int targetQubit, double angle)
501 {
502 const double halfAngle = angle * 0.5;
503 if (!ApplyH(targetQubit))
504 return false;
505 if (!ApplyCX(controlQubit, targetQubit))
506 return false;
507 if (!ApplyRZ(targetQubit, -halfAngle))
508 return false;
509 if (!ApplyCX(controlQubit, targetQubit))
510 return false;
511 if (!ApplyRZ(targetQubit, halfAngle))
512 return false;
513 if (!ApplyH(targetQubit))
514 return false;
515 return true;
516 }
517
518 bool ApplyCRY(int controlQubit, int targetQubit, double angle)
519 {
520 const double halfAngle = angle * 0.5;
521 if (!ApplyRY(targetQubit, halfAngle))
522 return false;
523 if (!ApplyCX(controlQubit, targetQubit))
524 return false;
525 if (!ApplyRY(targetQubit, -halfAngle))
526 return false;
527 if (!ApplyCX(controlQubit, targetQubit))
528 return false;
529 return true;
530 }
531
532 bool ApplyCRZ(int controlQubit, int targetQubit, double angle)
533 {
534 const double halfAngle = angle * 0.5;
535 if (!ApplyRZ(targetQubit, halfAngle))
536 return false;
537 if (!ApplyCX(controlQubit, targetQubit))
538 return false;
539 if (!ApplyRZ(targetQubit, -halfAngle))
540 return false;
541 if (!ApplyCX(controlQubit, targetQubit))
542 return false;
543 return true;
544 }
545
546 bool ApplyCP(int controlQubit, int targetQubit, double lambda)
547 {
548 const double halfAngle = lambda * 0.5;
549 if (!ApplyP(controlQubit, halfAngle))
550 return false;
551 if (!ApplyCX(controlQubit, targetQubit))
552 return false;
553 if (!ApplyP(targetQubit, -halfAngle))
554 return false;
555 if (!ApplyCX(controlQubit, targetQubit))
556 return false;
557 if (!ApplyP(targetQubit, halfAngle))
558 return false;
559
560 return true;
561 }
562
563 bool ApplyCS(int controlQubit, int targetQubit)
564 {
565 if (!ApplyT(controlQubit))
566 return false;
567 if (!ApplyT(targetQubit))
568 return false;
569 if (!ApplyCX(controlQubit, targetQubit))
570 return false;
571 if (!ApplyTDG(targetQubit))
572 return false;
573 if (!ApplyCX(controlQubit, targetQubit))
574 return false;
575
576 return true;
577 }
578
579 bool ApplyCSDAG(int controlQubit, int targetQubit)
580 {
581 if (!ApplyCX(controlQubit, targetQubit))
582 return false;
583 if (!ApplyT(targetQubit))
584 return false;
585 if (!ApplyCX(controlQubit, targetQubit))
586 return false;
587 if (!ApplyTDG(controlQubit))
588 return false;
589 if (!ApplyTDG(targetQubit))
590 return false;
591
592 return true;
593 }
594
595 bool ApplyCSX(int controlQubit, int targetQubit)
596 {
597 if (!ApplyH(targetQubit))
598 return false;
599 if (!ApplyCS(controlQubit, targetQubit))
600 return false;
601 if (!ApplyH(targetQubit))
602 return false;
603
604 return true;
605 }
606
607 bool ApplyCSXDAG(int controlQubit, int targetQubit)
608 {
609 if (!ApplyH(targetQubit))
610 return false;
611 if (!ApplyCSDAG(controlQubit, targetQubit))
612 return false;
613 if (!ApplyH(targetQubit))
614 return false;
615
616 return true;
617 }
618
619 bool ApplyCSwap(int controlQubit, int targetQubit1, int targetQubit2)
620 {
621 const size_t q1 = controlQubit; // control
622 const size_t q2 = targetQubit1;
623 const size_t q3 = targetQubit2;
624
625 if (!ApplyCX(q3, q2))
626 return false;
627 if (!ApplyCSX(q2, q3))
628 return false;
629 if (!ApplyCX(q1, q2))
630 return false;
631
632 if (!ApplyP(q3, M_PI))
633 return false;
634 if (!ApplyP(q2, -M_PI_2))
635 return false;
636
637 if (!ApplyCSX(q2, q3))
638 return false;
639 if (!ApplyCX(q1, q2))
640 return false;
641
642 if (!ApplyP(q3, M_PI))
643 return false;
644 if (!ApplyCSX(q1, q3))
645 return false;
646 if (!ApplyCX(q3, q2))
647 return false;
648
649 return true;
650 }
651
652 bool ApplyCCX(int controlQubit1, int controlQubit2, int targetQubit)
653 {
654 const size_t q1 = controlQubit1; // control 1
655 const size_t q2 = controlQubit2; // control 2
656 const size_t q3 = targetQubit; // target
657
658 if (!ApplyCSX(q2, q3))
659 return false;
660 if (!ApplyCX(q1, q2))
661 return false;
662 if (!ApplyCSXDAG(q2, q3))
663 return false;
664 if (!ApplyCX(q1, q2))
665 return false;
666 if (!ApplyCSX(q1, q3))
667 return false;
668
669 return true;
670 }
671
672 // to implement all gates, add:
673 // see qasm paper for some decompositions
674 // for the three qubit gates, see the decompositions already done for mps
675 // qcsim
676 /*
677 kCSwapGateType, kCCXGateType,
678 */
679
680 bool AddNoiseX(int qubit, double probability)
681 {
682 if (lib)
683 {
684 return lib->PauliPropAddNoiseX(obj, qubit, probability);
685 }
686 return false;
687 }
688
689 bool AddNoiseY(int qubit, double probability)
690 {
691 if (lib)
692 {
693 return lib->PauliPropAddNoiseY(obj, qubit, probability);
694 }
695 return false;
696 }
697
698 bool AddNoiseZ(int qubit, double probability)
699 {
700 if (lib)
701 {
702 return lib->PauliPropAddNoiseZ(obj, qubit, probability);
703 }
704 return false;
705 }
706
707 bool AddNoiseXYZ(int qubit, double px, double py, double pz)
708 {
709 if (lib)
710 {
711 return lib->PauliPropAddNoiseXYZ(obj, qubit, px, py, pz);
712 }
713 return false;
714 }
715
716 bool AddAmplitudeDamping(int qubit, double dampingProb, double exciteProb)
717 {
718 if (lib)
719 {
720 return lib->PauliPropAddAmplitudeDamping(obj, qubit, dampingProb, exciteProb);
721 }
722 return false;
723 }
724
725 double QubitProbability0(int qubit)
726 {
727 if (lib)
728 {
729 return lib->PauliPropQubitProbability0(obj, qubit);
730 }
731 return 0.0;
732 }
733
734 double Probability(unsigned long long int outcome)
735 {
736 if (lib)
737 {
738 return lib->PauliPropProbability(obj, outcome);
739 }
740 return 0.0;
741 }
742
743 bool MeasureQubit(int qubit)
744 {
745 if (lib)
746 {
747 return lib->PauliPropMeasureQubit(obj, qubit);
748 }
749 return false;
750 }
751
752 std::vector<bool> SampleQubits(const std::vector<int> &qubits)
753 {
754 std::vector<bool> results;
755 if (lib && !qubits.empty())
756 {
757 std::vector<int> cQubits = qubits;
758 unsigned char *res = lib->PauliPropSampleQubits(obj, qubits.data(), static_cast<int>(cQubits.size()));
759 if (!res)
760 return results;
761
762 results.reserve(cQubits.size());
763 for (size_t i = 0; i < cQubits.size(); ++i)
764 {
765 // results are encoded as bits
766 const bool bit = ((res[i / 8] >> (i % 8)) & 1) == 1;
767 results.push_back(bit);
768 }
769
770 lib->PauliPropFreeSampledQubits(res);
771 }
772 return results;
773 }
774
775 void SaveState()
776 {
777 if (lib)
778 {
779 lib->PauliPropSaveState(obj);
780 }
781 }
782
783 void RestoreState()
784 {
785 if (lib)
786 {
787 lib->PauliPropRestoreState(obj);
788 }
789 }
790
791 private:
792 int device; // Fixed even when native creation is delayed or repeated.
793 GpuDeviceContext lib;
794 void *obj;
795};
796
797} // namespace Simulators
798
799#endif
800#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)
Bounded online routing based on current physical bond dimensions.