15#ifndef _GPU_LIB_MPS_SIM_H_
16#define _GPU_LIB_MPS_SIM_H_
32 explicit GpuLibMPSSim(
const std::shared_ptr<GpuLibrary> &lib,
int device = -1) : lib(lib), obj(
nullptr)
36 auto lock = lib->LockInitialization();
37 if (lib->SetGpuDevice(device == -1 ? lib->GetCreationDevice() : device))
38 obj = lib->CreateMPS();
42 int GetGpuDevice()
const
44 return lib ? lib->MPSGetGpuId(obj) : -1;
47 GpuLibMPSSim(
const std::shared_ptr<GpuLibrary> &lib,
void *obj) : lib(lib), obj(obj)
51 GpuLibMPSSim() =
delete;
52 GpuLibMPSSim(
const GpuLibMPSSim &) =
delete;
53 GpuLibMPSSim &operator=(
const GpuLibMPSSim &) =
delete;
54 GpuLibMPSSim(GpuLibMPSSim &&) =
default;
55 GpuLibMPSSim &operator=(GpuLibMPSSim &&) =
default;
63 bool Create(
unsigned int nrQubits)
66 return lib->MPSCreate(obj, nrQubits);
71 bool CreateWithBasisState(
unsigned int nrQubits,
unsigned long long state)
74 return lib->MPSCreateWithBasisState(obj, nrQubits, state);
79 bool CreateWithBasisStateBits(
unsigned int nrQubits,
const std::vector<unsigned char> &stateBits)
82 return lib->MPSCreateWithBasisStateBits(obj, nrQubits, stateBits.data());
90 return lib->MPSReset(obj);
95 bool SetSeed(uint64_t seed)
97 return obj && lib->MPSSetSeed(obj, seed);
104 return obj && lib->MPSTrim(obj);
107 bool ReCanonicalize()
109 return obj && lib->MPSReCanonicalize(obj);
112 bool SetInitialQubitsMap(
const std::vector<long long int> &initialMap)
115 return lib->MPSSetInitialQubitsMap(obj, initialMap);
120 bool SetUseOptimalMeetingPosition(
bool useOptimalMeetingPosition)
123 return lib->MPSSetUseOptimalMeetingPosition(obj, useOptimalMeetingPosition);
127 bool GetUseOptimalMeetingPosition()
const
130 return lib->MPSGetUseOptimalMeetingPosition(obj);
137 return lib->MPSIsValid(obj);
142 bool IsCreated()
const
145 return lib->MPSIsCreated(obj);
150 bool SetDataType(
int useDoublePrecision)
153 return lib->MPSSetDataType(obj, useDoublePrecision);
158 bool IsDoublePrecision()
const
161 return lib->MPSIsDoublePrecision(obj);
166 bool SetCutoff(
double val)
169 return lib->MPSSetCutoff(obj, val);
174 double GetCutoff()
const
177 return lib->MPSGetCutoff(obj);
184 bool SetTruncationMode(
int mode)
187 return lib->MPSSetTruncationMode(obj, mode);
192 int GetTruncationMode()
const
195 return lib->MPSGetTruncationMode(obj);
200 bool SetGesvdJ(
int val)
203 return lib->MPSSetGesvdJ(obj, val);
208 bool GetGesvdJ()
const
211 return lib->MPSGetGesvdJ(obj);
217 bool SetGesvdP(
bool enable)
219 return obj && lib->MPSSetGesvdP(obj, enable);
222 bool GetGesvdP()
const
224 return lib->MPSGetGesvdP(obj);
227 bool SetGesvdR(
bool enable)
229 return obj && lib->MPSSetGesvdR(obj, enable);
232 bool GetGesvdR()
const
234 return lib->MPSGetGesvdR(obj);
237 int GetLastSvdAlgo()
const
239 return lib->MPSGetLastSvdAlgo(obj);
242 bool SetMaxExtent(
long int val)
245 return lib->MPSSetMaxExtent(obj, val);
250 long int GetMaxExtent()
const
253 return lib->MPSGetMaxExtent(obj);
258 int GetNrQubits()
const
261 return lib->MPSGetNrQubits(obj);
266 std::vector<long long int> GetBondDimensions(
size_t nrQubits)
const
268 if (!obj || nrQubits < 2)
270 std::vector<long long int> bondDims(nrQubits - 1);
271 if (!lib->MPSGetBondDimensions(obj, bondDims.data()))
276 std::vector<long long> GetQubitsMap()
const
278 std::vector<long long> map(GetNrQubits());
279 if (!lib->MPSGetQubitsMap(obj, map.data(),
static_cast<int>(map.size())))
284 bool SetCallbackContext(
void *context)
287 return lib->MPSSetCallbackContext(obj, context);
291 bool SetMeetingPositionCallback(int64_t (*callback)(
void *,
const int64_t *))
294 return lib->MPSSetMeetingPositionCallback(obj, callback);
298 bool SetBondDimensionsCallback(
void (*callback)(
void *,
const int64_t *))
301 return lib->MPSSetBondDimensionsCallback(obj, callback);
305 void InstallBondSummary(
void (*summary)(
void *, int64_t),
void (*full)(
void *,
const int64_t *))
307 const bool ok = lib->HasMPSBondSummary() ? lib->MPSSetBondDimensionSummaryCallback(obj, summary) : SetBondDimensionsCallback(full);
309 throw std::runtime_error(
"GPU MPS bond callback installation failed");
312 std::vector<std::complex<double>> GetStateVector()
314 const auto n = GetNrQubits();
316 throw std::length_error(
"GPU MPS dense output supports at most 40 qubits");
317 const auto count = TensorQueries::DenseSize(n);
318 std::vector<std::complex<double>> result(count);
319 if (lib->HasMPSGetStateVector())
323 if (!lib->MPSGetStateVector(obj,
reinterpret_cast<double *
>(result.data())))
324 throw std::runtime_error(
"GPU MPS statevector query failed");
328 std::vector<long int> bits(n);
329 for (
size_t i = 0; i < count; ++i)
331 for (
int q = 0; q < n; ++q)
332 bits[q] = (i >> q) & 1;
333 double re = 0., im = 0.;
334 if (!
Amplitude(n, bits.data(), &re, &im) || !std::isfinite(re) || !std::isfinite(im))
335 throw std::runtime_error(
"GPU MPS amplitude query failed");
336 result[i] = {re, im};
344 const auto n = GetNrQubits();
346 throw std::length_error(
"GPU MPS dense output supports at most 40 qubits");
347 std::vector<double> result(TensorQueries::DenseSize(n));
348 if (lib->HasMPSAllProbabilities())
350 if (!lib->MPSAllProbabilities(obj, result.data()))
351 throw std::runtime_error(
"GPU MPS probability enumeration failed");
355 const auto amplitudes = GetStateVector();
356 for (
size_t i = 0; i < result.size(); ++i)
357 result[i] = std::norm(amplitudes[i]);
362 void MoveAtBeginningOfChain(
const std::vector<int> &qubits)
364 if (!lib->HasMPSMoveAtBeginningOfChain())
365 throw std::runtime_error(
"GPU MPS chain movement requires an updated GPU plugin");
366 if (!lib->MPSMoveAtBeginningOfChain(obj, qubits.data(), TensorQueries::Count(qubits.size())))
367 throw std::runtime_error(
"GPU MPS chain movement failed");
370 std::complex<double> ExpectationValueOperators(
const std::vector<int> &qubits,
const std::vector<double> &matrices)
372 if (!lib->HasMPSExpectationValueOperators())
373 throw std::runtime_error(
"GPU MPS operator expectations require an updated GPU plugin");
374 double re = 0., im = 0.;
375 if (!lib->MPSExpectationValueOperators(obj, TensorQueries::Count(qubits.size()), qubits.data(), matrices.data(), &re, &im))
376 throw std::runtime_error(
"GPU MPS operator expectation failed");
380 std::vector<double> ExpectationValues(
const std::vector<std::string> &paulis)
382 TensorQueries::PauliBatch batch(paulis);
383 std::vector<double> values(paulis.size());
386 if (lib->HasMPSExpectationValues())
388 if (!lib->MPSExpectationValues(obj, TensorQueries::Count(paulis.size()), batch.strings.data(), batch.lengths.data(), values.data()))
389 throw std::runtime_error(
"GPU MPS batch expectation failed");
393 for (
size_t i = 0; i < paulis.size(); ++i)
395 values[i] = ExpectationValue(paulis[i]);
396 if (!std::isfinite(values[i]))
397 throw std::runtime_error(
"GPU MPS expectation failed");
403 std::unordered_map<std::vector<bool>, int64_t> SampleHistogram(
size_t shots, std::vector<unsigned int> qubits)
405 if (shots == 0 || qubits.empty())
407 if (shots >
static_cast<size_t>(std::numeric_limits<long int>::max()) || qubits.size() >
static_cast<size_t>(std::numeric_limits<long int>::max()))
408 throw std::length_error(
"GPU MPS sampling size exceeds API limits");
409 for (
auto q : qubits)
410 if (q >=
static_cast<size_t>(GetNrQubits()))
411 throw std::out_of_range(
"GPU MPS sampled qubit is out of range");
412 using Map = std::unordered_map<std::vector<bool>, int64_t>;
413 auto deleter = [
this](Map *map) { FreeMapForSample(map); };
414 std::unique_ptr<Map,
decltype(deleter)> map(GetMapForSample(), deleter);
415 if (!map || !Sample(shots, qubits.size(), qubits.data(), map.get()))
416 throw std::runtime_error(
"GPU MPS sampling failed");
418 for (
const auto &entry : *map)
420 if (entry.second < 0 ||
static_cast<size_t>(entry.second) > shots - total)
421 throw std::runtime_error(
"GPU MPS returned invalid sample counts");
422 total +=
static_cast<size_t>(entry.second);
425 throw std::runtime_error(
"GPU MPS returned incomplete sample counts");
429 bool Amplitude(
long int numFixedValues,
long int *fixedValues,
double *real,
double *imaginary)
const
432 return lib->MPSAmplitude(obj, numFixedValues, fixedValues, real, imaginary);
437 double Probability0(
unsigned int qubit)
const
440 return lib->MPSProbability0(obj, qubit);
445 bool Measure(
unsigned int qubit)
448 return lib->MPSMeasure(obj, qubit);
453 bool MeasureQubits(
long int numQubits,
unsigned int *qubits,
int *result)
456 return lib->MPSMeasureQubits(obj, numQubits, qubits, result);
461 std::unordered_map<std::vector<bool>, int64_t> *GetMapForSample()
const
464 return lib->MPSGetMapForSample();
469 bool FreeMapForSample(std::unordered_map<std::vector<bool>, int64_t> *map)
const
472 return lib->MPSFreeMapForSample(map);
477 bool Sample(
long int numShots,
long int numQubits,
unsigned int *qubits,
void *resultMap)
480 return lib->MPSSample(obj, numShots, numQubits, qubits, resultMap);
485 bool SampleRaw(
unsigned int nSamples,
long int *samples,
unsigned int nBits,
const unsigned int *bitOrdering)
488 return lib->MPSSampleRaw(obj, nSamples, samples, nBits, bitOrdering);
493 bool SampleAll(
unsigned int nSamples,
long int *samples)
496 return lib->MPSSampleAll(obj, nSamples, samples);
504 return lib->MPSSaveState(obj);
512 return lib->MPSRestoreState(obj);
517 bool CleanSavedState()
520 return lib->MPSCleanSavedState(obj);
525 std::unique_ptr<GpuLibMPSSim> Clone()
const
529 auto *cloned = lib->MPSClone(obj);
531 throw std::runtime_error(
"GPU MPS clone failed");
532 return std::make_unique<GpuLibMPSSim>(lib, cloned);
538 double ExpectationValue(
const std::string &pauliString)
541 return lib->MPSExpectationValue(obj, pauliString.c_str(), pauliString.length());
546 std::complex<double> ProjectOnZero()
549 return lib->MPSProjectOnZero(obj);
551 return std::complex<double>(0., 0.);
554 bool ApplyX(
unsigned int siteA)
557 return lib->MPSApplyX(obj, siteA);
562 bool ApplyY(
unsigned int siteA)
565 return lib->MPSApplyY(obj, siteA);
570 bool ApplyZ(
unsigned int siteA)
573 return lib->MPSApplyZ(obj, siteA);
578 bool ApplyH(
unsigned int siteA)
581 return lib->MPSApplyH(obj, siteA);
586 bool ApplyS(
unsigned int siteA)
589 return lib->MPSApplyS(obj, siteA);
597 return lib->MPSApplySDG(obj, siteA);
602 bool ApplyT(
unsigned int siteA)
605 return lib->MPSApplyT(obj, siteA);
613 return lib->MPSApplyTDG(obj, siteA);
618 bool ApplySX(
unsigned int siteA)
621 return lib->MPSApplySX(obj, siteA);
629 return lib->MPSApplySXDG(obj, siteA);
634 bool ApplyK(
unsigned int siteA)
637 return lib->MPSApplyK(obj, siteA);
642 bool ApplyP(
unsigned int siteA,
double theta)
645 return lib->MPSApplyP(obj, siteA, theta);
650 bool ApplyRx(
unsigned int siteA,
double theta)
653 return lib->MPSApplyRx(obj, siteA, theta);
658 bool ApplyRy(
unsigned int siteA,
double theta)
661 return lib->MPSApplyRy(obj, siteA, theta);
666 bool ApplyRz(
unsigned int siteA,
double theta)
669 return lib->MPSApplyRz(obj, siteA, theta);
674 bool ApplyU(
unsigned int siteA,
double theta,
double phi,
double lambda,
double gamma)
677 return lib->MPSApplyU(obj, siteA, theta, phi, lambda, gamma);
682 bool ApplyOneQubitMatrix(
unsigned int qubit,
const double *matrixInterleaved)
685 return lib->MPSApplyOneQubitMatrix(obj, qubit, matrixInterleaved);
690 bool ApplyTwoQubitMatrix(
unsigned int qubit1,
unsigned int qubit2,
const double *matrixInterleaved)
693 return lib->MPSApplyTwoQubitMatrix(obj, qubit1, qubit2, matrixInterleaved);
698 bool ApplySwap(
unsigned int controlQubit,
unsigned int targetQubit)
701 return lib->MPSApplySwap(obj, controlQubit, targetQubit);
706 bool ApplyCX(
unsigned int controlQubit,
unsigned int targetQubit)
709 return lib->MPSApplyCX(obj, controlQubit, targetQubit);
714 bool ApplyCY(
unsigned int controlQubit,
unsigned int targetQubit)
717 return lib->MPSApplyCY(obj, controlQubit, targetQubit);
722 bool ApplyCZ(
unsigned int controlQubit,
unsigned int targetQubit)
725 return lib->MPSApplyCZ(obj, controlQubit, targetQubit);
730 bool ApplyCH(
unsigned int controlQubit,
unsigned int targetQubit)
733 return lib->MPSApplyCH(obj, controlQubit, targetQubit);
738 bool ApplyCSX(
unsigned int controlQubit,
unsigned int targetQubit)
741 return lib->MPSApplyCSX(obj, controlQubit, targetQubit);
746 bool ApplyCSXDG(
unsigned int controlQubit,
unsigned int targetQubit)
749 return lib->MPSApplyCSXDG(obj, controlQubit, targetQubit);
754 bool ApplyCP(
unsigned int controlQubit,
unsigned int targetQubit,
double theta)
757 return lib->MPSApplyCP(obj, controlQubit, targetQubit, theta);
762 bool ApplyCRx(
unsigned int controlQubit,
unsigned int targetQubit,
double theta)
765 return lib->MPSApplyCRx(obj, controlQubit, targetQubit, theta);
770 bool ApplyCRy(
unsigned int controlQubit,
unsigned int targetQubit,
double theta)
773 return lib->MPSApplyCRy(obj, controlQubit, targetQubit, theta);
778 bool ApplyCRz(
unsigned int controlQubit,
unsigned int targetQubit,
double theta)
781 return lib->MPSApplyCRz(obj, controlQubit, targetQubit, theta);
786 bool ApplyCU(
unsigned int controlQubit,
unsigned int targetQubit,
double theta,
double phi,
double lambda,
double gamma)
789 return lib->MPSApplyCU(obj, controlQubit, targetQubit, theta, phi, lambda, gamma);
795 GpuDeviceContext lib;
int ApplyK(void *sim, int qubit)
int RestoreState(void *sim)
int ApplyRx(void *sim, int qubit, double theta)
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)
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 ApplyY(void *sim, int qubit)
double * Amplitude(void *sim, unsigned long long int outcome)
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.