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)
29 : lib(lib), obj(
nullptr) {}
31 GpuPauliPropagator() =
delete;
32 GpuPauliPropagator(
const GpuPauliPropagator &) =
delete;
33 GpuPauliPropagator &operator=(
const GpuPauliPropagator &) =
delete;
34 GpuPauliPropagator(GpuPauliPropagator &&) =
default;
35 GpuPauliPropagator &operator=(GpuPauliPropagator &&) =
default;
37 ~GpuPauliPropagator() {
38 if (lib && obj) lib->DestroyPauliPropSimulator(obj);
43 obj = lib->CreatePauliPropSimulator(numQubits);
45 return obj !=
nullptr;
52 return lib->PauliPropGetNrQubits(obj);
57 bool SetWillUseSampling(
bool willUseSampling) {
59 return lib->PauliPropSetWillUseSampling(obj, willUseSampling) == 1;
64 bool GetWillUseSampling() {
66 return lib->PauliPropGetWillUseSampling(obj) == 1;
71 double GetCoefficientTruncationCutoff() {
73 return lib->PauliPropGetCoefficientTruncationCutoff(obj);
78 void SetCoefficientTruncationCutoff(
double cutoff) {
80 lib->PauliPropSetCoefficientTruncationCutoff(obj, cutoff);
84 double GetWeightTruncationCutoff() {
86 return lib->PauliPropGetWeightTruncationCutoff(obj);
91 void SetWeightTruncationCutoff(
double cutoff) {
93 lib->PauliPropSetWeightTruncationCutoff(obj, cutoff);
97 int GetNumGatesBetweenTruncations() {
99 return lib->PauliPropGetNumGatesBetweenTruncations(obj);
104 void SetNumGatesBetweenTruncations(
int numGates) {
106 lib->PauliPropSetNumGatesBetweenTruncations(obj, numGates);
110 int GetNumGatesBetweenDeduplications() {
112 return lib->PauliPropGetNumGatesBetweenDeduplications(obj);
117 void SetNumGatesBetweenDeduplications(
int numGates) {
119 lib->PauliPropSetNumGatesBetweenDeduplications(obj, numGates);
123 bool ClearOperators() {
125 return lib->PauliPropClearOperators(obj);
130 bool AllocateMemory(
double percentage) {
132 return lib->PauliPropAllocateMemory(obj, percentage);
137 double GetExpectationValue() {
139 return lib->PauliPropGetExpectationValue(obj);
146 return lib->PauliPropExecute(obj);
151 double ExpectationValue(
const std::string &pauliStr) {
152 SetInPauliExpansionUnique(pauliStr);
154 return GetExpectationValue();
157 double ExpectationValueMultiple(
const std::vector<std::string> &pauliStrs,
158 const std::vector<double> &coefficients) {
159 SetInPauliExpansionMultiple(pauliStrs, coefficients);
161 return GetExpectationValue();
164 bool SetInPauliExpansionUnique(
const std::string &pauliStr) {
166 return lib->PauliPropSetInPauliExpansionUnique(obj, pauliStr.c_str());
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());
178 return lib->PauliPropSetInPauliExpansionMultiple(
179 obj, (
const char **)cStrs.data(), coefficients.data(),
180 static_cast<int>(pauliStrs.size()));
187 return lib->PauliPropApplyX(obj, qubit);
194 return lib->PauliPropApplyY(obj, qubit);
201 return lib->PauliPropApplyZ(obj, qubit);
208 return lib->PauliPropApplyH(obj, qubit);
215 return lib->PauliPropApplyS(obj, qubit);
220 bool ApplySQRTX(
int qubit) {
222 return lib->PauliPropApplySQRTX(obj, qubit);
227 bool ApplySQRTY(
int qubit) {
229 return lib->PauliPropApplySQRTY(obj, qubit);
234 bool ApplySQRTZ(
int qubit) {
236 return lib->PauliPropApplySQRTZ(obj, qubit);
241 bool ApplyCX(
int controlQubit,
int targetQubit) {
243 return lib->PauliPropApplyCX(obj, controlQubit, targetQubit);
248 bool ApplyCY(
int controlQubit,
int targetQubit) {
250 return lib->PauliPropApplyCY(obj, controlQubit, targetQubit);
255 bool ApplyCZ(
int controlQubit,
int targetQubit) {
257 return lib->PauliPropApplyCZ(obj, controlQubit, targetQubit);
262 bool ApplySWAP(
int qubit1,
int qubit2) {
264 return lib->PauliPropApplySWAP(obj, qubit1, qubit2);
269 bool ApplyISWAP(
int qubit1,
int qubit2) {
271 return lib->PauliPropApplyISWAP(obj, qubit1, qubit2);
276 bool ApplyRX(
int qubit,
double angle) {
278 return lib->PauliPropApplyRX(obj, qubit, angle);
283 bool ApplyRY(
int qubit,
double angle) {
285 return lib->PauliPropApplyRY(obj, qubit, angle);
290 bool ApplyRZ(
int qubit,
double angle) {
292 return lib->PauliPropApplyRZ(obj, qubit, angle);
298 if (!
ApplyZ(qubit))
return false;
299 if (!
ApplyS(qubit))
return false;
305 if (!
ApplyZ(qubit))
return false;
306 if (!
ApplyS(qubit))
return false;
307 if (!
ApplyH(qubit))
return false;
308 if (!
ApplyS(qubit))
return false;
313 bool ApplySxDAG(
int qubit) {
314 if (!
ApplyS(qubit))
return false;
315 if (!
ApplyH(qubit))
return false;
316 if (!
ApplyS(qubit))
return false;
320 bool ApplyP(
int qubit,
double lambda) {
return ApplyRZ(qubit, lambda); }
322 bool ApplyT(
int qubit) {
return ApplyRZ(qubit, M_PI_4); }
324 bool ApplyTDG(
int qubit) {
return ApplyRZ(qubit, -M_PI_4); }
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;
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;
351 bool ApplyCU(
int controlQubit,
int targetQubit,
double theta,
double phi,
352 double lambda,
double gamma = 0.0) {
354 if (!
ApplyP(controlQubit, gamma))
return false;
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;
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;
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;
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;
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;
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;
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;
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;
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;
443 bool ApplyCSwap(
int controlQubit,
int targetQubit1,
int targetQubit2) {
444 const size_t q1 = controlQubit;
445 const size_t q2 = targetQubit1;
446 const size_t q3 = targetQubit2;
448 if (!
ApplyCX(q3, q2))
return false;
449 if (!
ApplyCSX(q2, q3))
return false;
450 if (!
ApplyCX(q1, q2))
return false;
452 if (!
ApplyP(q3, M_PI))
return false;
453 if (!
ApplyP(q2, -M_PI_2))
return false;
455 if (!
ApplyCSX(q2, q3))
return false;
456 if (!
ApplyCX(q1, q2))
return false;
458 if (!
ApplyP(q3, M_PI))
return false;
459 if (!
ApplyCSX(q1, q3))
return false;
460 if (!
ApplyCX(q3, q2))
return false;
465 bool ApplyCCX(
int controlQubit1,
int controlQubit2,
int targetQubit) {
466 const size_t q1 = controlQubit1;
467 const size_t q2 = controlQubit2;
468 const size_t q3 = targetQubit;
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;
487 bool AddNoiseX(
int qubit,
double probability) {
489 return lib->PauliPropAddNoiseX(obj, qubit, probability);
494 bool AddNoiseY(
int qubit,
double probability) {
496 return lib->PauliPropAddNoiseY(obj, qubit, probability);
501 bool AddNoiseZ(
int qubit,
double probability) {
503 return lib->PauliPropAddNoiseZ(obj, qubit, probability);
508 bool AddNoiseXYZ(
int qubit,
double px,
double py,
double pz) {
510 return lib->PauliPropAddNoiseXYZ(obj, qubit, px, py, pz);
515 bool AddAmplitudeDamping(
int qubit,
double dampingProb,
double exciteProb) {
517 return lib->PauliPropAddAmplitudeDamping(obj, qubit, dampingProb,
523 double QubitProbability0(
int qubit) {
525 return lib->PauliPropQubitProbability0(obj, qubit);
530 double Probability(
unsigned long long int outcome) {
532 return lib->PauliPropProbability(obj, outcome);
537 bool MeasureQubit(
int qubit) {
539 return lib->PauliPropMeasureQubit(obj, qubit);
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;
552 results.reserve(cQubits.size());
553 for (
size_t i = 0; i < cQubits.size(); ++i) {
555 const bool bit = ((res[i / 8] >> (i % 8)) & 1) == 1;
556 results.push_back(bit);
559 lib->PauliPropFreeSampledQubits(res);
566 lib->PauliPropSaveState(obj);
572 lib->PauliPropRestoreState(obj);
577 std::shared_ptr<GpuLibrary> 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)