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