Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
GpuDensityMatrixSimulator.h
Go to the documentation of this file.
1#pragma once
2#if defined(INCLUDED_BY_FACTORY) && defined(__linux__)
3#include "../Core/Factory.h"
5
7{
8// density_matrix backend. Owns exactly one native Gpu implementation.
9class GpuDensityMatrixSimulator : public ImmediateGpuSimulator
10{
11 public:
12 GpuDensityMatrixSimulator()
13 {
14 configuration.SetConfiguration("method", "density_matrix");
15 }
16
17 const char *MethodName() const override
18 {
19 return "density_matrix";
20 }
21
22 void Initialize() override
23 {
24 if (nrQubits)
25 {
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));
32 {
33 densityMatrix = SimulatorsFactory::CreateGpuDensityMatrix(gpuDevice);
34 if (!densityMatrix)
35 throw std::runtime_error("GpuState::Initialize: Failed to create the density matrix "
36 "state.");
37 for (const auto &[key, value] : configuration.GetConfigMap())
38 if (key != "method")
39 Configure(key.c_str(), value.c_str());
40 if (!densityMatrix->Create(nrQubits))
41 throw std::runtime_error("GpuState::Initialize: Failed to initialize the density matrix "
42 "state.");
43 }
44 if (GetGpuDevice() != gpuDevice)
45 throw std::runtime_error("GpuState::Initialize: GPU plugin did not confirm the requested "
46 "device; update the GPU library");
47 }
48 }
49
50 void InitializeState(size_t num_qubits, std::vector<std::complex<double>> &amplitudes) override
51 {
52 if (num_qubits == 0)
53 return;
54 Clear();
55 nrQubits = num_qubits;
56 Initialize();
57 const bool created = densityMatrix->CreateWithState(nrQubits, reinterpret_cast<const double *>(amplitudes.data()));
58 if (!created)
59 throw std::runtime_error("GpuState::InitializeState: Failed to initialize the state.");
60 }
61
62#ifndef NO_QISKIT_AER
63 void InitializeState(size_t num_qubits, AER::Vector<std::complex<double>> &amplitudes) override
64 {
65 if (num_qubits == 0)
66 return;
67 Clear();
68 nrQubits = num_qubits;
69 Initialize();
70 const bool created = densityMatrix->CreateWithState(nrQubits, reinterpret_cast<const double *>(amplitudes.data()));
71 if (!created)
72 throw std::runtime_error("GpuState::InitializeState: Failed to initialize the state.");
73 }
74
75#endif
76
77 void InitializeState(size_t num_qubits, Eigen::VectorXcd &amplitudes) override
78 {
79 if (num_qubits == 0)
80 return;
81 Clear();
82 nrQubits = num_qubits;
83 Initialize();
84 const bool created = densityMatrix->CreateWithState(nrQubits, reinterpret_cast<const double *>(amplitudes.data()));
85 if (!created)
86 throw std::runtime_error("GpuState::InitializeState: Failed to initialize the state.");
87 }
88
89 void InitializeToBasisState(size_t num_qubits, Types::qubit_t basisState) override
90 {
91 if (num_qubits == 0)
92 return;
93 Clear();
94 nrQubits = num_qubits;
95 Initialize();
96 const bool created = densityMatrix->CreateWithBasisState(nrQubits, static_cast<unsigned long long>(basisState));
97 if (!created)
98 throw std::runtime_error("GpuState::InitializeToBasisState: Failed to initialize the "
99 "state.");
100 }
101
102 void InitializeToMixtureOfBasisStates(size_t num_qubits, const std::vector<std::pair<Types::qubit_t, double>> &mixture) override
103 {
104 if (num_qubits == 0)
105 return;
106 Clear();
107 nrQubits = num_qubits;
108 Initialize();
109 std::vector<std::pair<unsigned long long, double>> converted;
110 converted.reserve(mixture.size());
111 for (const auto &[basisState, weight] : mixture)
112 converted.emplace_back(static_cast<unsigned long long>(basisState), weight);
113 const bool created = densityMatrix->CreateWithMixtureOfBasisStates(nrQubits, converted);
114 if (!created)
115 throw std::runtime_error("GpuState::InitializeToMixtureOfBasisStates: Failed to initialize "
116 "the state.");
117 }
118
119 void Reset() override
120 {
121 if (densityMatrix)
122 densityMatrix->Reset();
123 upcomingGateIndex = 0;
124 }
125
126 void Configure(const char *key, const char *value) override
127 {
128 if (!key || !value)
129 return;
130 if (std::string("gpu_device") == key)
131 {
132 const int device = Configuration::ParseGpuDevice(value);
133 if ((densityMatrix) && device != Configuration::ParseGpuDevice(configuration.GetConfiguration(key)))
134 throw std::invalid_argument("gpu_device cannot change after initialization; clear the "
135 "simulator first");
136 configuration.SetConfiguration(key, std::to_string(device));
137 return;
138 }
139 const auto svdGroup = Configuration::GpuSvdSettingGroup(key);
140 if (!svdGroup.empty())
141 {
142 Configuration::ParseGpuSvdFlag(value);
143 configuration.SetConfiguration(key, value);
144 return;
145 }
146 if (std::string("method") == key)
147 {
148 ValidateMethod(value);
149 configuration.SetConfiguration(key, value);
150 return;
151 }
152 if (std::string(key) == "precision" || std::string(key) == "use_double_precision")
153 {
154 // Precision is immutable after native storage is allocated.
155 // Replayed settings take effect after Clear and Initialize.
156 const bool useDouble = Configuration::ParsePrecision(key, value);
157 if ((densityMatrix && densityMatrix->IsCreated()))
158 return;
159 if (densityMatrix)
160 densityMatrix->SetDataType(useDouble);
161 configuration.SetConfiguration(key, value);
162 return;
163 }
164 if (!configuration.WasApplied(key, value))
165 configuration.SetConfiguration(key, value);
166 if (std::string("seed") == key)
167 {
168 const uint64_t seed = std::stoull(value);
169 SeedAuxiliaryRng(seed);
170 nextSeedStream = 0;
171 if (densityMatrix)
172 densityMatrix->SetSeed(seed);
173 return;
174 }
175 // Configuration can be replayed from another method. Preserve the
176 // numeric validation, but tensor truncation has no native effect here.
177 if (std::string("matrix_product_state_truncation_threshold") == key || std::string("matrix_product_operator_truncation_threshold") == key)
178 std::stod(value);
179 else if (std::string("matrix_product_state_max_bond_dimension") == key || std::string("matrix_product_operator_max_bond_dimension") == key)
180 std::stoi(value);
181 }
182
183 std::string GetConfiguration(const char *key) const override
184 {
185 if (!key)
186 return {};
187 if (std::string(key) == "precision" || std::string(key) == "use_double_precision")
188 {
189 const bool useDouble = densityMatrix ? densityMatrix->IsDoublePrecision() : configuration.GetConfiguration("precision") == "double";
190 return std::string(key) == "precision" ? (useDouble ? "double" : "single") : (useDouble ? "1" : "0");
191 }
192 if (!key)
193 return {};
194 if (std::string("method") == key)
195 return MethodName();
196 return configuration.GetConfiguration(key);
197 }
198
199 size_t AllocateQubits(size_t num_qubits) override
200 {
201 if (densityMatrix)
202 return 0;
203 const size_t oldNrQubits = nrQubits;
204 nrQubits += num_qubits;
205 return oldNrQubits;
206 }
207
208 void Clear() override
209 {
210 densityMatrix = nullptr;
211 nrQubits = 0;
212 upcomingGateIndex = 0;
213 upcomingGates.clear();
214 }
215
216 size_t Measure(const Types::qubits_vector &qubits) override
217 {
218 if (qubits.size() > sizeof(size_t) * 8)
219 std::cerr << "Warning: The number of qubits to measure is larger than the "
220 "number of bits in the size_t type, the outcome will be undefined"
221 << std::endl;
222 size_t res = 0;
223 size_t mask = 1ULL;
224 DontNotify();
225 {
226 for (size_t qubit : qubits)
227 {
228 if (densityMatrix->Measure(static_cast<unsigned int>(qubit)))
229 res |= mask;
230 mask <<= 1;
231 }
232 }
233 Notify();
234 NotifyObservers(qubits);
235 return res;
236 }
237
238 std::vector<bool> MeasureMany(const Types::qubits_vector &qubits) override
239 {
240 std::vector<bool> res(qubits.size(), false);
241 DontNotify();
242 {
243 for (size_t i = 0; i < qubits.size(); ++i)
244 res[i] = densityMatrix->Measure(qubits[i]);
245 }
246 Notify();
247 NotifyObservers(qubits);
248 return res;
249 }
250
251 void ApplyReset(const Types::qubits_vector &qubits) override
252 {
253 DontNotify();
254 {
255 for (size_t qubit : qubits)
256 densityMatrix->ApplyReset(qubit);
257 }
258 Notify();
259 NotifyObservers(qubits);
260 }
261
262 bool SupportsQuantumChannels() const override
263 {
264 return true;
265 }
266
267 void ApplyQuantumChannel(const Types::qubits_vector &targets, const QuantumChannel &channel) override
268 {
269 if (!densityMatrix)
270 throw std::runtime_error("GPU quantum channels require an initialized density matrix or "
271 "matrix product operator");
272 if (targets.size() != channel.GetNumberOfQubits() || targets.empty() || targets.size() > 2)
273 throw std::invalid_argument("GPU density matrices and matrix product operators support one- "
274 "and two-qubit local channels");
275 std::vector<int> gpuTargets;
276 gpuTargets.reserve(targets.size());
277 for (auto target : targets)
278 {
279 if (target >= nrQubits || std::find(gpuTargets.begin(), gpuTargets.end(), target) != gpuTargets.end())
280 throw std::invalid_argument("Invalid GPU quantum-channel target");
281 gpuTargets.push_back(static_cast<int>(target));
282 }
283 const auto &kraus = channel.GetKrausOperators();
284 std::vector<double> interleaved;
285 interleaved.reserve(kraus.size() * kraus.front().size() * 2);
286 for (const auto &op : kraus)
287 for (Eigen::Index i = 0; i < op.size(); ++i)
288 {
289 interleaved.push_back(op.data()[i].real());
290 interleaved.push_back(op.data()[i].imag());
291 }
292 const bool applied = densityMatrix->ApplyKraus(gpuTargets, kraus.size(), interleaved.data());
293 if (!applied)
294 throw std::runtime_error("GPU density-matrix/matrix-product-operator channel application "
295 "failed");
296 NotifyObservers(targets);
297 }
298
299 std::complex<double> DensityMatrixTrace() const override
300 {
301 if (densityMatrix)
302 return densityMatrix->Trace();
303 throw std::runtime_error("GPU mixed-state diagnostics require density_matrix or "
304 "matrix_product_operator");
305 }
306
307 double DensityMatrixPurity() const override
308 {
309 if (densityMatrix)
310 return densityMatrix->Purity();
311 throw std::runtime_error("GPU mixed-state diagnostics require density_matrix or "
312 "matrix_product_operator");
313 }
314
315 std::complex<double> DensityMatrixTraceOfSquare() const override
316 {
317 if (densityMatrix)
318 {
319 const double tr = densityMatrix->Trace();
320 return densityMatrix->Purity() * tr * tr;
321 }
322 throw std::runtime_error("GPU mixed-state diagnostics require density_matrix or "
323 "matrix_product_operator");
324 }
325
326 std::complex<double> DensityMatrixOverlap(const IState &other) const override
327 {
328 const auto *rhs = dynamic_cast<const GpuDensityMatrixSimulator *>(&other);
329 if (!rhs)
330 throw std::invalid_argument("Density-matrix overlap requires matching GPU backends");
331 if (densityMatrix && rhs->densityMatrix)
332 return densityMatrix->HilbertSchmidtOverlap(*rhs->densityMatrix);
333 throw std::invalid_argument("Density-matrix overlap requires two density matrices or two MPOs");
334 }
335
336 double DensityMatrixHermiticityResidual() const override
337 {
338 if (densityMatrix)
339 return densityMatrix->IsHermitian() ? 0. : std::numeric_limits<double>::infinity();
340 throw std::runtime_error("GPU mixed-state diagnostics require density_matrix or "
341 "matrix_product_operator");
342 }
343
344 bool IsDensityMatrixHermitian(double eps = 1e-10) const override
345 {
346 if (densityMatrix)
347 return densityMatrix->IsHermitian(eps);
348 throw std::runtime_error("GPU mixed-state diagnostics require density_matrix or "
349 "matrix_product_operator");
350 }
351
352 Eigen::MatrixXcd PartialTrace(const Types::qubits_vector &qubits) const override
353 {
354 std::vector<int> keep(qubits.begin(), qubits.end());
355 const auto values = densityMatrix ? densityMatrix->PartialTrace(keep) : throw std::runtime_error("GPU partial trace requires a mixed-state backend");
356 const Eigen::Index dim = static_cast<Eigen::Index>(size_t{1} << keep.size());
357 return Eigen::Map<const Eigen::MatrixXcd>(values.data(), dim, dim);
358 }
359
360 double FidelityWithStatevector(const Eigen::VectorXcd &psi) const override
361 {
362 std::vector<double> raw(2 * static_cast<size_t>(psi.size()));
363 for (Eigen::Index i = 0; i < psi.size(); ++i)
364 {
365 raw[2 * i] = psi[i].real();
366 raw[2 * i + 1] = psi[i].imag();
367 }
368 if (densityMatrix)
369 return densityMatrix->FidelityWithStatevector(raw.data());
370 throw std::runtime_error("GPU mixed-state fidelity requires density_matrix or "
371 "matrix_product_operator");
372 }
373
374 double Probability(Types::qubit_t outcome) override
375 {
376 return densityMatrix->Probability(outcome);
377 }
378
379 std::complex<double> Amplitude(Types::qubit_t outcome) override
380 {
381 throw std::runtime_error("GpuState::Amplitude: Amplitudes are not defined for density "
382 "matrices.");
383 }
384
385 std::vector<double> AllProbabilities() override
386 {
387 if (nrQubits == 0)
388 return {};
389 if (nrQubits >= std::numeric_limits<size_t>::digits)
390 throw std::length_error("Full probability enumeration exceeds the basis-index API; query "
391 "selected bit vectors");
392 const size_t numStates = size_t{1} << nrQubits;
393 std::vector<double> result(numStates);
394 densityMatrix->AllProbabilities(result.data());
395 return result;
396 }
397
398 std::vector<double> Probabilities(const Types::qubits_vector &qubits) override
399 {
400 std::vector<double> result(qubits.size());
401 {
402 for (size_t i = 0; i < qubits.size(); ++i)
403 result[i] = densityMatrix->Probability(qubits[i]);
404 }
405 return result;
406 }
407
408 std::unordered_map<Types::qubit_t, Types::qubit_t> SampleCounts(const Types::qubits_vector &qubits, size_t shots = 1000) override
409 {
410 if (qubits.empty() || shots == 0)
411 return {};
412 if (qubits.size() > sizeof(Types::qubit_t) * 8)
413 std::cerr << "Warning: The number of qubits to measure is larger than the "
414 "number of bits in the Types::qubit_t type, the outcome will be "
415 "undefined"
416 << std::endl;
417 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
418 DontNotify();
419 {
420 std::vector<long int> samples(shots);
421 if (!densityMatrix->SampleAll(shots, samples.data()))
422 {
423 Notify();
424 throw std::runtime_error("GpuState::SampleCounts: Density-matrix sampling failed.");
425 }
426 for (auto outcome : samples)
427 {
428 Types::qubit_t translatedOutcome = 0;
429 for (size_t i = 0; i < qubits.size(); ++i)
430 if (outcome & (1ULL << qubits[i]))
431 translatedOutcome |= 1ULL << i;
432 ++result[translatedOutcome];
433 }
434 }
435 Notify();
436 NotifyObservers(qubits);
437 return result;
438 }
439
440 std::unordered_map<std::vector<bool>, Types::qubit_t> SampleCountsMany(const Types::qubits_vector &qubits, size_t shots = 1000) override
441 {
442 if (qubits.empty() || shots == 0)
443 return {};
444 std::unordered_map<std::vector<bool>, Types::qubit_t> result;
445 DontNotify();
446 {
447 std::vector<long int> samples(shots);
448 if (!densityMatrix->SampleAll(shots, samples.data()))
449 {
450 Notify();
451 throw std::runtime_error("GpuState::SampleCountsMany: Density-matrix sampling failed.");
452 }
453 std::vector<bool> outcomeVec(qubits.size());
454 for (auto outcome : samples)
455 {
456 for (size_t i = 0; i < qubits.size(); ++i)
457 outcomeVec[i] = ((outcome >> qubits[i]) & 1) != 0;
458 ++result[outcomeVec];
459 }
460 }
461 Notify();
462 NotifyObservers(qubits);
463 return result;
464 }
465
466 double ExpectationValue(const std::string &pauliString) override
467 {
468 double result = 0.0;
469 result = densityMatrix->ExpectationValue(pauliString);
470 return result;
471 }
472
473 int GetGpuDevice() const override
474 {
475 if (densityMatrix)
476 return densityMatrix->GetGpuDevice();
477 return -1;
478 }
479
480 SimulationType GetSimulationType() const override
481 {
482 return SimulationType::kDensityMatrix;
483 }
484
485 void Flush() override
486 {
487 const bool done = densityMatrix ? densityMatrix->Synchronize() : true;
488 if (!done)
489 throw std::runtime_error("GpuState::Flush: device synchronization failed");
490 }
491
492 void SaveState() override
493 {
494 densityMatrix->SaveState();
495 }
496
497 void RestoreState() override
498 {
499 densityMatrix->RestoreState();
500 }
501
503 {
504 std::vector<long int> samples(1);
505 if (!densityMatrix->SampleAll(1, samples.data()))
506 throw std::runtime_error("GpuState::MeasureNoCollapse: Density-matrix sampling failed.");
507 return static_cast<Types::qubit_t>(samples.front());
508 }
509
510 std::vector<bool> MeasureNoCollapseMany() override
511 {
512 std::vector<long int> samples(1);
513 if (!densityMatrix->SampleAll(1, samples.data()))
514 throw std::runtime_error("GpuState::MeasureNoCollapseMany: Density-matrix sampling failed.");
515 std::vector<bool> result(nrQubits, false);
516 for (size_t i = 0; i < nrQubits; ++i)
517 result[i] = ((samples.front() >> i) & 1) != 0;
518 return result;
519 }
520
521 void ApplyGenericOneQubitGate(Types::qubit_t qubit, const Eigen::Matrix2cd &gate) override
522 {
523 ApplyQuantumChannel({qubit}, QuantumChannel({gate}));
524 return;
525 }
526
527 void ApplyGenericTwoQubitGate(Types::qubit_t qubit0, Types::qubit_t qubit1, const Eigen::Matrix4cd &gate) override
528 {
529 ApplyQuantumChannel({qubit0, qubit1}, QuantumChannel({gate}));
530 return;
531 }
532
533 void ApplyP(Types::qubit_t qubit, double lambda) override
534 {
535 densityMatrix->ApplyP(qubit, lambda);
536 NotifyObservers({qubit});
537 }
538
539 void ApplyX(Types::qubit_t qubit) override
540 {
541 densityMatrix->ApplyX(qubit);
542 NotifyObservers({qubit});
543 }
544
545 void ApplyY(Types::qubit_t qubit) override
546 {
547 densityMatrix->ApplyY(qubit);
548 NotifyObservers({qubit});
549 }
550
551 void ApplyZ(Types::qubit_t qubit) override
552 {
553 densityMatrix->ApplyZ(qubit);
554 NotifyObservers({qubit});
555 }
556
557 void ApplyH(Types::qubit_t qubit) override
558 {
559 densityMatrix->ApplyH(qubit);
560 NotifyObservers({qubit});
561 }
562
563 void ApplyS(Types::qubit_t qubit) override
564 {
565 densityMatrix->ApplyS(qubit);
566 NotifyObservers({qubit});
567 }
568
569 void ApplySDG(Types::qubit_t qubit) override
570 {
571 densityMatrix->ApplySDG(qubit);
572 NotifyObservers({qubit});
573 }
574
575 void ApplyT(Types::qubit_t qubit) override
576 {
577 densityMatrix->ApplyT(qubit);
578 NotifyObservers({qubit});
579 }
580
581 void ApplyTDG(Types::qubit_t qubit) override
582 {
583 densityMatrix->ApplyTDG(qubit);
584 NotifyObservers({qubit});
585 }
586
587 void ApplySx(Types::qubit_t qubit) override
588 {
589 densityMatrix->ApplySX(qubit);
590 NotifyObservers({qubit});
591 }
592
593 void ApplySxDAG(Types::qubit_t qubit) override
594 {
595 densityMatrix->ApplySXDG(qubit);
596 NotifyObservers({qubit});
597 }
598
599 void ApplyK(Types::qubit_t qubit) override
600 {
601 densityMatrix->ApplyK(qubit);
602 NotifyObservers({qubit});
603 }
604
605 void ApplyRx(Types::qubit_t qubit, double theta) override
606 {
607 densityMatrix->ApplyRx(qubit, theta);
608 NotifyObservers({qubit});
609 }
610
611 void ApplyRy(Types::qubit_t qubit, double theta) override
612 {
613 densityMatrix->ApplyRy(qubit, theta);
614 NotifyObservers({qubit});
615 }
616
617 void ApplyRz(Types::qubit_t qubit, double theta) override
618 {
619 densityMatrix->ApplyRz(qubit, theta);
620 NotifyObservers({qubit});
621 }
622
623 void ApplyU(Types::qubit_t qubit, double theta, double phi, double lambda, double gamma) override
624 {
625 densityMatrix->ApplyU(qubit, theta, phi, lambda, gamma);
626 NotifyObservers({qubit});
627 }
628
629 void ApplyCX(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
630 {
631 densityMatrix->ApplyCX(ctrl_qubit, tgt_qubit);
632 NotifyObservers({tgt_qubit, ctrl_qubit});
633 }
634
635 void ApplyCY(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
636 {
637 densityMatrix->ApplyCY(ctrl_qubit, tgt_qubit);
638 NotifyObservers({tgt_qubit, ctrl_qubit});
639 }
640
641 void ApplyCZ(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
642 {
643 densityMatrix->ApplyCZ(ctrl_qubit, tgt_qubit);
644 NotifyObservers({tgt_qubit, ctrl_qubit});
645 }
646
647 void ApplyCP(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double lambda) override
648 {
649 densityMatrix->ApplyCP(ctrl_qubit, tgt_qubit, lambda);
650 NotifyObservers({tgt_qubit, ctrl_qubit});
651 }
652
653 void ApplyCRx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
654 {
655 densityMatrix->ApplyCRx(ctrl_qubit, tgt_qubit, theta);
656 NotifyObservers({tgt_qubit, ctrl_qubit});
657 }
658
659 void ApplyCRy(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
660 {
661 densityMatrix->ApplyCRy(ctrl_qubit, tgt_qubit, theta);
662 NotifyObservers({tgt_qubit, ctrl_qubit});
663 }
664
665 void ApplyCRz(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta) override
666 {
667 densityMatrix->ApplyCRz(ctrl_qubit, tgt_qubit, theta);
668 NotifyObservers({tgt_qubit, ctrl_qubit});
669 }
670
671 void ApplyCH(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
672 {
673 densityMatrix->ApplyCH(ctrl_qubit, tgt_qubit);
674 NotifyObservers({tgt_qubit, ctrl_qubit});
675 }
676
677 void ApplyCSx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
678 {
679 densityMatrix->ApplyCSX(ctrl_qubit, tgt_qubit);
680 NotifyObservers({tgt_qubit, ctrl_qubit});
681 }
682
683 void ApplyCSxDAG(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override
684 {
685 densityMatrix->ApplyCSXDG(ctrl_qubit, tgt_qubit);
686 NotifyObservers({tgt_qubit, ctrl_qubit});
687 }
688
689 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1) override
690 {
691 densityMatrix->ApplySwap(qubit0, qubit1);
692 NotifyObservers({qubit1, qubit0});
693 }
694
695 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1, Types::qubit_t qubit2) override
696 {
697 densityMatrix->ApplyCCX(qubit0, qubit1, qubit2);
698 NotifyObservers({qubit0, qubit1, qubit2});
699 }
700
701 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0, Types::qubit_t qubit1) override
702 {
703 densityMatrix->ApplyCSwap(ctrl_qubit, qubit0, qubit1);
704 NotifyObservers({qubit1, qubit0, ctrl_qubit});
705 }
706
707 void ApplyCU(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit, double theta, double phi, double lambda, double gamma) override
708 {
709 densityMatrix->ApplyCU(ctrl_qubit, tgt_qubit, theta, phi, lambda, gamma);
710 NotifyObservers({tgt_qubit, ctrl_qubit});
711 }
712
713 std::unique_ptr<ISimulator> Clone() override
714 {
715 auto cloned = std::make_unique<GpuDensityMatrixSimulator>();
716 cloned->nrQubits = nrQubits;
717 cloned->upcomingGates = upcomingGates;
718 cloned->upcomingGateIndex = upcomingGateIndex;
719 cloned->configuration = configuration;
720 if (densityMatrix)
721 {
722 cloned->densityMatrix = densityMatrix->Clone();
723 if (!cloned->densityMatrix)
724 throw std::runtime_error("GpuSimulator::Clone: Failed to clone density matrix state.");
725 }
726 if (configuration.IsSet("seed"))
727 cloned->SetSeed(DeriveSeed(std::stoull(configuration.GetConfiguration("seed")), nextSeedStream++));
728 return cloned;
729 }
730
731 protected:
732 std::unique_ptr<GpuDensityMatrix> densityMatrix;
733};
734} // namespace Simulators::Private
735#endif
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)
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 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 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)
int ApplyGenericOneQubitGate(void *sim, unsigned long q0, const double *buffer)
int ApplyGenericTwoQubitGate(void *sim, unsigned long q0, unsigned long q1, const double *buffer)
int SaveState(void *sim)
SimulationType
The type of simulation.
Definition State.h:109
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
Definition Types.h:24
uint_fast64_t qubit_t
The type of a qubit.
Definition Types.h:23