6#ifndef _GPU_DENSITY_MATRIX_H_
7#define _GPU_DENSITY_MATRIX_H_
22class GpuDensityMatrix {
24 explicit GpuDensityMatrix(
const std::shared_ptr<GpuLibrary>& lib,
int device = -1)
25 : lib(lib), obj(
nullptr) {
27 auto lock = lib->LockInitialization();
28 if (lib->SetGpuDevice(device == -1 ? lib->GetCreationDevice() : device))
29 obj = lib->CreateDensityMatrix();
33 int GetGpuDevice()
const {
return lib ? lib->DMGetGpuId(obj) : -1; }
35 GpuDensityMatrix(
const std::shared_ptr<GpuLibrary>& lib,
void* obj)
36 : lib(lib), obj(obj) {}
37 GpuDensityMatrix() =
delete;
38 GpuDensityMatrix(
const GpuDensityMatrix&) =
delete;
39 GpuDensityMatrix& operator=(
const GpuDensityMatrix&) =
delete;
40 ~GpuDensityMatrix() {
if (lib && obj) lib->DestroyDensityMatrix(obj); }
42 bool Create(
unsigned int n) {
return lib->DMCreate(obj, n); }
43 bool CreateWithState(
unsigned int n,
const double* state) {
44 return lib->DMCreateWithState(obj, n, state);
46 bool CreateWithBasisState(
unsigned int n,
unsigned long long state) {
47 return lib->DMCreateWithBasisState(obj, n, state);
49 bool CreateWithMixtureOfBasisStates(
51 const std::vector<std::pair<unsigned long long, double>>& mixture) {
52 std::vector<unsigned long long> states;
53 std::vector<double> weights;
54 states.reserve(mixture.size());
55 weights.reserve(mixture.size());
56 for (
const auto& [state, weight] : mixture) {
57 states.push_back(state);
58 weights.push_back(weight);
60 return lib->DMCreateWithMixtureOfBasisStates(
61 obj, n, states.data(), weights.data(),
62 static_cast<int>(states.size()));
65 if (!lib->DMReset(obj))
66 throw std::runtime_error(
"GPU density-matrix reset failed");
68 bool SetSeed(uint64_t seed) {
return lib->DMSetSeed(obj, seed); }
69 bool IsCreated()
const {
return lib->DMIsCreated(obj); }
70 void SetDataType(
bool useDouble) {
71 if (!lib->DMSetDataType(obj, useDouble))
72 throw std::runtime_error(
73 "GPU density-matrix precision configuration failed");
75 bool Measure(
unsigned int q) {
return lib->DMMeasureQubitCollapse(obj, q); }
76 bool MeasureNoCollapse(
unsigned int q) {
return lib->DMMeasureQubitNoCollapse(obj, q); }
77 bool MeasureQubits(std::vector<int>& qubits, std::vector<int>& bits,
bool collapse =
true) {
78 if (qubits.size() != bits.size())
throw std::invalid_argument(
"Measurement vectors must have equal size");
79 return collapse ? lib->DMMeasureQubitsCollapse(obj, qubits.data(), bits.data(),
static_cast<int>(bits.size()))
80 : lib->DMMeasureQubitsNoCollapse(obj, qubits.data(), bits.data(),
static_cast<int>(bits.size()));
82 unsigned long long MeasureAll(
bool collapse =
true) {
return collapse ? lib->DMMeasureAllQubitsCollapse(obj) : lib->DMMeasureAllQubitsNoCollapse(obj); }
83 bool Sample(
unsigned int n,
long int* samples,
unsigned int nBits,
int* order) {
return lib->DMSample(obj, n, samples, nBits, order); }
84 bool SampleAll(
unsigned int shots,
long int* samples) {
85 return lib->DMSampleAll(obj, shots, samples);
88 return lib->DMBasisStateProbability(obj, outcome);
90 std::complex<double> GetElement(
long long row,
long long col)
const {
91 double re = 0., im = 0.;
92 if (!lib->DMGetElement(obj, row, col, &re, &im))
throw std::runtime_error(
"GPU density-matrix element query failed");
96 if (!lib->DMAllProbabilities(obj, probabilities))
97 throw std::runtime_error(
98 "GPU density-matrix probability enumeration failed");
100 double ExpectationValue(
const std::string& pauli)
const {
101 return lib->DMExpectationValue(obj, pauli.c_str(), pauli.size());
103 double QubitProbability0(
unsigned int q)
const {
return lib->DMQubitProbability0(obj, q); }
104 double Trace()
const {
return lib->DMTrace(obj); }
105 double Purity()
const {
return lib->DMPurity(obj); }
106 bool IsHermitian(
double eps = 1e-10)
const {
return lib->DMIsHermitian(obj, eps); }
107 std::vector<std::complex<double>> PartialTrace(
const std::vector<int>& qubits)
const {
108 const size_t dim =
size_t{1} << qubits.size();
109 std::vector<double> raw(2 * dim * dim);
110 if (!lib->DMPartialTrace(obj, qubits.data(),
static_cast<int>(qubits.size()), raw.data()))
111 throw std::runtime_error(
"GPU density-matrix partial trace failed");
112 std::vector<std::complex<double>> result(dim * dim);
113 for (
size_t i = 0; i < result.size(); ++i) result[i] = {raw[2*i], raw[2*i+1]};
116 std::complex<double> HilbertSchmidtOverlap(
const GpuDensityMatrix& other)
const {
117 double re = 0., im = 0.;
118 if (!lib->DMHilbertSchmidtOverlap(obj, other.obj, &re, &im))
119 throw std::runtime_error(
"GPU density-matrix overlap failed");
122 double FidelityWithStatevector(
const double* state)
const {
124 if (!lib->DMFidelityWithStatevector(obj, state, &result))
125 throw std::runtime_error(
"GPU density-matrix fidelity failed");
129 if (!lib->DMSaveState(obj))
130 throw std::runtime_error(
"GPU density-matrix state save failed");
133 if (!lib->DMRestoreState(obj))
134 throw std::runtime_error(
"GPU density-matrix state restore failed");
136 void CleanSavedState() {
137 if (!lib->DMCleanSavedState(obj))
138 throw std::runtime_error(
"GPU density-matrix saved-state cleanup failed");
140 std::unique_ptr<GpuDensityMatrix> Clone()
const {
141 void* cloned = lib->DMClone(obj);
142 if (!cloned)
return nullptr;
143 return std::make_unique<GpuDensityMatrix>(lib, cloned);
145 bool ApplyKraus(
const std::vector<int>& qubits,
int count,
146 const double* operators) {
147 return lib->DMApplyKraus(obj, qubits.size(), qubits.data(), count,
151#define GPU_DM_CHECK(call, name) \
154 throw std::runtime_error("GPU density-matrix " name " failed"); \
156#define GPU_DM_GATE1(name) \
157 void name(int q) { GPU_DM_CHECK(lib->DM##name(obj, q), #name); }
158#define GPU_DM_GATE2(name) \
159 void name(int a, int b) { GPU_DM_CHECK(lib->DM##name(obj, a, b), #name); }
160#define GPU_DM_ROT1(name) \
161 void name(int q, double x) { GPU_DM_CHECK(lib->DM##name(obj, q, x), #name); }
162#define GPU_DM_ROT2(name) \
163 void name(int a, int b, double x) { \
164 GPU_DM_CHECK(lib->DM##name(obj, a, b, x), #name); \
167 GPU_DM_ROT1(ApplyBitFlipNoise) GPU_DM_ROT1(ApplyPhaseFlipNoise)
168 GPU_DM_ROT1(ApplyDepolarizingNoise) GPU_DM_ROT1(ApplyAmplitudeDamping)
169 GPU_DM_ROT1(ApplyPhaseDamping) GPU_DM_GATE1(ApplyNonSelectiveMeasurement)
176 void ApplyU(
int q,
double a,
double b,
double c,
double d) {
177 GPU_DM_CHECK(lib->DMApplyU(obj, q, a, b, c, d),
"ApplyU");
183 void ApplyCCX(
int a,
int b,
int c) {
184 GPU_DM_CHECK(lib->DMApplyCCX(obj, a, b, c),
"ApplyCCX");
188 GPU_DM_CHECK(lib->DMApplyCSwap(obj, a, b, c),
"ApplyCSwap");
190 void ApplyCU(
int a,
int b,
double c,
double d,
double e,
double f) {
191 GPU_DM_CHECK(lib->DMApplyCU(obj, a, b, c, d, e, f),
"ApplyCU");
200 GpuDeviceContext lib;
int ApplyK(void *sim, int qubit)
double Probability(void *sim, unsigned long long int outcome)
int RestoreState(void *sim)
int ApplyRx(void *sim, int qubit, double theta)
int ApplyReset(void *sim, const unsigned long int *qubits, unsigned long int nrQubits)
int ApplyX(void *sim, int qubit)
int ApplyU(void *sim, int qubit, double theta, double phi, double lambda, double gamma)
int ApplyCRy(void *sim, int controlQubit, int targetQubit, double theta)
int ApplyTDG(void *sim, int qubit)
int ApplyCSXDG(void *sim, int controlQubit, int targetQubit)
int ApplyS(void *sim, int qubit)
int ApplyCX(void *sim, int controlQubit, int targetQubit)
int ApplyCRz(void *sim, int controlQubit, int targetQubit, double theta)
double * AllProbabilities(void *sim)
unsigned long long int MeasureNoCollapse(void *sim)
int ApplyCP(void *sim, int controlQubit, int targetQubit, double theta)
int ApplySXDG(void *sim, int qubit)
int ApplySDG(void *sim, int qubit)
unsigned long long int Measure(void *sim, const unsigned long int *qubits, unsigned long int nrQubits)
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 ApplySwap(void *sim, int qubit1, int qubit2)
int ApplyRy(void *sim, int qubit, double theta)
int ApplyP(void *sim, int qubit, double theta)
int ApplyCH(void *sim, int controlQubit, int targetQubit)
int ApplySX(void *sim, int qubit)
int ApplyCZ(void *sim, int controlQubit, int targetQubit)
int ApplyRz(void *sim, int qubit, double theta)
int ApplyT(void *sim, int qubit)
int ApplyCRx(void *sim, int controlQubit, int targetQubit, double theta)
int ApplyCSX(void *sim, int controlQubit, int targetQubit)