2#if defined(INCLUDED_BY_FACTORY) && defined(__linux__)
9class GpuTensorNetworkSimulator :
public ImmediateGpuSimulator
12 GpuTensorNetworkSimulator()
14 configuration.SetConfiguration(
"method",
"tensor_network");
17 const char *MethodName()
const override
19 return "tensor_network";
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 tn = SimulatorsFactory::CreateGpuLibTensorNetSim(gpuDevice);
36 for (
const auto &[key, value] : configuration.GetConfigMap())
38 Configure(key.c_str(), value.c_str());
39 const bool res = tn->Create(nrQubits);
41 throw std::runtime_error(
"GpuState::Initialize: Failed to create "
42 "and initialize the tensor network state.");
45 throw std::runtime_error(
"GpuState::Initialize: Failed to create the tensor network "
48 if (GetGpuDevice() != gpuDevice)
49 throw std::runtime_error(
"GpuState::Initialize: GPU plugin did not confirm the requested "
50 "device; update the GPU library");
58 upcomingGateIndex = 0;
61 void Configure(
const char *key,
const char *value)
override
65 if (std::string(
"gpu_device") == key)
67 const int device = Configuration::ParseGpuDevice(value);
68 if ((tn) && device != Configuration::ParseGpuDevice(configuration.GetConfiguration(key)))
69 throw std::invalid_argument(
"gpu_device cannot change after initialization; clear the "
71 configuration.SetConfiguration(key, std::to_string(device));
74 const auto svdGroup = Configuration::GpuSvdSettingGroup(key);
75 if (!svdGroup.empty())
77 const bool enabled = Configuration::ParseGpuSvdFlag(value);
78 const bool gesvd = svdGroup == key;
79 const char algorithm = std::string(key).back();
80 const auto apply = [algorithm, enabled](
auto &backend) {
84 return backend->SetGesvdJ(enabled);
86 return backend->SetGesvdP(enabled);
87 return backend->SetGesvdR(enabled);
89 const auto applyGesvd = [enabled](
auto &backend) {
90 if (!enabled || !backend)
92 return backend->SetGesvdJ(
false) && backend->SetGesvdP(
false) && backend->SetGesvdR(
false);
95 if (svdGroup ==
"tensor_network_use_gesvd")
96 applied = gesvd ? applyGesvd(tn) : apply(tn);
98 throw std::runtime_error(std::string(
"GPU library cannot apply ") + key +
"; an updated GPU plugin may be required");
99 configuration.SetConfiguration(key, value);
102 if (std::string(
"method") == key)
104 ValidateMethod(value);
105 configuration.SetConfiguration(key, value);
108 if (std::string(key) ==
"precision" || std::string(key) ==
"use_double_precision")
112 const bool useDouble = Configuration::ParsePrecision(key, value);
113 if ((tn && tn->IsCreated()))
115 if ((tn && !tn->SetDataType(useDouble)))
116 throw std::runtime_error(
"GPU precision configuration failed");
117 configuration.SetConfiguration(key, value);
120 if (!configuration.WasApplied(key, value))
121 configuration.SetConfiguration(key, value);
122 if (std::string(
"seed") == key)
124 const uint64_t seed = std::stoull(value);
125 SeedAuxiliaryRng(seed);
131 if (std::string(
"matrix_product_state_truncation_threshold") == key || std::string(
"matrix_product_operator_truncation_threshold") == key)
133 const double singularValueThreshold = std::stod(value);
134 if (singularValueThreshold >= 0.)
137 tn->SetCutoff(singularValueThreshold);
140 else if (std::string(
"matrix_product_state_truncation_mode") == key || std::string(
"matrix_product_operator_truncation_mode") == key)
142 int truncationMode = -1;
143 if (std::string(
"relative_max") == value)
145 else if (std::string(
"discarded_weight") == value)
147 if (truncationMode >= 0)
150 tn->SetTruncationMode(truncationMode);
153 else if (std::string(
"matrix_product_state_max_bond_dimension") == key || std::string(
"matrix_product_operator_max_bond_dimension") == key)
155 const long long int chi = std::stoi(value);
159 tn->SetMaxExtent(chi);
168 if (std::string(key) ==
"precision" || std::string(key) ==
"use_double_precision")
170 const bool useDouble = tn ? tn->IsDoublePrecision() : configuration.GetConfiguration(
"precision") ==
"double";
171 return std::string(key) ==
"precision" ? (useDouble ?
"double" :
"single") : (useDouble ?
"1" :
"0");
175 const auto svdGroup = Configuration::GpuSvdSettingGroup(key);
176 if (!svdGroup.empty())
180 const auto readGesvd = [](
const auto &backend) {
return !backend->GetGesvdJ() && !backend->GetGesvdP() && !backend->GetGesvdR(); };
181 if (svdGroup ==
"tensor_network_use_gesvd" && tn)
182 return readGesvd(tn) ?
"true" :
"false";
184 const char algorithm = std::string(key).back();
185 const auto read = [algorithm](
const auto &backend) {
186 if (algorithm ==
'j')
187 return backend->GetGesvdJ();
188 if (algorithm ==
'p')
189 return backend->GetGesvdP();
190 return backend->GetGesvdR();
192 if (svdGroup ==
"tensor_network_use_gesvd" && tn)
193 return read(tn) ?
"true" :
"false";
195 if (std::string(
"method") == key)
197 return configuration.GetConfiguration(key);
202 const size_t oldNrQubits = nrQubits;
203 nrQubits += num_qubits;
207 void Clear()
override
211 upcomingGateIndex = 0;
212 upcomingGates.clear();
217 if (qubits.size() >
sizeof(
size_t) * 8)
218 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
219 "number of bits in the size_t type, the outcome will be undefined"
225 for (
size_t qubit : qubits)
227 if (tn->Measure(
static_cast<unsigned int>(qubit)))
233 NotifyObservers(qubits);
239 std::vector<bool> res(qubits.size(),
false);
242 for (
size_t i = 0; i < qubits.size(); ++i)
243 res[i] = tn->Measure(
static_cast<unsigned int>(qubits[i]));
246 NotifyObservers(qubits);
254 for (
size_t qubit : qubits)
255 if (tn->Measure(
static_cast<unsigned int>(qubit)))
256 tn->ApplyX(
static_cast<unsigned int>(qubit));
259 NotifyObservers(qubits);
267 std::vector<long int> fixedValues(nrQubits);
268 for (
size_t i = 0; i < nrQubits; ++i)
269 fixedValues[i] = i < std::numeric_limits<Types::qubit_t>::digits ? (outcome >> i) & 1 : 0;
270 tn->Amplitude(nrQubits, fixedValues.data(), &real, &imag);
272 return std::complex<double>(real, imag);
279 if (nrQubits >= std::numeric_limits<size_t>::digits)
280 throw std::length_error(
"Full probability enumeration exceeds the basis-index API; query "
281 "selected bit vectors");
282 const size_t numStates =
size_t{1} << nrQubits;
283 std::vector<double> result(numStates);
288 result[i] = std::norm(std::complex<double>(val.real(), val.imag()));
296 if (qubits.empty() || shots == 0)
299 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
300 "number of bits in the Types::qubit_t type, the outcome will be "
303 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
306 std::unordered_map<std::vector<bool>, int64_t> *map = tn->GetMapForSample();
307 std::vector<unsigned int> qubitsIndices(qubits.begin(), qubits.end());
308 tn->Sample(shots, qubitsIndices.size(), qubitsIndices.data(), map);
309 const auto positions = SampleBitPositions(qubits);
310 for (
const auto &[meas, cnt] : *map)
316 if (meas[positions[q]])
320 result[outcome] += cnt;
322 tn->FreeMapForSample(map);
325 NotifyObservers(qubits);
331 if (qubits.empty() || shots == 0)
336 std::unordered_map<std::vector<bool>, int64_t> *map = tn->GetMapForSample();
337 std::vector<unsigned int> qubitsIndices(qubits.begin(), qubits.end());
338 tn->Sample(shots, qubitsIndices.size(), qubitsIndices.data(), map);
339 const auto positions = SampleBitPositions(qubits);
340 for (
const auto &[meas, cnt] : *map)
342 std::vector<bool> ordered(qubits.size());
343 for (
size_t q = 0; q < qubits.size(); ++q)
344 ordered[q] = meas[positions[q]];
345 result[ordered] += cnt;
347 tn->FreeMapForSample(map);
350 NotifyObservers(qubits);
354 double ExpectationValue(
const std::string &pauliString)
override
357 result = tn->ExpectationValue(pauliString);
361 int GetGpuDevice()
const override
364 return tn->GetGpuDevice();
370 return SimulationType::kTensorNetwork;
385 tn->ApplyP(qubit, lambda);
386 NotifyObservers({qubit});
392 NotifyObservers({qubit});
398 NotifyObservers({qubit});
404 NotifyObservers({qubit});
410 NotifyObservers({qubit});
416 NotifyObservers({qubit});
422 NotifyObservers({qubit});
428 NotifyObservers({qubit});
434 NotifyObservers({qubit});
440 NotifyObservers({qubit});
445 tn->ApplySXDG(qubit);
446 NotifyObservers({qubit});
452 NotifyObservers({qubit});
457 tn->ApplyRx(qubit, theta);
458 NotifyObservers({qubit});
463 tn->ApplyRy(qubit, theta);
464 NotifyObservers({qubit});
469 tn->ApplyRz(qubit, theta);
470 NotifyObservers({qubit});
473 void ApplyU(
Types::qubit_t qubit,
double theta,
double phi,
double lambda,
double gamma)
override
475 tn->ApplyU(qubit, theta, phi, lambda, gamma);
476 NotifyObservers({qubit});
481 tn->ApplyCX(ctrl_qubit, tgt_qubit);
482 NotifyObservers({tgt_qubit, ctrl_qubit});
487 tn->ApplyCY(ctrl_qubit, tgt_qubit);
488 NotifyObservers({tgt_qubit, ctrl_qubit});
493 tn->ApplyCZ(ctrl_qubit, tgt_qubit);
494 NotifyObservers({tgt_qubit, ctrl_qubit});
499 tn->ApplyCP(ctrl_qubit, tgt_qubit, lambda);
500 NotifyObservers({tgt_qubit, ctrl_qubit});
505 tn->ApplyCRx(ctrl_qubit, tgt_qubit, theta);
506 NotifyObservers({tgt_qubit, ctrl_qubit});
511 tn->ApplyCRy(ctrl_qubit, tgt_qubit, theta);
512 NotifyObservers({tgt_qubit, ctrl_qubit});
517 tn->ApplyCRz(ctrl_qubit, tgt_qubit, theta);
518 NotifyObservers({tgt_qubit, ctrl_qubit});
523 tn->ApplyCH(ctrl_qubit, tgt_qubit);
524 NotifyObservers({tgt_qubit, ctrl_qubit});
529 tn->ApplyCSX(ctrl_qubit, tgt_qubit);
530 NotifyObservers({tgt_qubit, ctrl_qubit});
535 tn->ApplyCSXDG(ctrl_qubit, tgt_qubit);
536 NotifyObservers({tgt_qubit, ctrl_qubit});
541 tn->ApplySwap(qubit0, qubit1);
542 NotifyObservers({qubit1, qubit0});
547 tn->ApplyCCX(qubit0, qubit1, qubit2);
548 NotifyObservers({qubit0, qubit1, qubit2});
553 tn->ApplyCSwap(ctrl_qubit, qubit0, qubit1);
554 NotifyObservers({qubit1, qubit0, ctrl_qubit});
559 tn->ApplyCU(ctrl_qubit, tgt_qubit, theta, phi, lambda, gamma);
560 NotifyObservers({tgt_qubit, ctrl_qubit});
563 std::unique_ptr<ISimulator> Clone()
override
565 throw std::runtime_error(
"GpuSimulator::Clone: Cloning Tensor Network or Pauli Propagator "
571 std::unique_ptr<GpuLibTNSim> tn;
int ApplyK(void *sim, int qubit)
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)
double * AllProbabilities(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 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 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 ApplyT(void *sim, int qubit)
int ApplyCRx(void *sim, int controlQubit, int targetQubit, double theta)
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.