Maestro 0.3.1
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
Composite.h
Go to the documentation of this file.
1
14
15#pragma once
16
17#ifndef _COMPOSITE_H_
18#define _COMPOSITE_H_
19
20#ifdef INCLUDED_BY_FACTORY
21
22#include "Individual.h"
23
24#include <vector>
25
26#include "Configuration.h"
27
28namespace Simulators {
29
30// TODO: Maybe use the pimpl idiom
31// https://en.cppreference.com/w/cpp/language/pimpl to hide the implementation
32// for good but during development this should be good enough
33namespace Private {
34
44class CompositeSimulator : public ISimulator {
45 public:
53 CompositeSimulator(SimulatorType type =
54#ifdef NO_QISKIT_AER
56#else
58#endif
59 ) noexcept
60 : type(type) {
61 // just in case somebody tries to use a composite simulator composed of
62 // composite simulators or a gpu simulator - this one would work, but until
63 // we implement some supporting functionality with cuda, especially for
64 // composite probably it shouldn't be used splitting and merging is slow and
65 // it should be done in the videocard memory instead of using the cpu, if
66 // the gpu simulators are used otherwise the transfer from videocard memory
67 // and host memory back and forth is going to slow down the simulation quite
68 // a bit
69 if (
70#ifndef NO_QISKIT_AER
71 type != SimulatorType::kQiskitAer &&
72#endif
73 type != SimulatorType::kQCSim)
74 type =
75#ifdef NO_QISKIT_AER
77#else
79#endif
80 }
81
90 void Initialize() override {
91 qubitsMap.resize(nrQubits);
92
93 // start with one qubit simulators:
94 for (size_t q = 0; q < nrQubits; ++q) {
95 qubitsMap[q] = q;
96 auto sim = std::make_unique<IndividualSimulator>(type);
97 sim->AllocateQubits(1);
98
99 // this is for tests when we default to matrix product state simulator
100#if 0
101 sim->Configure("method", "statevector");
102#endif
103
104 sim->SetMultithreading(enableMultithreading);
105 sim->Initialize();
106 sim->GetQubitsMap()[q] = 0;
107 simulators[q] = std::move(sim);
108 }
109 nextId = nrQubits;
110 }
111
118 void Reset() override { Initialize(); }
119
132 void InitializeState(size_t num_qubits,
133 std::vector<std::complex<double>> &amplitudes) override {
134 throw std::runtime_error(
135 "CompositeSimulator::InitializeState not supported");
136 }
137
150 /*
151 void InitializeState(size_t num_qubits, std::vector<std::complex<double>,
152 avoid_init_allocator<std::complex<double>>>& amplitudes) override
153 {
154 throw std::runtime_error("CompositeSimulator::InitializeState not
155 supported");
156 }
157 */
158
171#ifndef NO_QISKIT_AER
172 void InitializeState(size_t num_qubits,
173 AER::Vector<std::complex<double>> &amplitudes) override {
174 throw std::runtime_error(
175 "CompositeSimulator::InitializeState not supported");
176 }
177#endif
178
191 void InitializeState(size_t num_qubits,
192 Eigen::VectorXcd &amplitudes) override {
193 throw std::runtime_error(
194 "CompositeSimulator::InitializeState not supported");
195 }
196
207 void Configure(const char *key, const char *value) override {
208 // don't allow chaning the method, it should stay statevector
209 if (std::string("method") == key) return;
210
211 config.SetConfiguration(key, value);
212
213 if (std::string("seed") == key) {
214 const uint64_t seed = std::stoull(value);
215 for (auto &[id, simulator] : simulators)
216 simulator->SetSeed(DeriveSeed(seed, id));
217 } else {
218 for (auto &[id, simulator] : simulators) simulator->Configure(key, value);
219 }
220 }
221
229 std::string GetConfiguration(const char *key) const override {
230 if (simulators.empty()) return "";
231
232 return config.GetConfiguration(key);
233 }
234
243 size_t AllocateQubits(size_t num_qubits) override {
244 if (!simulators.empty()) return 0;
245
246 const size_t oldNrQubits = nrQubits;
247 nrQubits += num_qubits;
248 return oldNrQubits;
249 }
250
257 size_t GetNumberOfQubits() const override { return nrQubits; }
258
266 void Clear() override {
267 simulators.clear();
268 qubitsMap.clear();
269 nrQubits = 0;
270 }
271
277 void SaveStateToInternalDestructive() override {
278 for (auto &[id, simulator] : simulators)
279 simulator->SaveStateToInternalDestructive();
280 }
281
289 for (auto &[id, simulator] : simulators)
290 simulator->RestoreInternalDestructiveSavedState();
291 }
292
301 std::complex<double> AmplitudeRaw(Types::qubit_t outcome) override {
302 std::complex<double> res = 1.0;
303
304 for (auto &[id, simulator] : simulators)
305 res *=
306 simulator->AmplitudeRaw(simulator->ConvertOutcomeFromGlobal(outcome));
307
308 return res;
309 }
310
321 size_t Measure(const Types::qubits_vector &qubits) override {
322 if (qubits.size() > sizeof(size_t) * 8)
323 std::cerr
324 << "Warning: The number of qubits to measure is larger than the "
325 "number of bits in the size_t type, the outcome will be undefined"
326 << std::endl;
327
328 size_t res = 0;
329 size_t mask = 1ULL;
330
331 DontNotify();
332 for (Types::qubit_t qubit : qubits) {
333 const bool outcome = GetSimulator(qubit)->Measure({qubit}) != 0;
334 if (outcome) res |= mask;
335 mask <<= 1;
336
337 Split(qubit, outcome);
338 }
339 Notify();
340
341 NotifyObservers(qubits);
342
343 return res;
344 }
345
352 std::vector<bool> MeasureMany(const Types::qubits_vector &qubits) override {
353 std::vector<bool> res(qubits.size(), false);
354
355 DontNotify();
356 for (size_t q = 0; q < qubits.size(); ++q) {
357 Types::qubit_t qubit = qubits[q];
358 const bool outcome = GetSimulator(qubit)->Measure({qubit}) != 0;
359 if (outcome) res[q] = true;
360
361 Split(qubit, outcome);
362 }
363 Notify();
364
365 NotifyObservers(qubits);
366
367 return res;
368 }
369
376 void ApplyReset(const Types::qubits_vector &qubits) override {
377 DontNotify();
378 for (Types::qubit_t qubit : qubits) {
379 GetSimulator(qubit)->ApplyReset({qubit});
380 Split(qubit, false);
381 }
382 Notify();
383
384 NotifyObservers(qubits);
385 }
386
396 double Probability(Types::qubit_t outcome) override {
397 return std::norm(Amplitude(outcome));
398 }
399
408 std::complex<double> Amplitude(Types::qubit_t outcome) override {
409 std::complex<double> res = 1.0;
410
411 for (auto &[id, simulator] : simulators)
412 res *= simulator->Amplitude(outcome);
413
414 return res;
415 }
416
430 std::complex<double> ProjectOnZero() override {
431 std::complex<double> res = 1.0;
432
433 for (auto &[id, simulator] : simulators)
434 res *= simulator->ProjectOnZero();
435
436 return res;
437 }
438
446 std::vector<double> AllProbabilities() override {
447 const size_t nrBasisStates = 1ULL << nrQubits;
448 std::vector<double> result;
449
450 for (size_t i = 0; i < nrBasisStates; ++i)
451 result.emplace_back(Probability(i));
452
453 return result;
454 }
455
465 std::vector<double> Probabilities(
466 const Types::qubits_vector &qubits) override {
467 std::vector<double> result;
468
469 for (size_t i = 0; i < qubits.size(); ++i)
470 result.emplace_back(Probability(qubits[i]));
471
472 return result;
473 }
474
491 std::unordered_map<Types::qubit_t, Types::qubit_t> SampleCounts(
492 const Types::qubits_vector &qubits, size_t shots = 1000) override {
493 if (GetNumberOfQubits() > sizeof(Types::qubit_t) * 8)
494 std::cerr
495 << "Warning: The number of qubits to measure is larger than the "
496 "number of bits in the Types::qubit_t type, the outcome will be "
497 "undefined"
498 << std::endl;
499 // TODO: improve it as for the qcsim statevector simulator case!
500 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
501 DontNotify();
502
504
505 if (shots > 1) {
506 InitializeAlias();
507
508 for (size_t shot = 0; shot < shots; ++shot) {
509 size_t measRaw = 0;
510 for (auto &[id, simulator] : simulators)
511 measRaw |= simulator->SampleFromAlias();
512
513 size_t meas = 0;
514 size_t mask = 1ULL;
515 for (auto q : qubits) {
516 const size_t qubitMask = 1ULL << q;
517 if ((measRaw & qubitMask) != 0) meas |= mask;
518 mask <<= 1ULL;
519 }
520
521 ++result[meas];
522 }
523
524 ClearAlias();
525 } else
526 for (size_t shot = 0; shot < shots; ++shot) {
527 const auto measRaw = MeasureNoCollapse();
528
529 size_t meas = 0;
530 size_t mask = 1ULL;
531 for (auto q : qubits) {
532 const size_t qubitMask = 1ULL << q;
533 if ((measRaw & qubitMask) != 0) meas |= mask;
534 mask <<= 1ULL;
535 }
536
537 ++result[meas];
538 }
539
541
542 Notify();
543 NotifyObservers(qubits);
544
545 return result;
546 }
547
561 std::unordered_map<std::vector<bool>, Types::qubit_t> SampleCountsMany(
562 const Types::qubits_vector &qubits, size_t shots = 1000) override {
563 std::unordered_map<std::vector<bool>, Types::qubit_t> result;
564 DontNotify();
565
567 std::vector<bool> meas(qubits.size());
568 if (shots > 1) {
569 InitializeAlias();
570
571 for (size_t shot = 0; shot < shots; ++shot) {
572 size_t measRaw = 0;
573 for (auto &[id, simulator] : simulators)
574 measRaw |= simulator->SampleFromAlias();
575
576 for (size_t i = 0; i < qubits.size(); ++i)
577 meas[i] = ((measRaw >> qubits[i]) & 1) == 1;
578
579 ++result[meas];
580 }
581
582 ClearAlias();
583 } else {
584 for (size_t shot = 0; shot < shots; ++shot) {
585 const auto measRaw = MeasureNoCollapseMany();
586
587 for (size_t i = 0; i < qubits.size(); ++i) meas[i] = measRaw[qubits[i]];
588
589 ++result[meas];
590 }
591 }
592
594
595 Notify();
596 NotifyObservers(qubits);
597
598 return result;
599 }
611 double ExpectationValue(const std::string &pauliString) override {
612 std::unordered_map<size_t, std::string> pauliStrings;
613
614 for (size_t q = 0; q < pauliString.size(); ++q) {
615 const char op = toupper(pauliString[q]);
616 if (op == 'I') continue;
617
618 const size_t simId = qubitsMap[q];
619 const size_t localQubit = simulators[simId]->GetQubitsMap().at(q);
620
621 if (pauliStrings[simId].size() <= localQubit)
622 pauliStrings[simId].resize(localQubit + 1, 'I');
623
624 pauliStrings[simId][localQubit] = op;
625 }
626
627 double result = 1.0;
628 for (auto &[id, localPauliString] : pauliStrings)
629 result *= simulators[id]->ExpectationValue(localPauliString);
630
631 return result;
632 }
633
641 SimulatorType GetType() const override {
642#ifdef NO_QISKIT_AER
643 return SimulatorType::kCompositeQCSim;
644#else
645 if (type != SimulatorType::kQiskitAer)
646 return SimulatorType::kCompositeQCSim;
647
648 return SimulatorType::kCompositeQiskitAer;
649#endif
650 }
651
660 SimulationType GetSimulationType() const override {
661 return SimulationType::kStatevector;
662 }
663
671 void Flush() override {
672 for (auto &[id, simulator] : simulators) simulator->Flush();
673 }
674
675
681 void ApplyGenericOneQubitGate(Types::qubit_t qubit,
682 const Eigen::Matrix2cd& gate) override {
683 GetSimulator(qubit)->ApplyGenericOneQubitGate(qubit, gate);
684 NotifyObservers({qubit});
685 }
686
693 void ApplyGenericTwoQubitGate(Types::qubit_t qubit0, Types::qubit_t qubit1,
694 const Eigen::Matrix4cd& gate) override {
695 JoinIfNeeded(qubit0, qubit1);
696 GetSimulator(qubit0)->ApplyGenericTwoQubitGate(qubit0, qubit1, gate);
697 NotifyObservers({qubit0, qubit1});
698 }
699
700 // YES, all one qubit gates are that easy:
701
709 void ApplyP(Types::qubit_t qubit, double lambda) override {
710 GetSimulator(qubit)->ApplyP(qubit, lambda);
711 NotifyObservers({qubit});
712 }
713
720 void ApplyX(Types::qubit_t qubit) override {
721 GetSimulator(qubit)->ApplyX(qubit);
722 NotifyObservers({qubit});
723 }
724
731 void ApplyY(Types::qubit_t qubit) override {
732 GetSimulator(qubit)->ApplyY(qubit);
733 NotifyObservers({qubit});
734 }
735
742 void ApplyZ(Types::qubit_t qubit) override {
743 GetSimulator(qubit)->ApplyZ(qubit);
744 NotifyObservers({qubit});
745 }
746
753 void ApplyH(Types::qubit_t qubit) override {
754 GetSimulator(qubit)->ApplyH(qubit);
755 NotifyObservers({qubit});
756 }
757
764 void ApplyS(Types::qubit_t qubit) override {
765 GetSimulator(qubit)->ApplyS(qubit);
766 NotifyObservers({qubit});
767 }
768
775 void ApplySDG(Types::qubit_t qubit) override {
776 GetSimulator(qubit)->ApplySDG(qubit);
777 NotifyObservers({qubit});
778 }
779
786 void ApplyT(Types::qubit_t qubit) override {
787 GetSimulator(qubit)->ApplyT(qubit);
788 NotifyObservers({qubit});
789 }
790
797 void ApplyTDG(Types::qubit_t qubit) override {
798 GetSimulator(qubit)->ApplyTDG(qubit);
799 NotifyObservers({qubit});
800 }
801
808 void ApplySx(Types::qubit_t qubit) override {
809 GetSimulator(qubit)->ApplySx(qubit);
810 NotifyObservers({qubit});
811 }
812
819 void ApplySxDAG(Types::qubit_t qubit) override {
820 GetSimulator(qubit)->ApplySxDAG(qubit);
821 NotifyObservers({qubit});
822 }
823
830 void ApplyK(Types::qubit_t qubit) override {
831 GetSimulator(qubit)->ApplyK(qubit);
832 NotifyObservers({qubit});
833 }
834
842 void ApplyRx(Types::qubit_t qubit, double theta) override {
843 GetSimulator(qubit)->ApplyRx(qubit, theta);
844 NotifyObservers({qubit});
845 }
846
854 void ApplyRy(Types::qubit_t qubit, double theta) override {
855 GetSimulator(qubit)->ApplyRy(qubit, theta);
856 NotifyObservers({qubit});
857 }
858
866 void ApplyRz(Types::qubit_t qubit, double theta) override {
867 GetSimulator(qubit)->ApplyRz(qubit, theta);
868 NotifyObservers({qubit});
869 }
870
881 void ApplyU(Types::qubit_t qubit, double theta, double phi, double lambda,
882 double gamma) override {
883 GetSimulator(qubit)->ApplyU(qubit, theta, phi, lambda, gamma);
884 NotifyObservers({qubit});
885 }
886
887 // the gates that operate on more than one qubit need joining of the
888 // simulators, if the qubits are in different simulators
889
897 void ApplyCX(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
898 JoinIfNeeded(ctrl_qubit, tgt_qubit);
899 GetSimulator(ctrl_qubit)->ApplyCX(ctrl_qubit, tgt_qubit);
900 NotifyObservers({tgt_qubit, ctrl_qubit});
901 }
902
910 void ApplyCY(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
911 JoinIfNeeded(ctrl_qubit, tgt_qubit);
912 GetSimulator(ctrl_qubit)->ApplyCY(ctrl_qubit, tgt_qubit);
913 NotifyObservers({tgt_qubit, ctrl_qubit});
914 }
915
923 void ApplyCZ(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
924 JoinIfNeeded(ctrl_qubit, tgt_qubit);
925 GetSimulator(ctrl_qubit)->ApplyCZ(ctrl_qubit, tgt_qubit);
926 NotifyObservers({tgt_qubit, ctrl_qubit});
927 }
928
937 void ApplyCP(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
938 double lambda) override {
939 JoinIfNeeded(ctrl_qubit, tgt_qubit);
940 GetSimulator(ctrl_qubit)->ApplyCP(ctrl_qubit, tgt_qubit, lambda);
941 NotifyObservers({tgt_qubit, ctrl_qubit});
942 }
943
952 void ApplyCRx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
953 double theta) override {
954 JoinIfNeeded(ctrl_qubit, tgt_qubit);
955 GetSimulator(ctrl_qubit)->ApplyCRx(ctrl_qubit, tgt_qubit, theta);
956 NotifyObservers({tgt_qubit, ctrl_qubit});
957 }
958
967 void ApplyCRy(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
968 double theta) override {
969 JoinIfNeeded(ctrl_qubit, tgt_qubit);
970 GetSimulator(ctrl_qubit)->ApplyCRy(ctrl_qubit, tgt_qubit, theta);
971 NotifyObservers({tgt_qubit, ctrl_qubit});
972 }
973
982 void ApplyCRz(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
983 double theta) override {
984 JoinIfNeeded(ctrl_qubit, tgt_qubit);
985 GetSimulator(ctrl_qubit)->ApplyCRz(ctrl_qubit, tgt_qubit, theta);
986 NotifyObservers({tgt_qubit, ctrl_qubit});
987 }
988
996 void ApplyCH(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
997 JoinIfNeeded(ctrl_qubit, tgt_qubit);
998 GetSimulator(ctrl_qubit)->ApplyCH(ctrl_qubit, tgt_qubit);
999 NotifyObservers({tgt_qubit, ctrl_qubit});
1000 }
1001
1009 void ApplyCSx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
1010 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1011 GetSimulator(ctrl_qubit)->ApplyCSx(ctrl_qubit, tgt_qubit);
1012 NotifyObservers({tgt_qubit, ctrl_qubit});
1013 }
1014
1022 void ApplyCSxDAG(Types::qubit_t ctrl_qubit,
1023 Types::qubit_t tgt_qubit) override {
1024 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1025 GetSimulator(ctrl_qubit)->ApplyCSxDAG(ctrl_qubit, tgt_qubit);
1026 NotifyObservers({tgt_qubit, ctrl_qubit});
1027 }
1028
1036 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1) override {
1037 JoinIfNeeded(qubit0, qubit1);
1038 GetSimulator(qubit0)->ApplySwap(qubit0, qubit1);
1039 NotifyObservers({qubit1, qubit0});
1040 }
1041
1050 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1,
1051 Types::qubit_t qubit2) override {
1052 // TODO: See if it's worth optimizing to joing all three simulators at once,
1053 // if needed (that is, there is a different one for each qubit)
1054 JoinIfNeeded(qubit0, qubit1);
1055 JoinIfNeeded(qubit0, qubit2);
1056 GetSimulator(qubit0)->ApplyCCX(qubit0, qubit1, qubit2);
1057 NotifyObservers({qubit2, qubit1, qubit0});
1058 }
1059
1068 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0,
1069 Types::qubit_t qubit1) override {
1070 // TODO: See if it's worth optimizing to joing all three simulators at once,
1071 // if needed (that is, there is a different one for each qubit)
1072 JoinIfNeeded(ctrl_qubit, qubit0);
1073 JoinIfNeeded(ctrl_qubit, qubit1);
1074 GetSimulator(ctrl_qubit)->ApplyCSwap(ctrl_qubit, qubit0, qubit1);
1075 NotifyObservers({qubit1, qubit0, ctrl_qubit});
1076 }
1077
1089 void ApplyCU(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
1090 double theta, double phi, double lambda, double gamma) override {
1091 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1092 GetSimulator(ctrl_qubit)
1093 ->ApplyCU(ctrl_qubit, tgt_qubit, theta, phi, lambda, gamma);
1094 NotifyObservers({tgt_qubit, ctrl_qubit});
1095 }
1096
1097 void ApplyNop() override { GetSimulator(0)->ApplyNop(); }
1098
1107 void SetMultithreading(bool multithreading = true) override {
1108 enableMultithreading = multithreading;
1109 for (auto &[id, simulator] : simulators)
1110 simulator->SetMultithreading(multithreading);
1111 }
1112
1120 bool GetMultithreading() const override { return enableMultithreading; }
1121
1132 bool IsQcsim() const override {
1133 return type == Simulators::SimulatorType::kQCSim;
1134 }
1135
1150 void SaveState() override { savedState = Clone(); }
1151
1165 void RestoreState() override {
1166 if (savedState) {
1167 const CompositeSimulator *savedStatePtr =
1168 static_cast<CompositeSimulator *>(savedState.get());
1169
1170 type =
1171 savedStatePtr->type;
1172 qubitsMap =
1173 savedStatePtr
1174 ->qubitsMap;
1176
1177 nrQubits =
1178 savedStatePtr->nrQubits;
1179 nextId = savedStatePtr
1180 ->nextId;
1181 enableMultithreading =
1182 savedStatePtr
1183 ->enableMultithreading;
1185
1186 simulators.clear();
1187 for (auto &[id, simulator] : savedStatePtr->simulators) {
1188 auto isim = simulator->Clone();
1189 simulators[id] = std::unique_ptr<IndividualSimulator>(
1190 static_cast<IndividualSimulator *>(isim.release()));
1191 }
1192 }
1193 }
1194
1212 Types::qubit_t res = 0;
1213
1214 if (GetNumberOfQubits() > sizeof(Types::qubit_t) * 8)
1215 std::cerr
1216 << "Warning: The number of qubits to measure is larger than the "
1217 "number of bits in the Types::qubit_t type, the outcome will be "
1218 "undefined"
1219 << std::endl;
1220
1221 for (auto &[id, simulator] : simulators) {
1222 const Types::qubit_t meas = simulator->MeasureNoCollapse();
1223 res |= meas;
1224 }
1225
1226 return res;
1227 }
1228
1243 std::vector<bool> MeasureNoCollapseMany() override {
1244 std::vector<bool> res(nrQubits, false);
1245 for (auto &[id, simulator] : simulators) {
1246 const std::vector<bool> meas = simulator->MeasureNoCollapseMany();
1247 for (size_t i = 0; i < meas.size(); ++i)
1248 if (meas[i]) res[i] = true;
1249 }
1250 return res;
1251 }
1252
1263 std::unique_ptr<ISimulator> Clone() override {
1264 auto clone = std::make_unique<CompositeSimulator>(type);
1265
1266 clone->type = type;
1267 clone->qubitsMap =
1268 qubitsMap;
1270
1271 clone->nrQubits = nrQubits;
1272 clone->nextId = nextId;
1273 clone->enableMultithreading =
1274 enableMultithreading;
1276
1277 clone->config = config;
1278
1279 for (auto &[id, simulator] : simulators) {
1280 auto isim = simulator->Clone();
1281 clone->simulators[id] = std::unique_ptr<IndividualSimulator>(
1282 static_cast<IndividualSimulator *>(isim.release()));
1283 }
1284
1285 if (savedState) clone->savedState = savedState->Clone();
1286
1287 return clone;
1288 }
1289
1290 const Configuration& GetConfiguration() const { return config; }
1291
1292 const std::unordered_map<std::string, std::string>& GetConfigMap()
1293 const override {
1294 return config.GetConfigMap();
1295 }
1296
1297 private:
1298 void InitializeAlias() {
1299 for (auto &[id, simulator] : simulators) simulator->InitializeAlias();
1300 }
1301
1302 void ClearAlias() {
1303 for (auto &[id, simulator] : simulators) simulator->ClearAlias();
1304 }
1305
1314 inline std::unique_ptr<IndividualSimulator> &GetSimulator(size_t qubit) {
1315 assert(qubitsMap.size() > qubit);
1316 assert(simulators.find(qubitsMap[qubit]) != simulators.end());
1317
1318 // assume it was called with a valid qubit
1319 return simulators[qubitsMap[qubit]];
1320 }
1321
1322 // if executing a gate on two or three qubits, use this to see if it can be
1323 // executed directly if it returns true, join the two simulators together and
1324 // execute the gate (for three qubits, do that once again for the third qubit,
1325 // before execution)
1336 inline bool JoinNeeded(size_t qubit1, size_t qubit2) {
1337 // TODO: Not really needed for all gates that act on multiple qubits, is
1338 // this worth pursuing? the obvious example is the identity gate, which does
1339 // nothing, so a join is not needed
1340 return qubitsMap[qubit1] != qubitsMap[qubit2];
1341 }
1342
1351 inline void JoinIfNeeded(size_t qubit1, size_t qubit2) {
1352 if (JoinNeeded(qubit1, qubit2)) {
1353 const size_t simId = qubitsMap[qubit1];
1354 const size_t eraseSimId = qubitsMap[qubit2];
1355 auto &sim1 = GetSimulator(qubit1);
1356 const auto &sim2 = GetSimulator(qubit2);
1357
1358 sim1->Join(simId, sim2, qubitsMap, enableMultithreading);
1359
1360 simulators.erase(eraseSimId);
1361 }
1362 }
1363
1374 inline void Split(size_t qubit, bool qubitOutcome = false) {
1375 auto &sim = GetSimulator(
1376 qubit); // get the simulator for the qubit, this one will be split
1377 if (sim->GetNumberOfQubits() ==
1378 1) // no need to split it, it's already for a single qubit
1379 return;
1380
1381 qubitsMap[qubit] = nextId; // the qubit will be in the new simulator
1382 simulators[nextId] = sim->Split(qubit, qubitOutcome, enableMultithreading);
1383
1384 ++nextId;
1385 }
1386
1387 SimulatorType type;
1388 std::vector<size_t>
1389 qubitsMap;
1391 std::unordered_map<size_t, std::unique_ptr<IndividualSimulator>>
1392 simulators;
1393 size_t nrQubits = 0;
1394 size_t nextId = 0;
1395 bool enableMultithreading =
1396 true;
1397
1398 std::unique_ptr<ISimulator> savedState;
1399
1400 Configuration config;
1401};
1402
1403} // namespace Private
1404} // namespace Simulators
1405
1406#endif
1407#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)
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 GetMultithreading(void *sim)
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 SetMultithreading(void *sim, int multithreading)
int ApplyCU(void *sim, int controlQubit, int targetQubit, double theta, double phi, double lambda, double gamma)
int ApplySwap(void *sim, int qubit1, int qubit2)
void * GetSimulator(unsigned long int simHandle)
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 IsQcsim(void *sim)
int SaveState(void *sim)
@ kQCSim
qcsim simulator type
Definition State.h:76
@ kQiskitAer
qiskit aer simulator type
Definition State.h:74
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
Definition Types.h:22
uint_fast64_t qubit_t
The type of a qubit.
Definition Types.h:21