6#ifndef _GPU_DENSITY_MATRIX_H_
7#define _GPU_DENSITY_MATRIX_H_
26 explicit GpuDensityMatrix(
const std::shared_ptr<GpuLibrary> &lib,
int device = -1) : lib(lib), obj(
nullptr)
30 auto lock = lib->LockInitialization();
31 if (lib->SetGpuDevice(device == -1 ? lib->GetCreationDevice() : device))
32 obj = lib->CreateDensityMatrix();
36 int GetGpuDevice()
const
38 return lib ? lib->DMGetGpuId(obj) : -1;
41 GpuDensityMatrix(
const std::shared_ptr<GpuLibrary> &lib,
void *obj) : lib(lib), obj(obj)
45 GpuDensityMatrix() =
delete;
46 GpuDensityMatrix(
const GpuDensityMatrix &) =
delete;
47 GpuDensityMatrix &operator=(
const GpuDensityMatrix &) =
delete;
52 lib->DestroyDensityMatrix(obj);
55 bool Create(
unsigned int n)
57 return lib->DMCreate(obj, n);
60 bool CreateWithState(
unsigned int n,
const double *state)
62 return lib->DMCreateWithState(obj, n, state);
65 bool CreateWithBasisState(
unsigned int n,
unsigned long long state)
67 return lib->DMCreateWithBasisState(obj, n, state);
70 bool CreateWithMixtureOfBasisStates(
unsigned int n,
const std::vector<std::pair<unsigned long long, double>> &mixture)
72 std::vector<unsigned long long> states;
73 std::vector<double> weights;
74 states.reserve(mixture.size());
75 weights.reserve(mixture.size());
76 for (
const auto &[state, weight] : mixture)
78 states.push_back(state);
79 weights.push_back(weight);
81 return lib->DMCreateWithMixtureOfBasisStates(obj, n, states.data(), weights.data(),
static_cast<int>(states.size()));
86 return lib->DMSynchronize(obj);
91 if (!lib->DMReset(obj))
92 throw std::runtime_error(
"GPU density-matrix reset failed");
95 bool SetSeed(uint64_t seed)
97 return lib->DMSetSeed(obj, seed);
100 bool IsCreated()
const
102 return lib->DMIsCreated(obj);
105 bool IsDoublePrecision()
const
107 return lib->DMIsDoublePrecision(obj);
110 void SetDataType(
bool useDouble)
112 if (!lib->DMSetDataType(obj, useDouble))
113 throw std::runtime_error(
"GPU density-matrix precision configuration failed");
118 return lib->DMMeasureQubitCollapse(obj, q);
123 return lib->DMMeasureQubitNoCollapse(obj, q);
126 bool MeasureQubits(std::vector<int> &qubits, std::vector<int> &bits,
bool collapse =
true)
128 if (qubits.size() != bits.size())
129 throw std::invalid_argument(
"Measurement vectors must have equal size");
130 return collapse ? lib->DMMeasureQubitsCollapse(obj, qubits.data(), bits.data(),
static_cast<int>(bits.size()))
131 : lib->DMMeasureQubitsNoCollapse(obj, qubits.data(), bits.data(),
static_cast<int>(bits.size()));
134 unsigned long long MeasureAll(
bool collapse =
true)
136 return collapse ? lib->DMMeasureAllQubitsCollapse(obj) : lib->DMMeasureAllQubitsNoCollapse(obj);
139 bool Sample(
unsigned int n,
long int *samples,
unsigned int nBits,
int *order)
141 return lib->DMSample(obj, n, samples, nBits, order);
144 bool SampleAll(
unsigned int shots,
long int *samples)
146 return lib->DMSampleAll(obj, shots, samples);
151 return lib->DMBasisStateProbability(obj, outcome);
154 std::complex<double> GetElement(
long long row,
long long col)
const
156 double re = 0., im = 0.;
157 if (!lib->DMGetElement(obj, row, col, &re, &im))
158 throw std::runtime_error(
"GPU density-matrix element query failed");
164 if (!lib->DMAllProbabilities(obj, probabilities))
165 throw std::runtime_error(
"GPU density-matrix probability enumeration failed");
168 double ExpectationValue(
const std::string &pauli)
const
170 return lib->DMExpectationValue(obj, pauli.c_str(), pauli.size());
173 double QubitProbability0(
unsigned int q)
const
175 return lib->DMQubitProbability0(obj, q);
180 return lib->DMTrace(obj);
183 double Purity()
const
185 return lib->DMPurity(obj);
188 bool IsHermitian(
double eps = 1e-10)
const
190 return lib->DMIsHermitian(obj, eps);
193 std::vector<std::complex<double>> PartialTrace(
const std::vector<int> &qubits)
const
195 const size_t dim =
size_t{1} << qubits.size();
196 std::vector<double> raw(2 * dim * dim);
197 if (!lib->DMPartialTrace(obj, qubits.data(),
static_cast<int>(qubits.size()), raw.data()))
198 throw std::runtime_error(
"GPU density-matrix partial trace failed");
199 std::vector<std::complex<double>> result(dim * dim);
200 for (
size_t i = 0; i < result.size(); ++i)
201 result[i] = {raw[2 * i], raw[2 * i + 1]};
205 std::complex<double> HilbertSchmidtOverlap(
const GpuDensityMatrix &other)
const
207 double re = 0., im = 0.;
208 if (!lib->DMHilbertSchmidtOverlap(obj, other.obj, &re, &im))
209 throw std::runtime_error(
"GPU density-matrix overlap failed");
213 double FidelityWithStatevector(
const double *state)
const
216 if (!lib->DMFidelityWithStatevector(obj, state, &result))
217 throw std::runtime_error(
"GPU density-matrix fidelity failed");
223 if (!lib->DMSaveState(obj))
224 throw std::runtime_error(
"GPU density-matrix state save failed");
229 if (!lib->DMRestoreState(obj))
230 throw std::runtime_error(
"GPU density-matrix state restore failed");
233 void CleanSavedState()
235 if (!lib->DMCleanSavedState(obj))
236 throw std::runtime_error(
"GPU density-matrix saved-state cleanup failed");
239 std::unique_ptr<GpuDensityMatrix> Clone()
const
241 void *cloned = lib->DMClone(obj);
244 return std::make_unique<GpuDensityMatrix>(lib, cloned);
247 bool ApplyKraus(
const std::vector<int> &qubits,
int count,
const double *operators)
249 return lib->DMApplyKraus(obj, qubits.size(), qubits.data(), count, operators);
252#define GPU_DM_CHECK(call, name) \
256 throw std::runtime_error("GPU density-matrix " name " failed"); \
258#define GPU_DM_GATE1(name) \
261 GPU_DM_CHECK(lib->DM##name(obj, q), #name); \
263#define GPU_DM_GATE2(name) \
264 void name(int a, int b) \
266 GPU_DM_CHECK(lib->DM##name(obj, a, b), #name); \
268#define GPU_DM_ROT1(name) \
269 void name(int q, double x) \
271 GPU_DM_CHECK(lib->DM##name(obj, q, x), #name); \
273#define GPU_DM_ROT2(name) \
274 void name(int a, int b, double x) \
276 GPU_DM_CHECK(lib->DM##name(obj, a, b, x), #name); \
280 GPU_DM_ROT1(ApplyBitFlipNoise)
282 GPU_DM_ROT1(ApplyPhaseFlipNoise)
284 GPU_DM_ROT1(ApplyDepolarizingNoise)
286 GPU_DM_ROT1(ApplyAmplitudeDamping)
288 GPU_DM_ROT1(ApplyPhaseDamping)
290 GPU_DM_GATE1(ApplyNonSelectiveMeasurement)
316 GPU_DM_CHECK(lib->DMApplyU(obj, q, a, b, c, d),
"ApplyU");
331 GPU_DM_CHECK(lib->DMApplyCCX(obj, a, b, c),
"ApplyCCX");
337 GPU_DM_CHECK(lib->DMApplyCSwap(obj, a, b, c),
"ApplyCSwap");
340 void ApplyCU(
int a,
int b,
double c,
double d,
double e,
double f)
342 GPU_DM_CHECK(lib->DMApplyCU(obj, a, b, c, d, e, f),
"ApplyCU");
352 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)
Bounded online routing based on current physical bond dimensions.