2#if defined(INCLUDED_BY_FACTORY) && defined(__linux__)
9class GpuStatevectorSimulator :
public ImmediateGpuSimulator
12 GpuStatevectorSimulator()
14 configuration.SetConfiguration(
"method",
"statevector");
17 const char *MethodName()
const override
22 void Initialize()
override
26 auto initializationLock = GpuLibrary::GetInstance()->LockInitialization();
27 const int gpuDevice = configuration.IsSet(
"gpu_device") ? Configuration::ParseGpuDevice(configuration.GetConfiguration(
"gpu_device"))
28 : SimulatorsFactory::ResolveGpuDevice();
29 configuration.SetConfiguration(
"gpu_device", std::to_string(gpuDevice));
30 if (!SimulatorsFactory::GetGpuLibrary(gpuDevice))
31 throw std::runtime_error(
"GpuState::Initialize: Unable to initialize GPU device " + std::to_string(gpuDevice));
33 state = SimulatorsFactory::CreateGpuLibStateVectorSim(gpuDevice);
36 for (
const auto &[key, value] : configuration.GetConfigMap())
38 Configure(key.c_str(), value.c_str());
39 const bool res = state->Create(nrQubits);
41 throw std::runtime_error(
"GpuState::Initialize: Failed to create "
42 "and initialize the statevector state.");
45 throw std::runtime_error(
"GpuState::Initialize: Failed to create the statevector state.");
47 if (GetGpuDevice() != gpuDevice)
48 throw std::runtime_error(
"GpuState::Initialize: GPU plugin did not confirm the requested "
49 "device; update the GPU library");
53 void InitializeState(
size_t num_qubits, std::vector<std::complex<double>> &litudes)
override
58 nrQubits = num_qubits;
60 const bool created = state->CreateWithState(nrQubits,
reinterpret_cast<const double *
>(amplitudes.data()));
62 throw std::runtime_error(
"GpuState::InitializeState: Failed to initialize the state.");
66 void InitializeState(
size_t num_qubits, AER::Vector<std::complex<double>> &litudes)
override
71 nrQubits = num_qubits;
73 const bool created = state->CreateWithState(nrQubits,
reinterpret_cast<const double *
>(amplitudes.data()));
75 throw std::runtime_error(
"GpuState::InitializeState: Failed to initialize the state.");
80 void InitializeState(
size_t num_qubits, Eigen::VectorXcd &litudes)
override
85 nrQubits = num_qubits;
87 const bool created = state->CreateWithState(nrQubits,
reinterpret_cast<const double *
>(amplitudes.data()));
89 throw std::runtime_error(
"GpuState::InitializeState: Failed to initialize the state.");
96 upcomingGateIndex = 0;
99 void Configure(
const char *key,
const char *value)
override
103 if (std::string(
"gpu_device") == key)
105 const int device = Configuration::ParseGpuDevice(value);
106 if ((state) && device != Configuration::ParseGpuDevice(configuration.GetConfiguration(key)))
107 throw std::invalid_argument(
"gpu_device cannot change after initialization; clear the "
109 configuration.SetConfiguration(key, std::to_string(device));
112 const auto svdGroup = Configuration::GpuSvdSettingGroup(key);
113 if (!svdGroup.empty())
115 Configuration::ParseGpuSvdFlag(value);
116 configuration.SetConfiguration(key, value);
119 if (std::string(
"method") == key)
121 ValidateMethod(value);
122 configuration.SetConfiguration(key, value);
125 if (std::string(key) ==
"precision" || std::string(key) ==
"use_double_precision")
129 const bool useDouble = Configuration::ParsePrecision(key, value);
130 if ((state && state->GetNrQubits() > 0))
132 if ((state && !state->SetDataType(useDouble)))
133 throw std::runtime_error(
"GPU precision configuration failed");
134 configuration.SetConfiguration(key, value);
137 if (!configuration.WasApplied(key, value))
138 configuration.SetConfiguration(key, value);
139 if (std::string(
"seed") == key)
141 const uint64_t seed = std::stoull(value);
142 SeedAuxiliaryRng(seed);
145 state->SetSeed(seed);
150 if (std::string(
"matrix_product_state_truncation_threshold") == key || std::string(
"matrix_product_operator_truncation_threshold") == key)
152 else if (std::string(
"matrix_product_state_max_bond_dimension") == key || std::string(
"matrix_product_operator_max_bond_dimension") == key)
160 if (std::string(key) ==
"precision" || std::string(key) ==
"use_double_precision")
162 const bool useDouble = state ? state->IsDoublePrecision() : configuration.GetConfiguration(
"precision") ==
"double";
163 return std::string(key) ==
"precision" ? (useDouble ?
"double" :
"single") : (useDouble ?
"1" :
"0");
167 if (std::string(
"method") == key)
169 return configuration.GetConfiguration(key);
176 const size_t oldNrQubits = nrQubits;
177 nrQubits += num_qubits;
181 void Clear()
override
185 upcomingGateIndex = 0;
186 upcomingGates.clear();
191 if (qubits.size() >
sizeof(
size_t) * 8)
192 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
193 "number of bits in the size_t type, the outcome will be undefined"
199 for (
size_t qubit : qubits)
201 if (state->MeasureQubitCollapse(
static_cast<int>(qubit)))
207 NotifyObservers(qubits);
213 std::vector<bool> res(qubits.size(),
false);
216 for (
size_t i = 0; i < qubits.size(); ++i)
217 res[i] = state->MeasureQubitCollapse(
static_cast<int>(qubits[i]));
220 NotifyObservers(qubits);
228 for (
size_t qubit : qubits)
229 if (state->MeasureQubitCollapse(
static_cast<int>(qubit)))
230 state->ApplyX(
static_cast<int>(qubit));
233 NotifyObservers(qubits);
238 return state->BasisStateProbability(outcome);
245 state->Amplitude(outcome, &real, &imag);
246 return std::complex<double>(real, imag);
253 if (nrQubits >= std::numeric_limits<size_t>::digits)
254 throw std::length_error(
"Full probability enumeration exceeds the basis-index API; query "
255 "selected bit vectors");
256 const size_t numStates =
size_t{1} << nrQubits;
257 std::vector<double> result(numStates);
258 state->AllProbabilities(result.data());
264 std::vector<double> result(qubits.size());
266 for (
size_t i = 0; i < qubits.size(); ++i)
267 result[i] = state->BasisStateProbability(qubits[i]);
274 if (qubits.empty() || shots == 0)
277 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
278 "number of bits in the Types::qubit_t type, the outcome will be "
281 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
284 std::vector<long int> samples(shots);
285 state->SampleAll(shots, samples.data());
286 for (
auto outcome : samples)
290 for (
size_t i = 0; i < qubits.size(); ++i)
292 if (outcome & (1ULL << qubits[i]))
293 translatedOutcome |= mask;
296 ++result[translatedOutcome];
300 NotifyObservers(qubits);
306 if (qubits.empty() || shots == 0)
311 std::vector<long int> samples(shots);
312 state->SampleAll(shots, samples.data());
313 std::vector<bool> outcomeVec(qubits.size());
314 for (
auto outcome : samples)
316 for (
size_t i = 0; i < qubits.size(); ++i)
317 outcomeVec[i] = ((outcome >> qubits[i]) & 1) == 1;
318 ++result[outcomeVec];
322 NotifyObservers(qubits);
326 double ExpectationValue(
const std::string &pauliString)
override
329 result = state->ExpectationValue(pauliString);
333 int GetGpuDevice()
const override
336 return state->GetGpuDevice();
342 return SimulationType::kStatevector;
345 void Flush()
override
347 const bool done = state ? state->Synchronize() :
true;
349 throw std::runtime_error(
"GpuState::Flush: device synchronization failed");
354 state->SaveStateDestructive();
359 state->RestoreStateFreeSaved();
369 state->RestoreStateNoFreeSaved();
374 return state->MeasureAllQubitsNoCollapse();
377 std::vector<bool> MeasureNoCollapseMany()
override
379 const auto meas = state->MeasureAllQubitsNoCollapse();
380 std::vector<bool> result(nrQubits,
false);
381 for (
size_t i = 0; i < nrQubits; ++i)
382 result[i] = ((meas >> i) & 1) == 1;
388 ValidateStatevectorTarget(qubit);
389 if (!state->ApplyOneQubitMatrixWithLayout(
static_cast<int>(qubit),
reinterpret_cast<const double *
>(gate.data()), GpuLibrary::MATRIX_COLUMN_MAJOR))
390 throw std::runtime_error(
"GPU statevector failed to apply one-qubit matrix");
391 NotifyObservers({qubit});
397 ValidateStatevectorTarget(qubit0);
398 ValidateStatevectorTarget(qubit1);
399 if (!state->ApplyTwoQubitMatrixWithLayout(
static_cast<int>(qubit0),
static_cast<int>(qubit1),
reinterpret_cast<const double *
>(gate.data()),
400 GpuLibrary::MATRIX_COLUMN_MAJOR))
401 throw std::runtime_error(
"GPU statevector failed to apply two-qubit matrix");
402 NotifyObservers({qubit0, qubit1});
407 const Eigen::Matrix<std::complex<double>, 8, 8> &gate)
override
409 ValidateStatevectorTarget(qubit0);
410 ValidateStatevectorTarget(qubit1);
411 ValidateStatevectorTarget(qubit2);
412 if (!state->ApplyThreeQubitMatrixWithLayout(
static_cast<int>(qubit0),
static_cast<int>(qubit1),
static_cast<int>(qubit2),
413 reinterpret_cast<const double *
>(gate.data()), GpuLibrary::MATRIX_COLUMN_MAJOR))
414 throw std::runtime_error(
"GPU statevector failed to apply three-qubit matrix");
415 NotifyObservers({qubit0, qubit1, qubit2});
420 state->ApplyP(qubit, lambda);
421 NotifyObservers({qubit});
426 state->ApplyX(qubit);
427 NotifyObservers({qubit});
432 state->ApplyY(qubit);
433 NotifyObservers({qubit});
438 state->ApplyZ(qubit);
439 NotifyObservers({qubit});
444 state->ApplyH(qubit);
445 NotifyObservers({qubit});
450 state->ApplyS(qubit);
451 NotifyObservers({qubit});
456 state->ApplySDG(qubit);
457 NotifyObservers({qubit});
462 state->ApplyT(qubit);
463 NotifyObservers({qubit});
468 state->ApplyTDG(qubit);
469 NotifyObservers({qubit});
474 state->ApplySX(qubit);
475 NotifyObservers({qubit});
480 state->ApplySXDG(qubit);
481 NotifyObservers({qubit});
486 state->ApplyK(qubit);
487 NotifyObservers({qubit});
492 state->ApplyRx(qubit, theta);
493 NotifyObservers({qubit});
498 state->ApplyRy(qubit, theta);
499 NotifyObservers({qubit});
504 state->ApplyRz(qubit, theta);
505 NotifyObservers({qubit});
508 void ApplyU(
Types::qubit_t qubit,
double theta,
double phi,
double lambda,
double gamma)
override
510 state->ApplyU(qubit, theta, phi, lambda, gamma);
511 NotifyObservers({qubit});
516 state->ApplyCX(ctrl_qubit, tgt_qubit);
517 NotifyObservers({tgt_qubit, ctrl_qubit});
522 state->ApplyCY(ctrl_qubit, tgt_qubit);
523 NotifyObservers({tgt_qubit, ctrl_qubit});
528 state->ApplyCZ(ctrl_qubit, tgt_qubit);
529 NotifyObservers({tgt_qubit, ctrl_qubit});
534 state->ApplyCP(ctrl_qubit, tgt_qubit, lambda);
535 NotifyObservers({tgt_qubit, ctrl_qubit});
540 state->ApplyCRx(ctrl_qubit, tgt_qubit, theta);
541 NotifyObservers({tgt_qubit, ctrl_qubit});
546 state->ApplyCRy(ctrl_qubit, tgt_qubit, theta);
547 NotifyObservers({tgt_qubit, ctrl_qubit});
552 state->ApplyCRz(ctrl_qubit, tgt_qubit, theta);
553 NotifyObservers({tgt_qubit, ctrl_qubit});
558 state->ApplyCH(ctrl_qubit, tgt_qubit);
559 NotifyObservers({tgt_qubit, ctrl_qubit});
564 state->ApplyCSX(ctrl_qubit, tgt_qubit);
565 NotifyObservers({tgt_qubit, ctrl_qubit});
570 state->ApplyCSXDG(ctrl_qubit, tgt_qubit);
571 NotifyObservers({tgt_qubit, ctrl_qubit});
576 state->ApplySwap(qubit0, qubit1);
577 NotifyObservers({qubit1, qubit0});
582 state->ApplyCCX(qubit0, qubit1, qubit2);
583 NotifyObservers({qubit0, qubit1, qubit2});
588 state->ApplyCSwap(ctrl_qubit, qubit0, qubit1);
589 NotifyObservers({qubit1, qubit0, ctrl_qubit});
594 state->ApplyCU(ctrl_qubit, tgt_qubit, theta, phi, lambda, gamma);
595 NotifyObservers({tgt_qubit, ctrl_qubit});
598 std::unique_ptr<ISimulator> Clone()
override
600 auto cloned = std::make_unique<GpuStatevectorSimulator>();
601 cloned->nrQubits = nrQubits;
602 cloned->upcomingGates = upcomingGates;
603 cloned->upcomingGateIndex = upcomingGateIndex;
604 cloned->configuration = configuration;
606 cloned->state = state->Clone();
607 if (configuration.IsSet(
"seed"))
608 cloned->SetSeed(DeriveSeed(std::stoull(configuration.GetConfiguration(
"seed")), nextSeedStream++));
613 std::unique_ptr<GpuLibStateVectorSim> state;
619 throw std::logic_error(
"GPU statevector is not initialized");
621 throw std::out_of_range(
"GPU statevector qubit is out of range");
int ApplyK(void *sim, int qubit)
double Probability(void *sim, unsigned long long int outcome)
char * GetConfiguration(void *sim, const char *key)
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 ApplyS(void *sim, int qubit)
int ApplyCX(void *sim, int controlQubit, int targetQubit)
unsigned long int AllocateQubits(void *sim, unsigned long int nrQubits)
int ApplyCRz(void *sim, int controlQubit, int targetQubit, double theta)
unsigned long int GetNumberOfQubits(void *sim)
double * AllProbabilities(void *sim)
unsigned long long int MeasureNoCollapse(void *sim)
int ApplyCP(void *sim, int controlQubit, int targetQubit, double theta)
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)
double * Amplitude(void *sim, unsigned long long int outcome)
int ApplyZ(void *sim, int qubit)
int ApplyH(void *sim, int qubit)
int ApplyGenericThreeQubitGate(void *sim, unsigned long q0, unsigned long q1, unsigned long q2, const double *buffer)
int ApplyCY(void *sim, int controlQubit, int targetQubit)
double * Probabilities(void *sim, const unsigned long long int *qubits, unsigned long int nrQubits)
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 SaveStateToInternalDestructive(void *sim)
int ApplyCH(void *sim, int controlQubit, int targetQubit)
int GetSimulationType(void *sim)
unsigned long long int * SampleCounts(void *sim, const unsigned long long int *qubits, unsigned long int nrQubits, unsigned long int shots)
int ApplyCZ(void *sim, int controlQubit, int targetQubit)
int ApplyRz(void *sim, int qubit, double theta)
int RestoreInternalDestructiveSavedState(void *sim)
int ApplyT(void *sim, int qubit)
int ApplyCRx(void *sim, int controlQubit, int targetQubit, double theta)
int ApplyGenericOneQubitGate(void *sim, unsigned long q0, const double *buffer)
int ApplyGenericTwoQubitGate(void *sim, unsigned long q0, unsigned long q1, const double *buffer)
SimulationType
The type of simulation.
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
uint_fast64_t qubit_t
The type of a qubit.