Maestro 0.2.5
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 if (lib) {
99 return lib->PauliPropGetNumGatesBetweenTruncations(obj);
100 }
101 return 0;
102 }
103
104 void SetNumGatesBetweenTruncations(int numGates) {
105 if (lib) {
106 lib->PauliPropSetNumGatesBetweenTruncations(obj, numGates);
107 }
108 }
109
110 int GetNumGatesBetweenDeduplications() {
111 if (lib) {
112 return lib->PauliPropGetNumGatesBetweenDeduplications(obj);
113 }
114 return 0;
115 }
116
117 void SetNumGatesBetweenDeduplications(int numGates) {
118 if (lib) {
119 lib->PauliPropSetNumGatesBetweenDeduplications(obj, numGates);
120 }
121 }
122
123 bool ClearOperators() {
124 if (lib) {
125 return lib->PauliPropClearOperators(obj);
126 }
127 return false;
128 }
129
130 bool AllocateMemory(double percentage) {
131 if (lib) {
132 return lib->PauliPropAllocateMemory(obj, percentage);
133 }
134 return false;
135 }
136
137 double GetExpectationValue() {
138 if (lib) {
139 return lib->PauliPropGetExpectationValue(obj);
140 }
141 return 0.0;
142 }
143
144 bool Execute() {
145 if (lib) {
146 return lib->PauliPropExecute(obj);
147 }
148 return false;
149 }
150
151 double ExpectationValue(const std::string &pauliStr) {
152 SetInPauliExpansionUnique(pauliStr);
153 Execute();
154 return GetExpectationValue();
155 }
156
157 double ExpectationValueMultiple(const std::vector<std::string> &pauliStrs,
158 const std::vector<double> &coefficients) {
159 SetInPauliExpansionMultiple(pauliStrs, coefficients);
160 Execute();
161 return GetExpectationValue();
162 }
163
164 bool SetInPauliExpansionUnique(const std::string &pauliStr) {
165 if (lib) {
166 return lib->PauliPropSetInPauliExpansionUnique(obj, pauliStr.c_str());
167 }
168 return false;
169 }
170
171 bool SetInPauliExpansionMultiple(const std::vector<std::string> &pauliStrs,
172 const std::vector<double> &coefficients) {
173 if (lib && !pauliStrs.empty() && pauliStrs.size() == coefficients.size()) {
174 std::vector<char *> cStrs(pauliStrs.size());
175 for (size_t i = 0; i < pauliStrs.size(); ++i) {
176 cStrs[i] = const_cast<char *>(pauliStrs[i].c_str());
177 }
178 return lib->PauliPropSetInPauliExpansionMultiple(
179 obj, (const char **)cStrs.data(), coefficients.data(),
180 static_cast<int>(pauliStrs.size()));
181 }
182 return false;
183 }
184
185 bool ApplyX(int qubit) {
186 if (lib) {
187 return lib->PauliPropApplyX(obj, qubit);
188 }
189 return false;
190 }
191
192 bool ApplyY(int qubit) {
193 if (lib) {
194 return lib->PauliPropApplyY(obj, qubit);
195 }
196 return false;
197 }
198
199 bool ApplyZ(int qubit) {
200 if (lib) {
201 return lib->PauliPropApplyZ(obj, qubit);
202 }
203 return false;
204 }
205
206 bool ApplyH(int qubit) {
207 if (lib) {
208 return lib->PauliPropApplyH(obj, qubit);
209 }
210 return false;
211 }
212
213 bool ApplyS(int qubit) {
214 if (lib) {
215 return lib->PauliPropApplyS(obj, qubit);
216 }
217 return false;
218 }
219
220 bool ApplySQRTX(int qubit) {
221 if (lib) {
222 return lib->PauliPropApplySQRTX(obj, qubit);
223 }
224 return false;
225 }
226
227 bool ApplySQRTY(int qubit) {
228 if (lib) {
229 return lib->PauliPropApplySQRTY(obj, qubit);
230 }
231 return false;
232 }
233
234 bool ApplySQRTZ(int qubit) {
235 if (lib) {
236 return lib->PauliPropApplySQRTZ(obj, qubit);
237 }
238 return false;
239 }
240
241 bool ApplyCX(int controlQubit, int targetQubit) {
242 if (lib) {
243 return lib->PauliPropApplyCX(obj, controlQubit, targetQubit);
244 }
245 return false;
246 }
247
248 bool ApplyCY(int controlQubit, int targetQubit) {
249 if (lib) {
250 return lib->PauliPropApplyCY(obj, controlQubit, targetQubit);
251 }
252 return false;
253 }
254
255 bool ApplyCZ(int controlQubit, int targetQubit) {
256 if (lib) {
257 return lib->PauliPropApplyCZ(obj, controlQubit, targetQubit);
258 }
259 return false;
260 }
261
262 bool ApplySWAP(int qubit1, int qubit2) {
263 if (lib) {
264 return lib->PauliPropApplySWAP(obj, qubit1, qubit2);
265 }
266 return false;
267 }
268
269 bool ApplyISWAP(int qubit1, int qubit2) {
270 if (lib) {
271 return lib->PauliPropApplyISWAP(obj, qubit1, qubit2);
272 }
273 return false;
274 }
275
276 bool ApplyRX(int qubit, double angle) {
277 if (lib) {
278 return lib->PauliPropApplyRX(obj, qubit, angle);
279 }
280 return false;
281 }
282
283 bool ApplyRY(int qubit, double angle) {
284 if (lib) {
285 return lib->PauliPropApplyRY(obj, qubit, angle);
286 }
287 return false;
288 }
289
290 bool ApplyRZ(int qubit, double angle) {
291 if (lib) {
292 return lib->PauliPropApplyRZ(obj, qubit, angle);
293 }
294 return false;
295 }
296
297 bool ApplySDG(int qubit) {
298 if (!ApplyZ(qubit)) return false;
299 if (!ApplyS(qubit)) return false;
300
301 return true;
302 }
303
304 bool ApplyK(int qubit) {
305 if (!ApplyZ(qubit)) return false;
306 if (!ApplyS(qubit)) return false;
307 if (!ApplyH(qubit)) return false;
308 if (!ApplyS(qubit)) return false;
309
310 return true;
311 }
312
313 bool ApplySxDAG(int qubit) {
314 if (!ApplyS(qubit)) return false;
315 if (!ApplyH(qubit)) return false;
316 if (!ApplyS(qubit)) return false;
317 return true;
318 }
319
320 bool ApplyP(int qubit, double lambda) { return ApplyRZ(qubit, lambda); }
321
322 bool ApplyT(int qubit) { return ApplyRZ(qubit, M_PI_4); }
323
324 bool ApplyTDG(int qubit) { return ApplyRZ(qubit, -M_PI_4); }
325
326 bool ApplyU(int qubit, double theta, double phi, double lambda,
327 double gamma = 0.0) {
328 if (!ApplyRZ(qubit, lambda)) return false;
329 if (!ApplyRY(qubit, theta)) return false;
330 if (!ApplyRZ(qubit, phi)) return false;
331
332 return true;
333 }
334
335 bool ApplyCH(int controlQubit, int targetQubit) {
336 if (!ApplyH(targetQubit)) return false;
337 if (!ApplySDG(targetQubit)) return false;
338 if (!ApplyCX(controlQubit, targetQubit)) return false;
339 if (!ApplyH(targetQubit)) return false;
340 if (!ApplyT(targetQubit)) return false;
341 if (!ApplyCX(controlQubit, targetQubit)) return false;
342 if (!ApplyT(targetQubit)) return false;
343 if (!ApplyH(targetQubit)) return false;
344 if (!ApplyS(targetQubit)) return false;
345 if (!ApplyX(targetQubit)) return false;
346 if (!ApplyS(controlQubit)) return false;
347
348 return true;
349 }
350
351 bool ApplyCU(int controlQubit, int targetQubit, double theta, double phi,
352 double lambda, double gamma = 0.0) {
353 if (gamma != 0.0) {
354 if (!ApplyP(controlQubit, gamma)) return false;
355 }
356 const double lambdaPlusPhiHalf = 0.5 * (lambda + phi);
357 const double halfTheta = 0.5 * theta;
358 if (!ApplyP(targetQubit, 0.5 * (lambda - phi))) return false;
359 if (!ApplyP(controlQubit, lambdaPlusPhiHalf)) return false;
360 if (!ApplyCX(controlQubit, targetQubit)) return false;
361 if (!ApplyU(targetQubit, -halfTheta, 0, -lambdaPlusPhiHalf)) return false;
362 if (!ApplyCX(controlQubit, targetQubit)) return false;
363 if (!ApplyU(targetQubit, halfTheta, phi, 0)) return false;
364 return true;
365 }
366
367 bool ApplyCRX(int controlQubit, int targetQubit, double angle) {
368 const double halfAngle = angle * 0.5;
369 if (!ApplyH(targetQubit)) return false;
370 if (!ApplyCX(controlQubit, targetQubit)) return false;
371 if (!ApplyRZ(targetQubit, -halfAngle)) return false;
372 if (!ApplyCX(controlQubit, targetQubit)) return false;
373 if (!ApplyRZ(targetQubit, halfAngle)) return false;
374 if (!ApplyH(targetQubit)) return false;
375 return true;
376 }
377
378 bool ApplyCRY(int controlQubit, int targetQubit, double angle) {
379 const double halfAngle = angle * 0.5;
380 if (!ApplyRY(targetQubit, halfAngle)) return false;
381 if (!ApplyCX(controlQubit, targetQubit)) return false;
382 if (!ApplyRY(targetQubit, -halfAngle)) return false;
383 if (!ApplyCX(controlQubit, targetQubit)) return false;
384 return true;
385 }
386
387 bool ApplyCRZ(int controlQubit, int targetQubit, double angle) {
388 const double halfAngle = angle * 0.5;
389 if (!ApplyRZ(targetQubit, halfAngle)) return false;
390 if (!ApplyCX(controlQubit, targetQubit)) return false;
391 if (!ApplyRZ(targetQubit, -halfAngle)) return false;
392 if (!ApplyCX(controlQubit, targetQubit)) return false;
393 return true;
394 }
395
396 bool ApplyCP(int controlQubit, int targetQubit, double lambda) {
397 const double halfAngle = lambda * 0.5;
398 if (!ApplyP(controlQubit, halfAngle)) return false;
399 if (!ApplyCX(controlQubit, targetQubit)) return false;
400 if (!ApplyP(targetQubit, -halfAngle)) return false;
401 if (!ApplyCX(controlQubit, targetQubit)) return false;
402 if (!ApplyP(targetQubit, halfAngle)) return false;
403
404 return true;
405 }
406
407 bool ApplyCS(int controlQubit, int targetQubit) {
408 if (!ApplyT(controlQubit)) return false;
409 if (!ApplyT(targetQubit)) return false;
410 if (!ApplyCX(controlQubit, targetQubit)) return false;
411 if (!ApplyTDG(targetQubit)) return false;
412 if (!ApplyCX(controlQubit, targetQubit)) return false;
413
414 return true;
415 }
416
417 bool ApplyCSDAG(int controlQubit, int targetQubit) {
418 if (!ApplyCX(controlQubit, targetQubit)) return false;
419 if (!ApplyT(targetQubit)) return false;
420 if (!ApplyCX(controlQubit, targetQubit)) return false;
421 if (!ApplyTDG(controlQubit)) return false;
422 if (!ApplyTDG(targetQubit)) return false;
423
424 return true;
425 }
426
427 bool ApplyCSX(int controlQubit, int targetQubit) {
428 if (!ApplyH(targetQubit)) return false;
429 if (!ApplyCS(controlQubit, targetQubit)) return false;
430 if (!ApplyH(targetQubit)) return false;
431
432 return true;
433 }
434
435 bool ApplyCSXDAG(int controlQubit, int targetQubit) {
436 if (!ApplyH(targetQubit)) return false;
437 if (!ApplyCSDAG(controlQubit, targetQubit)) return false;
438 if (!ApplyH(targetQubit)) return false;
439
440 return true;
441 }
442
443 bool ApplyCSwap(int controlQubit, int targetQubit1, int targetQubit2) {
444 const size_t q1 = controlQubit; // control
445 const size_t q2 = targetQubit1;
446 const size_t q3 = targetQubit2;
447
448 if (!ApplyCX(q3, q2)) return false;
449 if (!ApplyCSX(q2, q3)) return false;
450 if (!ApplyCX(q1, q2)) return false;
451
452 if (!ApplyP(q3, M_PI)) return false;
453 if (!ApplyP(q2, -M_PI_2)) return false;
454
455 if (!ApplyCSX(q2, q3)) return false;
456 if (!ApplyCX(q1, q2)) return false;
457
458 if (!ApplyP(q3, M_PI)) return false;
459 if (!ApplyCSX(q1, q3)) return false;
460 if (!ApplyCX(q3, q2)) return false;
461
462 return true;
463 }
464
465 bool ApplyCCX(int controlQubit1, int controlQubit2, int targetQubit) {
466 const size_t q1 = controlQubit1; // control 1
467 const size_t q2 = controlQubit2; // control 2
468 const size_t q3 = targetQubit; // target
469
470 if (!ApplyCSX(q2, q3)) return false;
471 if (!ApplyCX(q1, q2)) return false;
472 if (!ApplyCSXDAG(q2, q3)) return false;
473 if (!ApplyCX(q1, q2)) return false;
474 if (!ApplyCSX(q1, q3)) return false;
475
476 return true;
477 }
478
479 // to implement all gates, add:
480 // see qasm paper for some decompositions
481 // for the three qubit gates, see the decompositions already done for mps
482 // qcsim
483 /*
484 kCSwapGateType, kCCXGateType,
485 */
486
487 bool AddNoiseX(int qubit, double probability) {
488 if (lib) {
489 return lib->PauliPropAddNoiseX(obj, qubit, probability);
490 }
491 return false;
492 }
493
494 bool AddNoiseY(int qubit, double probability) {
495 if (lib) {
496 return lib->PauliPropAddNoiseY(obj, qubit, probability);
497 }
498 return false;
499 }
500
501 bool AddNoiseZ(int qubit, double probability) {
502 if (lib) {
503 return lib->PauliPropAddNoiseZ(obj, qubit, probability);
504 }
505 return false;
506 }
507
508 bool AddNoiseXYZ(int qubit, double px, double py, double pz) {
509 if (lib) {
510 return lib->PauliPropAddNoiseXYZ(obj, qubit, px, py, pz);
511 }
512 return false;
513 }
514
515 bool AddAmplitudeDamping(int qubit, double dampingProb, double exciteProb) {
516 if (lib) {
517 return lib->PauliPropAddAmplitudeDamping(obj, qubit, dampingProb,
518 exciteProb);
519 }
520 return false;
521 }
522
523 double QubitProbability0(int qubit) {
524 if (lib) {
525 return lib->PauliPropQubitProbability0(obj, qubit);
526 }
527 return 0.0;
528 }
529
530 double Probability(unsigned long long int outcome) {
531 if (lib) {
532 return lib->PauliPropProbability(obj, outcome);
533 }
534 return 0.0;
535 }
536
537 bool MeasureQubit(int qubit) {
538 if (lib) {
539 return lib->PauliPropMeasureQubit(obj, qubit);
540 }
541 return false;
542 }
543
544 std::vector<bool> SampleQubits(const std::vector<int> &qubits) {
545 std::vector<bool> results;
546 if (lib && !qubits.empty()) {
547 std::vector<int> cQubits = qubits;
548 unsigned char *res = lib->PauliPropSampleQubits(
549 obj, qubits.data(), static_cast<int>(cQubits.size()));
550 if (!res) return results;
551
552 results.reserve(cQubits.size());
553 for (size_t i = 0; i < cQubits.size(); ++i) {
554 // results are encoded as bits
555 const bool bit = ((res[i / 8] >> (i % 8)) & 1) == 1;
556 results.push_back(bit);
557 }
558
559 lib->PauliPropFreeSampledQubits(res);
560 }
561 return results;
562 }
563
564 void SaveState() {
565 if (lib) {
566 lib->PauliPropSaveState(obj);
567 }
568 }
569
570 void RestoreState() {
571 if (lib) {
572 lib->PauliPropRestoreState(obj);
573 }
574 }
575
576 private:
577 std::shared_ptr<GpuLibrary> lib;
578 void *obj;
579};
580
581} // namespace Simulators
582
583#endif
584#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)