Maestro 0.1.0
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 {
43public:
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)
208 return;
209
210 for (auto &[id, simulator] : simulators)
211 simulator->Configure(key, value);
212 }
213
221 std::string GetConfiguration(const char *key) const override {
222 if (simulators.empty())
223 return "";
224
225 return simulators.begin()->second->GetConfiguration(key);
226 }
227
236 size_t AllocateQubits(size_t num_qubits) override {
237 if (!simulators.empty())
238 return 0;
239
240 const size_t oldNrQubits = nrQubits;
241 nrQubits += num_qubits;
242 return oldNrQubits;
243 }
244
251 size_t GetNumberOfQubits() const override { return nrQubits; }
252
260 void Clear() override {
261 simulators.clear();
262 qubitsMap.clear();
263 nrQubits = 0;
264 }
265
271 void SaveStateToInternalDestructive() override {
272 for (auto &[id, simulator] : simulators)
273 simulator->SaveStateToInternalDestructive();
274 }
275
283 for (auto &[id, simulator] : simulators)
284 simulator->RestoreInternalDestructiveSavedState();
285 }
286
295 std::complex<double> AmplitudeRaw(Types::qubit_t outcome) override {
296 std::complex<double> res = 1.0;
297
298 for (auto &[id, simulator] : simulators)
299 res *=
300 simulator->AmplitudeRaw(simulator->ConvertOutcomeFromGlobal(outcome));
301
302 return res;
303 }
304
312 size_t Measure(const Types::qubits_vector &qubits) override {
313 size_t res = 0;
314 size_t mask = 1ULL;
315
316 DontNotify();
317 for (Types::qubit_t qubit : qubits) {
318 const bool outcome = GetSimulator(qubit)->Measure({qubit}) != 0;
319 if (outcome)
320 res |= mask;
321 mask <<= 1;
322
323 Split(qubit, outcome);
324 }
325 Notify();
326
327 NotifyObservers(qubits);
328
329 return res;
330 }
331
338 void ApplyReset(const Types::qubits_vector &qubits) override {
339 DontNotify();
340 for (Types::qubit_t qubit : qubits) {
341 GetSimulator(qubit)->ApplyReset({qubit});
342 Split(qubit, false);
343 }
344 Notify();
345
346 NotifyObservers(qubits);
347 }
348
358 double Probability(Types::qubit_t outcome) override {
359 return std::norm(Amplitude(outcome));
360 }
361
370 std::complex<double> Amplitude(Types::qubit_t outcome) override {
371 std::complex<double> res = 1.0;
372
373 for (auto &[id, simulator] : simulators)
374 res *= simulator->Amplitude(outcome);
375
376 return res;
377 }
378
386 std::vector<double> AllProbabilities() override {
387 const size_t nrBasisStates = 1ULL << nrQubits;
388 std::vector<double> result;
389
390 for (size_t i = 0; i < nrBasisStates; ++i)
391 result.emplace_back(Probability(i));
392
393 return result;
394 }
395
405 std::vector<double>
406 Probabilities(const Types::qubits_vector &qubits) override {
407 std::vector<double> result;
408
409 for (size_t i = 0; i < qubits.size(); ++i)
410 result.emplace_back(Probability(qubits[i]));
411
412 return result;
413 }
414
428 std::unordered_map<Types::qubit_t, Types::qubit_t>
430 size_t shots = 1000) override {
431 // TODO: improve it as for the qcsim statevector simulator case!
432 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
433 DontNotify();
434
436
437 if (shots > 1) {
438 InitializeAlias();
439
440 for (size_t shot = 0; shot < shots; ++shot) {
441 size_t measRaw = 0;
442 for (auto &[id, simulator] : simulators)
443 measRaw |= simulator->SampleFromAlias();
444
445 size_t meas = 0;
446 size_t mask = 1ULL;
447 for (auto q : qubits) {
448 const size_t qubitMask = 1ULL << q;
449 if ((measRaw & qubitMask) != 0)
450 meas |= mask;
451 mask <<= 1ULL;
452 }
453
454 ++result[meas];
455 }
456
457 ClearAlias();
458 } else
459 for (size_t shot = 0; shot < shots; ++shot) {
460 const auto measRaw = MeasureNoCollapse();
461
462 size_t meas = 0;
463 size_t mask = 1ULL;
464 for (auto q : qubits) {
465 const size_t qubitMask = 1ULL << q;
466 if ((measRaw & qubitMask) != 0)
467 meas |= mask;
468 mask <<= 1ULL;
469 }
470
471 ++result[meas];
472 }
473
475
476 Notify();
477 NotifyObservers(qubits);
478
479 return result;
480 }
481
493 double ExpectationValue(const std::string &pauliString) override {
494 std::unordered_map<size_t, std::string> pauliStrings;
495
496 for (size_t q = 0; q < pauliString.size(); ++q) {
497 const char op = toupper(pauliString[q]);
498 if (op == 'I')
499 continue;
500
501 const size_t simId = qubitsMap[q];
502 const size_t localQubit = simulators[simId]->GetQubitsMap().at(q);
503
504 if (pauliStrings[simId].size() <= localQubit)
505 pauliStrings[simId].resize(localQubit + 1, 'I');
506
507 pauliStrings[simId][localQubit] = op;
508 }
509
510 double result = 1.0;
511 for (auto &[id, localPauliString] : pauliStrings)
512 result *= simulators[id]->ExpectationValue(localPauliString);
513
514 return result;
515 }
516
524 SimulatorType GetType() const override {
525#ifdef NO_QISKIT_AER
526 return SimulatorType::kCompositeQCSim;
527#else
528 if (type != SimulatorType::kQiskitAer)
529 return SimulatorType::kCompositeQCSim;
530
531 return SimulatorType::kCompositeQiskitAer;
532#endif
533 }
534
543 SimulationType GetSimulationType() const override {
544 return SimulationType::kStatevector;
545 }
546
554 void Flush() override {
555 for (auto &[id, simulator] : simulators)
556 simulator->Flush();
557 }
558
559 // YES, all one qubit gates are that easy:
560
568 void ApplyP(Types::qubit_t qubit, double lambda) override {
569 GetSimulator(qubit)->ApplyP(qubit, lambda);
570 NotifyObservers({qubit});
571 }
572
579 void ApplyX(Types::qubit_t qubit) override {
580 GetSimulator(qubit)->ApplyX(qubit);
581 NotifyObservers({qubit});
582 }
583
590 void ApplyY(Types::qubit_t qubit) override {
591 GetSimulator(qubit)->ApplyY(qubit);
592 NotifyObservers({qubit});
593 }
594
601 void ApplyZ(Types::qubit_t qubit) override {
602 GetSimulator(qubit)->ApplyZ(qubit);
603 NotifyObservers({qubit});
604 }
605
612 void ApplyH(Types::qubit_t qubit) override {
613 GetSimulator(qubit)->ApplyH(qubit);
614 NotifyObservers({qubit});
615 }
616
623 void ApplyS(Types::qubit_t qubit) override {
624 GetSimulator(qubit)->ApplyS(qubit);
625 NotifyObservers({qubit});
626 }
627
634 void ApplySDG(Types::qubit_t qubit) override {
635 GetSimulator(qubit)->ApplySDG(qubit);
636 NotifyObservers({qubit});
637 }
638
645 void ApplyT(Types::qubit_t qubit) override {
646 GetSimulator(qubit)->ApplyT(qubit);
647 NotifyObservers({qubit});
648 }
649
656 void ApplyTDG(Types::qubit_t qubit) override {
657 GetSimulator(qubit)->ApplyTDG(qubit);
658 NotifyObservers({qubit});
659 }
660
667 void ApplySx(Types::qubit_t qubit) override {
668 GetSimulator(qubit)->ApplySx(qubit);
669 NotifyObservers({qubit});
670 }
671
678 void ApplySxDAG(Types::qubit_t qubit) override {
679 GetSimulator(qubit)->ApplySxDAG(qubit);
680 NotifyObservers({qubit});
681 }
682
689 void ApplyK(Types::qubit_t qubit) override {
690 GetSimulator(qubit)->ApplyK(qubit);
691 NotifyObservers({qubit});
692 }
693
701 void ApplyRx(Types::qubit_t qubit, double theta) override {
702 GetSimulator(qubit)->ApplyRx(qubit, theta);
703 NotifyObservers({qubit});
704 }
705
713 void ApplyRy(Types::qubit_t qubit, double theta) override {
714 GetSimulator(qubit)->ApplyRy(qubit, theta);
715 NotifyObservers({qubit});
716 }
717
725 void ApplyRz(Types::qubit_t qubit, double theta) override {
726 GetSimulator(qubit)->ApplyRz(qubit, theta);
727 NotifyObservers({qubit});
728 }
729
740 void ApplyU(Types::qubit_t qubit, double theta, double phi, double lambda,
741 double gamma) override {
742 GetSimulator(qubit)->ApplyU(qubit, theta, phi, lambda, gamma);
743 NotifyObservers({qubit});
744 }
745
746 // the gates that operate on more than one qubit need joining of the
747 // simulators, if the qubits are in different simulators
748
756 void ApplyCX(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
757 JoinIfNeeded(ctrl_qubit, tgt_qubit);
758 GetSimulator(ctrl_qubit)->ApplyCX(ctrl_qubit, tgt_qubit);
759 NotifyObservers({tgt_qubit, ctrl_qubit});
760 }
761
769 void ApplyCY(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
770 JoinIfNeeded(ctrl_qubit, tgt_qubit);
771 GetSimulator(ctrl_qubit)->ApplyCY(ctrl_qubit, tgt_qubit);
772 NotifyObservers({tgt_qubit, ctrl_qubit});
773 }
774
782 void ApplyCZ(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
783 JoinIfNeeded(ctrl_qubit, tgt_qubit);
784 GetSimulator(ctrl_qubit)->ApplyCZ(ctrl_qubit, tgt_qubit);
785 NotifyObservers({tgt_qubit, ctrl_qubit});
786 }
787
796 void ApplyCP(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
797 double lambda) override {
798 JoinIfNeeded(ctrl_qubit, tgt_qubit);
799 GetSimulator(ctrl_qubit)->ApplyCP(ctrl_qubit, tgt_qubit, lambda);
800 NotifyObservers({tgt_qubit, ctrl_qubit});
801 }
802
811 void ApplyCRx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
812 double theta) override {
813 JoinIfNeeded(ctrl_qubit, tgt_qubit);
814 GetSimulator(ctrl_qubit)->ApplyCRx(ctrl_qubit, tgt_qubit, theta);
815 NotifyObservers({tgt_qubit, ctrl_qubit});
816 }
817
826 void ApplyCRy(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
827 double theta) override {
828 JoinIfNeeded(ctrl_qubit, tgt_qubit);
829 GetSimulator(ctrl_qubit)->ApplyCRy(ctrl_qubit, tgt_qubit, theta);
830 NotifyObservers({tgt_qubit, ctrl_qubit});
831 }
832
841 void ApplyCRz(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
842 double theta) override {
843 JoinIfNeeded(ctrl_qubit, tgt_qubit);
844 GetSimulator(ctrl_qubit)->ApplyCRz(ctrl_qubit, tgt_qubit, theta);
845 NotifyObservers({tgt_qubit, ctrl_qubit});
846 }
847
855 void ApplyCH(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
856 JoinIfNeeded(ctrl_qubit, tgt_qubit);
857 GetSimulator(ctrl_qubit)->ApplyCH(ctrl_qubit, tgt_qubit);
858 NotifyObservers({tgt_qubit, ctrl_qubit});
859 }
860
868 void ApplyCSx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
869 JoinIfNeeded(ctrl_qubit, tgt_qubit);
870 GetSimulator(ctrl_qubit)->ApplyCSx(ctrl_qubit, tgt_qubit);
871 NotifyObservers({tgt_qubit, ctrl_qubit});
872 }
873
881 void ApplyCSxDAG(Types::qubit_t ctrl_qubit,
882 Types::qubit_t tgt_qubit) override {
883 JoinIfNeeded(ctrl_qubit, tgt_qubit);
884 GetSimulator(ctrl_qubit)->ApplyCSxDAG(ctrl_qubit, tgt_qubit);
885 NotifyObservers({tgt_qubit, ctrl_qubit});
886 }
887
895 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1) override {
896 JoinIfNeeded(qubit0, qubit1);
897 GetSimulator(qubit0)->ApplySwap(qubit0, qubit1);
898 NotifyObservers({qubit1, qubit0});
899 }
900
909 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1,
910 Types::qubit_t qubit2) override {
911 // TODO: See if it's worth optimizing to joing all three simulators at once,
912 // if needed (that is, there is a different one for each qubit)
913 JoinIfNeeded(qubit0, qubit1);
914 JoinIfNeeded(qubit0, qubit2);
915 GetSimulator(qubit0)->ApplyCCX(qubit0, qubit1, qubit2);
916 NotifyObservers({qubit2, qubit1, qubit0});
917 }
918
927 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0,
928 Types::qubit_t qubit1) override {
929 // TODO: See if it's worth optimizing to joing all three simulators at once,
930 // if needed (that is, there is a different one for each qubit)
931 JoinIfNeeded(ctrl_qubit, qubit0);
932 JoinIfNeeded(ctrl_qubit, qubit1);
933 GetSimulator(ctrl_qubit)->ApplyCSwap(ctrl_qubit, qubit0, qubit1);
934 NotifyObservers({qubit1, qubit0, ctrl_qubit});
935 }
936
948 void ApplyCU(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
949 double theta, double phi, double lambda, double gamma) override {
950 JoinIfNeeded(ctrl_qubit, tgt_qubit);
951 GetSimulator(ctrl_qubit)
952 ->ApplyCU(ctrl_qubit, tgt_qubit, theta, phi, lambda, gamma);
953 NotifyObservers({tgt_qubit, ctrl_qubit});
954 }
955
956 void ApplyNop() { GetSimulator(0)->ApplyNop(); }
957
966 void SetMultithreading(bool multithreading = true) override {
967 enableMultithreading = multithreading;
968 for (auto &[id, simulator] : simulators)
969 simulator->SetMultithreading(multithreading);
970 }
971
979 bool GetMultithreading() const override { return enableMultithreading; }
980
991 bool IsQcsim() const override {
993 }
994
1009 void SaveState() override { savedState = Clone(); }
1010
1024 void RestoreState() override {
1025 if (savedState) {
1026 const CompositeSimulator *savedStatePtr =
1027 static_cast<CompositeSimulator *>(savedState.get());
1028
1029 type =
1030 savedStatePtr->type;
1031 qubitsMap =
1032 savedStatePtr
1033 ->qubitsMap;
1035
1036 nrQubits =
1037 savedStatePtr->nrQubits;
1038 nextId = savedStatePtr
1039 ->nextId;
1040 enableMultithreading =
1041 savedStatePtr
1042 ->enableMultithreading;
1044
1045 simulators.clear();
1046 for (auto &[id, simulator] : savedStatePtr->simulators) {
1047 auto isim = simulator->Clone();
1048 simulators[id] = std::unique_ptr<IndividualSimulator>(
1049 static_cast<IndividualSimulator *>(isim.release()));
1050 }
1051 }
1052 }
1053
1068 Types::qubit_t res = 0;
1069
1070 for (auto &[id, simulator] : simulators) {
1071 const Types::qubit_t meas = simulator->MeasureNoCollapse();
1072 res |= meas;
1073 }
1074
1075 return res;
1076 }
1077
1088 std::unique_ptr<ISimulator> Clone() override {
1089 auto clone = std::make_unique<CompositeSimulator>(type);
1090
1091 clone->type = type;
1092 clone->qubitsMap =
1093 qubitsMap;
1095
1096 clone->nrQubits = nrQubits;
1097 clone->nextId = nextId;
1098 clone->enableMultithreading =
1099 enableMultithreading;
1101
1102 for (auto &[id, simulator] : simulators) {
1103 auto isim = simulator->Clone();
1104 clone->simulators[id] = std::unique_ptr<IndividualSimulator>(
1105 static_cast<IndividualSimulator *>(isim.release()));
1106 }
1107
1108 if (savedState)
1109 clone->savedState = savedState->Clone();
1110
1111 return clone;
1112 }
1113
1114private:
1115 void InitializeAlias() {
1116 for (auto &[id, simulator] : simulators)
1117 simulator->InitializeAlias();
1118 }
1119
1120 void ClearAlias() {
1121 for (auto &[id, simulator] : simulators)
1122 simulator->ClearAlias();
1123 }
1124
1133 inline std::unique_ptr<IndividualSimulator> &GetSimulator(size_t qubit) {
1134 assert(qubitsMap.size() > qubit);
1135 assert(simulators.find(qubitsMap[qubit]) != simulators.end());
1136
1137 // assume it was called with a valid qubit
1138 return simulators[qubitsMap[qubit]];
1139 }
1140
1141 // if executing a gate on two or three qubits, use this to see if it can be
1142 // executed directly if it returns true, join the two simulators together and
1143 // execute the gate (for three qubits, do that once again for the third qubit,
1144 // before execution)
1155 inline bool JoinNeeded(size_t qubit1, size_t qubit2) {
1156 // TODO: Not really needed for all gates that act on multiple qubits, is
1157 // this worth pursuing? the obvious example is the identity gate, which does
1158 // nothing, so a join is not needed
1159 return qubitsMap[qubit1] != qubitsMap[qubit2];
1160 }
1161
1170 inline void JoinIfNeeded(size_t qubit1, size_t qubit2) {
1171 if (JoinNeeded(qubit1, qubit2)) {
1172 const size_t simId = qubitsMap[qubit1];
1173 const size_t eraseSimId = qubitsMap[qubit2];
1174 auto &sim1 = GetSimulator(qubit1);
1175 const auto &sim2 = GetSimulator(qubit2);
1176
1177 sim1->Join(simId, sim2, qubitsMap, enableMultithreading);
1178
1179 simulators.erase(eraseSimId);
1180 }
1181 }
1182
1193 inline void Split(size_t qubit, bool qubitOutcome = false) {
1194 auto &sim = GetSimulator(
1195 qubit); // get the simulator for the qubit, this one will be split
1196 if (sim->GetNumberOfQubits() ==
1197 1) // no need to split it, it's already for a single qubit
1198 return;
1199
1200 qubitsMap[qubit] = nextId; // the qubit will be in the new simulator
1201 simulators[nextId] = sim->Split(qubit, qubitOutcome, enableMultithreading);
1202
1203 ++nextId;
1204 }
1205
1206 SimulatorType type;
1207 std::vector<size_t>
1208 qubitsMap;
1210 std::unordered_map<size_t, std::unique_ptr<IndividualSimulator>>
1211 simulators;
1212 size_t nrQubits = 0;
1213 size_t nextId = 0;
1214 bool enableMultithreading =
1215 true;
1216
1217 std::unique_ptr<ISimulator> savedState;
1218};
1219
1220} // namespace Private
1221} // namespace Simulators
1222
1223#endif
1224#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:67
@ kQiskitAer
qiskit aer simulator type
Definition State.h:65
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
Definition Types.h:21
uint_fast64_t qubit_t
The type of a qubit.
Definition Types.h:20