14#ifndef _GPU_PAULI_PROPAGATOR_H
15#define _GPU_PAULI_PROPAGATOR_H 1
21#define _USE_MATH_DEFINES
26class GpuPauliPropagator {
28 explicit GpuPauliPropagator(
const std::shared_ptr<GpuLibrary> &lib,
int device = -1)
29 : device(device == -1 && lib ? lib->GetCreationDevice() : device), lib(lib), obj(
nullptr) {}
31 int GetGpuDevice()
const {
return lib ? lib->PauliPropGetGpuId(obj) : -1; }
33 GpuPauliPropagator() =
delete;
34 GpuPauliPropagator(
const GpuPauliPropagator &) =
delete;
35 GpuPauliPropagator &operator=(
const GpuPauliPropagator &) =
delete;
36 GpuPauliPropagator(GpuPauliPropagator &&) =
default;
37 GpuPauliPropagator &operator=(GpuPauliPropagator &&) =
default;
39 ~GpuPauliPropagator() {
40 if (lib && obj) lib->DestroyPauliPropSimulator(obj);
45 auto lock = lib->LockInitialization();
46 if (!lib->SetGpuDevice(device))
return false;
47 if (obj) lib->DestroyPauliPropSimulator(obj);
49 obj = lib->CreatePauliPropSimulator(numQubits);
51 return obj !=
nullptr;
58 return lib->PauliPropGetNrQubits(obj);
63 bool SetSeed(uint64_t seed) {
64 return lib && obj && lib->PauliPropSetSeed(obj, seed);
67 bool SetWillUseSampling(
bool willUseSampling) {
69 return lib->PauliPropSetWillUseSampling(obj, willUseSampling) == 1;
74 bool GetWillUseSampling() {
76 return lib->PauliPropGetWillUseSampling(obj) == 1;
81 double GetCoefficientTruncationCutoff() {
83 return lib->PauliPropGetCoefficientTruncationCutoff(obj);
88 void SetCoefficientTruncationCutoff(
double cutoff) {
90 lib->PauliPropSetCoefficientTruncationCutoff(obj, cutoff);
94 double GetWeightTruncationCutoff() {
96 return lib->PauliPropGetWeightTruncationCutoff(obj);
101 void SetWeightTruncationCutoff(
double cutoff) {
103 lib->PauliPropSetWeightTruncationCutoff(obj, cutoff);
107 int GetNumGatesBetweenTruncations() {
109 return lib->PauliPropGetNumGatesBetweenTruncations(obj);
114 void SetNumGatesBetweenTruncations(
int numGates) {
116 lib->PauliPropSetNumGatesBetweenTruncations(obj, numGates);
120 int GetNumGatesBetweenDeduplications() {
122 return lib->PauliPropGetNumGatesBetweenDeduplications(obj);
127 void SetNumGatesBetweenDeduplications(
int numGates) {
129 lib->PauliPropSetNumGatesBetweenDeduplications(obj, numGates);
133 bool ClearOperators() {
135 return lib->PauliPropClearOperators(obj);
140 bool AllocateMemory(
double percentage) {
142 return lib->PauliPropAllocateMemory(obj, percentage);
147 double GetExpectationValue() {
149 return lib->PauliPropGetExpectationValue(obj);
156 return lib->PauliPropExecute(obj);
161 double ExpectationValue(
const std::string &pauliStr) {
162 SetInPauliExpansionUnique(pauliStr);
164 return GetExpectationValue();
167 double ExpectationValueMultiple(
const std::vector<std::string> &pauliStrs,
168 const std::vector<double> &coefficients) {
169 SetInPauliExpansionMultiple(pauliStrs, coefficients);
171 return GetExpectationValue();
174 bool SetInPauliExpansionUnique(
const std::string &pauliStr) {
176 return lib->PauliPropSetInPauliExpansionUnique(obj, pauliStr.c_str());
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());
188 return lib->PauliPropSetInPauliExpansionMultiple(
189 obj, (
const char **)cStrs.data(), coefficients.data(),
190 static_cast<int>(pauliStrs.size()));
197 return lib->PauliPropApplyX(obj, qubit);
204 return lib->PauliPropApplyY(obj, qubit);
211 return lib->PauliPropApplyZ(obj, qubit);
218 return lib->PauliPropApplyH(obj, qubit);
225 return lib->PauliPropApplyS(obj, qubit);
230 bool ApplySQRTX(
int qubit) {
232 return lib->PauliPropApplySQRTX(obj, qubit);
237 bool ApplySQRTY(
int qubit) {
239 return lib->PauliPropApplySQRTY(obj, qubit);
244 bool ApplySQRTZ(
int qubit) {
246 return lib->PauliPropApplySQRTZ(obj, qubit);
251 bool ApplyCX(
int controlQubit,
int targetQubit) {
253 return lib->PauliPropApplyCX(obj, controlQubit, targetQubit);
258 bool ApplyCY(
int controlQubit,
int targetQubit) {
260 return lib->PauliPropApplyCY(obj, controlQubit, targetQubit);
265 bool ApplyCZ(
int controlQubit,
int targetQubit) {
267 return lib->PauliPropApplyCZ(obj, controlQubit, targetQubit);
272 bool ApplySWAP(
int qubit1,
int qubit2) {
274 return lib->PauliPropApplySWAP(obj, qubit1, qubit2);
279 bool ApplyISWAP(
int qubit1,
int qubit2) {
281 return lib->PauliPropApplyISWAP(obj, qubit1, qubit2);
286 bool ApplyRX(
int qubit,
double angle) {
288 return lib->PauliPropApplyRX(obj, qubit, angle);
293 bool ApplyRY(
int qubit,
double angle) {
295 return lib->PauliPropApplyRY(obj, qubit, angle);
300 bool ApplyRZ(
int qubit,
double angle) {
302 return lib->PauliPropApplyRZ(obj, qubit, angle);
308 if (!
ApplyZ(qubit))
return false;
309 if (!
ApplyS(qubit))
return false;
315 if (!
ApplyZ(qubit))
return false;
316 if (!
ApplyS(qubit))
return false;
317 if (!
ApplyH(qubit))
return false;
318 if (!
ApplyS(qubit))
return false;
323 bool ApplySxDAG(
int qubit) {
324 if (!
ApplyS(qubit))
return false;
325 if (!
ApplyH(qubit))
return false;
326 if (!
ApplyS(qubit))
return false;
330 bool ApplyP(
int qubit,
double lambda) {
return ApplyRZ(qubit, lambda); }
332 bool ApplyT(
int qubit) {
return ApplyRZ(qubit, M_PI_4); }
334 bool ApplyTDG(
int qubit) {
return ApplyRZ(qubit, -M_PI_4); }
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;
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;
361 bool ApplyCU(
int controlQubit,
int targetQubit,
double theta,
double phi,
362 double lambda,
double gamma = 0.0) {
364 if (!
ApplyP(controlQubit, gamma))
return false;
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;
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;
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;
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;
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;
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;
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;
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;
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;
453 bool ApplyCSwap(
int controlQubit,
int targetQubit1,
int targetQubit2) {
454 const size_t q1 = controlQubit;
455 const size_t q2 = targetQubit1;
456 const size_t q3 = targetQubit2;
458 if (!
ApplyCX(q3, q2))
return false;
459 if (!
ApplyCSX(q2, q3))
return false;
460 if (!
ApplyCX(q1, q2))
return false;
462 if (!
ApplyP(q3, M_PI))
return false;
463 if (!
ApplyP(q2, -M_PI_2))
return false;
465 if (!
ApplyCSX(q2, q3))
return false;
466 if (!
ApplyCX(q1, q2))
return false;
468 if (!
ApplyP(q3, M_PI))
return false;
469 if (!
ApplyCSX(q1, q3))
return false;
470 if (!
ApplyCX(q3, q2))
return false;
475 bool ApplyCCX(
int controlQubit1,
int controlQubit2,
int targetQubit) {
476 const size_t q1 = controlQubit1;
477 const size_t q2 = controlQubit2;
478 const size_t q3 = targetQubit;
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;
497 bool AddNoiseX(
int qubit,
double probability) {
499 return lib->PauliPropAddNoiseX(obj, qubit, probability);
504 bool AddNoiseY(
int qubit,
double probability) {
506 return lib->PauliPropAddNoiseY(obj, qubit, probability);
511 bool AddNoiseZ(
int qubit,
double probability) {
513 return lib->PauliPropAddNoiseZ(obj, qubit, probability);
518 bool AddNoiseXYZ(
int qubit,
double px,
double py,
double pz) {
520 return lib->PauliPropAddNoiseXYZ(obj, qubit, px, py, pz);
525 bool AddAmplitudeDamping(
int qubit,
double dampingProb,
double exciteProb) {
527 return lib->PauliPropAddAmplitudeDamping(obj, qubit, dampingProb,
533 double QubitProbability0(
int qubit) {
535 return lib->PauliPropQubitProbability0(obj, qubit);
540 double Probability(
unsigned long long int outcome) {
542 return lib->PauliPropProbability(obj, outcome);
547 bool MeasureQubit(
int qubit) {
549 return lib->PauliPropMeasureQubit(obj, qubit);
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;
562 results.reserve(cQubits.size());
563 for (
size_t i = 0; i < cQubits.size(); ++i) {
565 const bool bit = ((res[i / 8] >> (i % 8)) & 1) == 1;
566 results.push_back(bit);
569 lib->PauliPropFreeSampledQubits(res);
576 lib->PauliPropSaveState(obj);
582 lib->PauliPropRestoreState(obj);
588 GpuDeviceContext lib;
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)