Maestro 0.2.11
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
26namespace Simulators {
27
28// TODO: Maybe use the pimpl idiom
29// https://en.cppreference.com/w/cpp/language/pimpl to hide the implementation
30// for good but during development this should be good enough
31namespace Private {
32
42class CompositeSimulator : public ISimulator {
43 public:
51 CompositeSimulator(SimulatorType type =
52#ifdef NO_QISKIT_AER
54#else
56#endif
57 ) noexcept
58 : type(type) {
59 // just in case somebody tries to use a composite simulator composed of
60 // composite simulators or a gpu simulator - this one would work, but until
61 // we implement some supporting functionality with cuda, especially for
62 // composite probably it shouldn't be used splitting and merging is slow and
63 // it should be done in the videocard memory instead of using the cpu, if
64 // the gpu simulators are used otherwise the transfer from videocard memory
65 // and host memory back and forth is going to slow down the simulation quite
66 // a bit
67 if (
68#ifndef NO_QISKIT_AER
69 type != SimulatorType::kQiskitAer &&
70#endif
71 type != SimulatorType::kQCSim)
72 type =
73#ifdef NO_QISKIT_AER
75#else
77#endif
78 }
79
88 void Initialize() override {
89 qubitsMap.resize(nrQubits);
90
91 // start with one qubit simulators:
92 for (size_t q = 0; q < nrQubits; ++q) {
93 qubitsMap[q] = q;
94 auto sim = std::make_unique<IndividualSimulator>(type);
95 sim->AllocateQubits(1);
96
97 // this is for tests when we default to matrix product state simulator
98#if 0
99 sim->Configure("method", "statevector");
100#endif
101
102 sim->SetMultithreading(enableMultithreading);
103 sim->Initialize();
104 sim->GetQubitsMap()[q] = 0;
105 simulators[q] = std::move(sim);
106 }
107 nextId = nrQubits;
108 }
109
116 void Reset() override { Initialize(); }
117
130 void InitializeState(size_t num_qubits,
131 std::vector<std::complex<double>> &amplitudes) override {
132 throw std::runtime_error(
133 "CompositeSimulator::InitializeState not supported");
134 }
135
148 /*
149 void InitializeState(size_t num_qubits, std::vector<std::complex<double>,
150 avoid_init_allocator<std::complex<double>>>& amplitudes) override
151 {
152 throw std::runtime_error("CompositeSimulator::InitializeState not
153 supported");
154 }
155 */
156
169#ifndef NO_QISKIT_AER
170 void InitializeState(size_t num_qubits,
171 AER::Vector<std::complex<double>> &amplitudes) override {
172 throw std::runtime_error(
173 "CompositeSimulator::InitializeState not supported");
174 }
175#endif
176
189 void InitializeState(size_t num_qubits,
190 Eigen::VectorXcd &amplitudes) override {
191 throw std::runtime_error(
192 "CompositeSimulator::InitializeState not supported");
193 }
194
205 void Configure(const char *key, const char *value) override {
206 // don't allow chaning the method, it should stay statevector
207 if (std::string("method") == key) return;
208
209 for (auto &[id, simulator] : simulators) simulator->Configure(key, value);
210 }
211
219 std::string GetConfiguration(const char *key) const override {
220 if (simulators.empty()) return "";
221
222 return simulators.begin()->second->GetConfiguration(key);
223 }
224
233 size_t AllocateQubits(size_t num_qubits) override {
234 if (!simulators.empty()) return 0;
235
236 const size_t oldNrQubits = nrQubits;
237 nrQubits += num_qubits;
238 return oldNrQubits;
239 }
240
247 size_t GetNumberOfQubits() const override { return nrQubits; }
248
256 void Clear() override {
257 simulators.clear();
258 qubitsMap.clear();
259 nrQubits = 0;
260 }
261
267 void SaveStateToInternalDestructive() override {
268 for (auto &[id, simulator] : simulators)
269 simulator->SaveStateToInternalDestructive();
270 }
271
279 for (auto &[id, simulator] : simulators)
280 simulator->RestoreInternalDestructiveSavedState();
281 }
282
291 std::complex<double> AmplitudeRaw(Types::qubit_t outcome) override {
292 std::complex<double> res = 1.0;
293
294 for (auto &[id, simulator] : simulators)
295 res *=
296 simulator->AmplitudeRaw(simulator->ConvertOutcomeFromGlobal(outcome));
297
298 return res;
299 }
300
311 size_t Measure(const Types::qubits_vector &qubits) override {
312 if (qubits.size() > sizeof(size_t) * 8)
313 std::cerr
314 << "Warning: The number of qubits to measure is larger than the "
315 "number of bits in the size_t type, the outcome will be undefined"
316 << std::endl;
317
318 size_t res = 0;
319 size_t mask = 1ULL;
320
321 DontNotify();
322 for (Types::qubit_t qubit : qubits) {
323 const bool outcome = GetSimulator(qubit)->Measure({qubit}) != 0;
324 if (outcome) res |= mask;
325 mask <<= 1;
326
327 Split(qubit, outcome);
328 }
329 Notify();
330
331 NotifyObservers(qubits);
332
333 return res;
334 }
335
342 std::vector<bool> MeasureMany(const Types::qubits_vector &qubits) override {
343 std::vector<bool> res(qubits.size(), false);
344
345 DontNotify();
346 for (size_t q = 0; q < qubits.size(); ++q) {
347 Types::qubit_t qubit = qubits[q];
348 const bool outcome = GetSimulator(qubit)->Measure({qubit}) != 0;
349 if (outcome) res[q] = true;
350
351 Split(qubit, outcome);
352 }
353 Notify();
354
355 NotifyObservers(qubits);
356
357 return res;
358 }
359
366 void ApplyReset(const Types::qubits_vector &qubits) override {
367 DontNotify();
368 for (Types::qubit_t qubit : qubits) {
369 GetSimulator(qubit)->ApplyReset({qubit});
370 Split(qubit, false);
371 }
372 Notify();
373
374 NotifyObservers(qubits);
375 }
376
386 double Probability(Types::qubit_t outcome) override {
387 return std::norm(Amplitude(outcome));
388 }
389
398 std::complex<double> Amplitude(Types::qubit_t outcome) override {
399 std::complex<double> res = 1.0;
400
401 for (auto &[id, simulator] : simulators)
402 res *= simulator->Amplitude(outcome);
403
404 return res;
405 }
406
420 std::complex<double> ProjectOnZero() override {
421 std::complex<double> res = 1.0;
422
423 for (auto &[id, simulator] : simulators)
424 res *= simulator->ProjectOnZero();
425
426 return res;
427 }
428
436 std::vector<double> AllProbabilities() override {
437 const size_t nrBasisStates = 1ULL << nrQubits;
438 std::vector<double> result;
439
440 for (size_t i = 0; i < nrBasisStates; ++i)
441 result.emplace_back(Probability(i));
442
443 return result;
444 }
445
455 std::vector<double> Probabilities(
456 const Types::qubits_vector &qubits) override {
457 std::vector<double> result;
458
459 for (size_t i = 0; i < qubits.size(); ++i)
460 result.emplace_back(Probability(qubits[i]));
461
462 return result;
463 }
464
481 std::unordered_map<Types::qubit_t, Types::qubit_t> SampleCounts(
482 const Types::qubits_vector &qubits, size_t shots = 1000) override {
483 if (GetNumberOfQubits() > sizeof(Types::qubit_t) * 8)
484 std::cerr
485 << "Warning: The number of qubits to measure is larger than the "
486 "number of bits in the Types::qubit_t type, the outcome will be "
487 "undefined"
488 << std::endl;
489 // TODO: improve it as for the qcsim statevector simulator case!
490 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
491 DontNotify();
492
494
495 if (shots > 1) {
496 InitializeAlias();
497
498 for (size_t shot = 0; shot < shots; ++shot) {
499 size_t measRaw = 0;
500 for (auto &[id, simulator] : simulators)
501 measRaw |= simulator->SampleFromAlias();
502
503 size_t meas = 0;
504 size_t mask = 1ULL;
505 for (auto q : qubits) {
506 const size_t qubitMask = 1ULL << q;
507 if ((measRaw & qubitMask) != 0) meas |= mask;
508 mask <<= 1ULL;
509 }
510
511 ++result[meas];
512 }
513
514 ClearAlias();
515 } else
516 for (size_t shot = 0; shot < shots; ++shot) {
517 const auto measRaw = MeasureNoCollapse();
518
519 size_t meas = 0;
520 size_t mask = 1ULL;
521 for (auto q : qubits) {
522 const size_t qubitMask = 1ULL << q;
523 if ((measRaw & qubitMask) != 0) meas |= mask;
524 mask <<= 1ULL;
525 }
526
527 ++result[meas];
528 }
529
531
532 Notify();
533 NotifyObservers(qubits);
534
535 return result;
536 }
537
551 std::unordered_map<std::vector<bool>, Types::qubit_t> SampleCountsMany(
552 const Types::qubits_vector &qubits, size_t shots = 1000) override {
553 std::unordered_map<std::vector<bool>, Types::qubit_t> result;
554 DontNotify();
555
557 std::vector<bool> meas(qubits.size());
558 if (shots > 1) {
559 InitializeAlias();
560
561 for (size_t shot = 0; shot < shots; ++shot) {
562 size_t measRaw = 0;
563 for (auto &[id, simulator] : simulators)
564 measRaw |= simulator->SampleFromAlias();
565
566 for (size_t i = 0; i < qubits.size(); ++i)
567 meas[i] = ((measRaw >> qubits[i]) & 1) == 1;
568
569 ++result[meas];
570 }
571
572 ClearAlias();
573 } else {
574 for (size_t shot = 0; shot < shots; ++shot) {
575 const auto measRaw = MeasureNoCollapseMany();
576
577 for (size_t i = 0; i < qubits.size(); ++i) meas[i] = measRaw[qubits[i]];
578
579 ++result[meas];
580 }
581 }
582
584
585 Notify();
586 NotifyObservers(qubits);
587
588 return result;
589 }
601 double ExpectationValue(const std::string &pauliString) override {
602 std::unordered_map<size_t, std::string> pauliStrings;
603
604 for (size_t q = 0; q < pauliString.size(); ++q) {
605 const char op = toupper(pauliString[q]);
606 if (op == 'I') continue;
607
608 const size_t simId = qubitsMap[q];
609 const size_t localQubit = simulators[simId]->GetQubitsMap().at(q);
610
611 if (pauliStrings[simId].size() <= localQubit)
612 pauliStrings[simId].resize(localQubit + 1, 'I');
613
614 pauliStrings[simId][localQubit] = op;
615 }
616
617 double result = 1.0;
618 for (auto &[id, localPauliString] : pauliStrings)
619 result *= simulators[id]->ExpectationValue(localPauliString);
620
621 return result;
622 }
623
631 SimulatorType GetType() const override {
632#ifdef NO_QISKIT_AER
633 return SimulatorType::kCompositeQCSim;
634#else
635 if (type != SimulatorType::kQiskitAer)
636 return SimulatorType::kCompositeQCSim;
637
638 return SimulatorType::kCompositeQiskitAer;
639#endif
640 }
641
650 SimulationType GetSimulationType() const override {
651 return SimulationType::kStatevector;
652 }
653
661 void Flush() override {
662 for (auto &[id, simulator] : simulators) simulator->Flush();
663 }
664
665
671 void ApplyGenericOneQubitGate(Types::qubit_t qubit,
672 const Eigen::Matrix2cd& gate) override {
673 GetSimulator(qubit)->ApplyGenericOneQubitGate(qubit, gate);
674 NotifyObservers({qubit});
675 }
676
683 void ApplyGenericTwoQubitGate(Types::qubit_t qubit0, Types::qubit_t qubit1,
684 const Eigen::Matrix4cd& gate) override {
685 JoinIfNeeded(qubit0, qubit1);
686 GetSimulator(qubit0)->ApplyGenericTwoQubitGate(qubit0, qubit1, gate);
687 NotifyObservers({qubit0, qubit1});
688 }
689
690 // YES, all one qubit gates are that easy:
691
699 void ApplyP(Types::qubit_t qubit, double lambda) override {
700 GetSimulator(qubit)->ApplyP(qubit, lambda);
701 NotifyObservers({qubit});
702 }
703
710 void ApplyX(Types::qubit_t qubit) override {
711 GetSimulator(qubit)->ApplyX(qubit);
712 NotifyObservers({qubit});
713 }
714
721 void ApplyY(Types::qubit_t qubit) override {
722 GetSimulator(qubit)->ApplyY(qubit);
723 NotifyObservers({qubit});
724 }
725
732 void ApplyZ(Types::qubit_t qubit) override {
733 GetSimulator(qubit)->ApplyZ(qubit);
734 NotifyObservers({qubit});
735 }
736
743 void ApplyH(Types::qubit_t qubit) override {
744 GetSimulator(qubit)->ApplyH(qubit);
745 NotifyObservers({qubit});
746 }
747
754 void ApplyS(Types::qubit_t qubit) override {
755 GetSimulator(qubit)->ApplyS(qubit);
756 NotifyObservers({qubit});
757 }
758
765 void ApplySDG(Types::qubit_t qubit) override {
766 GetSimulator(qubit)->ApplySDG(qubit);
767 NotifyObservers({qubit});
768 }
769
776 void ApplyT(Types::qubit_t qubit) override {
777 GetSimulator(qubit)->ApplyT(qubit);
778 NotifyObservers({qubit});
779 }
780
787 void ApplyTDG(Types::qubit_t qubit) override {
788 GetSimulator(qubit)->ApplyTDG(qubit);
789 NotifyObservers({qubit});
790 }
791
798 void ApplySx(Types::qubit_t qubit) override {
799 GetSimulator(qubit)->ApplySx(qubit);
800 NotifyObservers({qubit});
801 }
802
809 void ApplySxDAG(Types::qubit_t qubit) override {
810 GetSimulator(qubit)->ApplySxDAG(qubit);
811 NotifyObservers({qubit});
812 }
813
820 void ApplyK(Types::qubit_t qubit) override {
821 GetSimulator(qubit)->ApplyK(qubit);
822 NotifyObservers({qubit});
823 }
824
832 void ApplyRx(Types::qubit_t qubit, double theta) override {
833 GetSimulator(qubit)->ApplyRx(qubit, theta);
834 NotifyObservers({qubit});
835 }
836
844 void ApplyRy(Types::qubit_t qubit, double theta) override {
845 GetSimulator(qubit)->ApplyRy(qubit, theta);
846 NotifyObservers({qubit});
847 }
848
856 void ApplyRz(Types::qubit_t qubit, double theta) override {
857 GetSimulator(qubit)->ApplyRz(qubit, theta);
858 NotifyObservers({qubit});
859 }
860
871 void ApplyU(Types::qubit_t qubit, double theta, double phi, double lambda,
872 double gamma) override {
873 GetSimulator(qubit)->ApplyU(qubit, theta, phi, lambda, gamma);
874 NotifyObservers({qubit});
875 }
876
877 // the gates that operate on more than one qubit need joining of the
878 // simulators, if the qubits are in different simulators
879
887 void ApplyCX(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
888 JoinIfNeeded(ctrl_qubit, tgt_qubit);
889 GetSimulator(ctrl_qubit)->ApplyCX(ctrl_qubit, tgt_qubit);
890 NotifyObservers({tgt_qubit, ctrl_qubit});
891 }
892
900 void ApplyCY(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
901 JoinIfNeeded(ctrl_qubit, tgt_qubit);
902 GetSimulator(ctrl_qubit)->ApplyCY(ctrl_qubit, tgt_qubit);
903 NotifyObservers({tgt_qubit, ctrl_qubit});
904 }
905
913 void ApplyCZ(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
914 JoinIfNeeded(ctrl_qubit, tgt_qubit);
915 GetSimulator(ctrl_qubit)->ApplyCZ(ctrl_qubit, tgt_qubit);
916 NotifyObservers({tgt_qubit, ctrl_qubit});
917 }
918
927 void ApplyCP(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
928 double lambda) override {
929 JoinIfNeeded(ctrl_qubit, tgt_qubit);
930 GetSimulator(ctrl_qubit)->ApplyCP(ctrl_qubit, tgt_qubit, lambda);
931 NotifyObservers({tgt_qubit, ctrl_qubit});
932 }
933
942 void ApplyCRx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
943 double theta) override {
944 JoinIfNeeded(ctrl_qubit, tgt_qubit);
945 GetSimulator(ctrl_qubit)->ApplyCRx(ctrl_qubit, tgt_qubit, theta);
946 NotifyObservers({tgt_qubit, ctrl_qubit});
947 }
948
957 void ApplyCRy(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
958 double theta) override {
959 JoinIfNeeded(ctrl_qubit, tgt_qubit);
960 GetSimulator(ctrl_qubit)->ApplyCRy(ctrl_qubit, tgt_qubit, theta);
961 NotifyObservers({tgt_qubit, ctrl_qubit});
962 }
963
972 void ApplyCRz(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
973 double theta) override {
974 JoinIfNeeded(ctrl_qubit, tgt_qubit);
975 GetSimulator(ctrl_qubit)->ApplyCRz(ctrl_qubit, tgt_qubit, theta);
976 NotifyObservers({tgt_qubit, ctrl_qubit});
977 }
978
986 void ApplyCH(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
987 JoinIfNeeded(ctrl_qubit, tgt_qubit);
988 GetSimulator(ctrl_qubit)->ApplyCH(ctrl_qubit, tgt_qubit);
989 NotifyObservers({tgt_qubit, ctrl_qubit});
990 }
991
999 void ApplyCSx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
1000 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1001 GetSimulator(ctrl_qubit)->ApplyCSx(ctrl_qubit, tgt_qubit);
1002 NotifyObservers({tgt_qubit, ctrl_qubit});
1003 }
1004
1012 void ApplyCSxDAG(Types::qubit_t ctrl_qubit,
1013 Types::qubit_t tgt_qubit) override {
1014 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1015 GetSimulator(ctrl_qubit)->ApplyCSxDAG(ctrl_qubit, tgt_qubit);
1016 NotifyObservers({tgt_qubit, ctrl_qubit});
1017 }
1018
1026 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1) override {
1027 JoinIfNeeded(qubit0, qubit1);
1028 GetSimulator(qubit0)->ApplySwap(qubit0, qubit1);
1029 NotifyObservers({qubit1, qubit0});
1030 }
1031
1040 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1,
1041 Types::qubit_t qubit2) override {
1042 // TODO: See if it's worth optimizing to joing all three simulators at once,
1043 // if needed (that is, there is a different one for each qubit)
1044 JoinIfNeeded(qubit0, qubit1);
1045 JoinIfNeeded(qubit0, qubit2);
1046 GetSimulator(qubit0)->ApplyCCX(qubit0, qubit1, qubit2);
1047 NotifyObservers({qubit2, qubit1, qubit0});
1048 }
1049
1058 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0,
1059 Types::qubit_t qubit1) override {
1060 // TODO: See if it's worth optimizing to joing all three simulators at once,
1061 // if needed (that is, there is a different one for each qubit)
1062 JoinIfNeeded(ctrl_qubit, qubit0);
1063 JoinIfNeeded(ctrl_qubit, qubit1);
1064 GetSimulator(ctrl_qubit)->ApplyCSwap(ctrl_qubit, qubit0, qubit1);
1065 NotifyObservers({qubit1, qubit0, ctrl_qubit});
1066 }
1067
1079 void ApplyCU(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
1080 double theta, double phi, double lambda, double gamma) override {
1081 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1082 GetSimulator(ctrl_qubit)
1083 ->ApplyCU(ctrl_qubit, tgt_qubit, theta, phi, lambda, gamma);
1084 NotifyObservers({tgt_qubit, ctrl_qubit});
1085 }
1086
1087 void ApplyNop() override { GetSimulator(0)->ApplyNop(); }
1088
1097 void SetMultithreading(bool multithreading = true) override {
1098 enableMultithreading = multithreading;
1099 for (auto &[id, simulator] : simulators)
1100 simulator->SetMultithreading(multithreading);
1101 }
1102
1110 bool GetMultithreading() const override { return enableMultithreading; }
1111
1122 bool IsQcsim() const override {
1123 return type == Simulators::SimulatorType::kQCSim;
1124 }
1125
1140 void SaveState() override { savedState = Clone(); }
1141
1155 void RestoreState() override {
1156 if (savedState) {
1157 const CompositeSimulator *savedStatePtr =
1158 static_cast<CompositeSimulator *>(savedState.get());
1159
1160 type =
1161 savedStatePtr->type;
1162 qubitsMap =
1163 savedStatePtr
1164 ->qubitsMap;
1166
1167 nrQubits =
1168 savedStatePtr->nrQubits;
1169 nextId = savedStatePtr
1170 ->nextId;
1171 enableMultithreading =
1172 savedStatePtr
1173 ->enableMultithreading;
1175
1176 simulators.clear();
1177 for (auto &[id, simulator] : savedStatePtr->simulators) {
1178 auto isim = simulator->Clone();
1179 simulators[id] = std::unique_ptr<IndividualSimulator>(
1180 static_cast<IndividualSimulator *>(isim.release()));
1181 }
1182 }
1183 }
1184
1202 Types::qubit_t res = 0;
1203
1204 if (GetNumberOfQubits() > sizeof(Types::qubit_t) * 8)
1205 std::cerr
1206 << "Warning: The number of qubits to measure is larger than the "
1207 "number of bits in the Types::qubit_t type, the outcome will be "
1208 "undefined"
1209 << std::endl;
1210
1211 for (auto &[id, simulator] : simulators) {
1212 const Types::qubit_t meas = simulator->MeasureNoCollapse();
1213 res |= meas;
1214 }
1215
1216 return res;
1217 }
1218
1233 std::vector<bool> MeasureNoCollapseMany() override {
1234 std::vector<bool> res(nrQubits, false);
1235 for (auto &[id, simulator] : simulators) {
1236 const std::vector<bool> meas = simulator->MeasureNoCollapseMany();
1237 for (size_t i = 0; i < meas.size(); ++i)
1238 if (meas[i]) res[i] = true;
1239 }
1240 return res;
1241 }
1242
1253 std::unique_ptr<ISimulator> Clone() override {
1254 auto clone = std::make_unique<CompositeSimulator>(type);
1255
1256 clone->type = type;
1257 clone->qubitsMap =
1258 qubitsMap;
1260
1261 clone->nrQubits = nrQubits;
1262 clone->nextId = nextId;
1263 clone->enableMultithreading =
1264 enableMultithreading;
1266
1267 for (auto &[id, simulator] : simulators) {
1268 auto isim = simulator->Clone();
1269 clone->simulators[id] = std::unique_ptr<IndividualSimulator>(
1270 static_cast<IndividualSimulator *>(isim.release()));
1271 }
1272
1273 if (savedState) clone->savedState = savedState->Clone();
1274
1275 return clone;
1276 }
1277
1278 private:
1279 void InitializeAlias() {
1280 for (auto &[id, simulator] : simulators) simulator->InitializeAlias();
1281 }
1282
1283 void ClearAlias() {
1284 for (auto &[id, simulator] : simulators) simulator->ClearAlias();
1285 }
1286
1295 inline std::unique_ptr<IndividualSimulator> &GetSimulator(size_t qubit) {
1296 assert(qubitsMap.size() > qubit);
1297 assert(simulators.find(qubitsMap[qubit]) != simulators.end());
1298
1299 // assume it was called with a valid qubit
1300 return simulators[qubitsMap[qubit]];
1301 }
1302
1303 // if executing a gate on two or three qubits, use this to see if it can be
1304 // executed directly if it returns true, join the two simulators together and
1305 // execute the gate (for three qubits, do that once again for the third qubit,
1306 // before execution)
1317 inline bool JoinNeeded(size_t qubit1, size_t qubit2) {
1318 // TODO: Not really needed for all gates that act on multiple qubits, is
1319 // this worth pursuing? the obvious example is the identity gate, which does
1320 // nothing, so a join is not needed
1321 return qubitsMap[qubit1] != qubitsMap[qubit2];
1322 }
1323
1332 inline void JoinIfNeeded(size_t qubit1, size_t qubit2) {
1333 if (JoinNeeded(qubit1, qubit2)) {
1334 const size_t simId = qubitsMap[qubit1];
1335 const size_t eraseSimId = qubitsMap[qubit2];
1336 auto &sim1 = GetSimulator(qubit1);
1337 const auto &sim2 = GetSimulator(qubit2);
1338
1339 sim1->Join(simId, sim2, qubitsMap, enableMultithreading);
1340
1341 simulators.erase(eraseSimId);
1342 }
1343 }
1344
1355 inline void Split(size_t qubit, bool qubitOutcome = false) {
1356 auto &sim = GetSimulator(
1357 qubit); // get the simulator for the qubit, this one will be split
1358 if (sim->GetNumberOfQubits() ==
1359 1) // no need to split it, it's already for a single qubit
1360 return;
1361
1362 qubitsMap[qubit] = nextId; // the qubit will be in the new simulator
1363 simulators[nextId] = sim->Split(qubit, qubitOutcome, enableMultithreading);
1364
1365 ++nextId;
1366 }
1367
1368 SimulatorType type;
1369 std::vector<size_t>
1370 qubitsMap;
1372 std::unordered_map<size_t, std::unique_ptr<IndividualSimulator>>
1373 simulators;
1374 size_t nrQubits = 0;
1375 size_t nextId = 0;
1376 bool enableMultithreading =
1377 true;
1378
1379 std::unique_ptr<ISimulator> savedState;
1380};
1381
1382} // namespace Private
1383} // namespace Simulators
1384
1385#endif
1386#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:72
@ kQiskitAer
qiskit aer simulator type
Definition State.h:70
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