Maestro 0.1.0
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
Composite.h
Go to the documentation of this file.
1
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
308 size_t Measure(const Types::qubits_vector &qubits) override {
309 size_t res = 0;
310 size_t mask = 1ULL;
311
312 DontNotify();
313 for (Types::qubit_t qubit : qubits) {
314 const bool outcome = GetSimulator(qubit)->Measure({qubit}) != 0;
315 if (outcome) res |= mask;
316 mask <<= 1;
317
318 Split(qubit, outcome);
319 }
320 Notify();
321
322 NotifyObservers(qubits);
323
324 return res;
325 }
326
333 void ApplyReset(const Types::qubits_vector &qubits) override {
334 DontNotify();
335 for (Types::qubit_t qubit : qubits) {
336 GetSimulator(qubit)->ApplyReset({qubit});
337 Split(qubit, false);
338 }
339 Notify();
340
341 NotifyObservers(qubits);
342 }
343
353 double Probability(Types::qubit_t outcome) override {
354 return std::norm(Amplitude(outcome));
355 }
356
365 std::complex<double> Amplitude(Types::qubit_t outcome) override {
366 std::complex<double> res = 1.0;
367
368 for (auto &[id, simulator] : simulators)
369 res *= simulator->Amplitude(outcome);
370
371 return res;
372 }
373
381 std::vector<double> AllProbabilities() override {
382 const size_t nrBasisStates = 1ULL << nrQubits;
383 std::vector<double> result;
384
385 for (size_t i = 0; i < nrBasisStates; ++i)
386 result.emplace_back(Probability(i));
387
388 return result;
389 }
390
400 std::vector<double> Probabilities(
401 const Types::qubits_vector &qubits) override {
402 std::vector<double> result;
403
404 for (size_t i = 0; i < qubits.size(); ++i)
405 result.emplace_back(Probability(qubits[i]));
406
407 return result;
408 }
409
423 std::unordered_map<Types::qubit_t, Types::qubit_t> SampleCounts(
424 const Types::qubits_vector &qubits, size_t shots = 1000) override {
425 // TODO: improve it as for the qcsim statevector simulator case!
426 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
427 DontNotify();
428
430
431 if (shots > 1) {
432 InitializeAlias();
433
434 for (size_t shot = 0; shot < shots; ++shot) {
435 size_t measRaw = 0;
436 for (auto &[id, simulator] : simulators)
437 measRaw |= simulator->SampleFromAlias();
438
439 size_t meas = 0;
440 size_t mask = 1ULL;
441 for (auto q : qubits) {
442 const size_t qubitMask = 1ULL << q;
443 if ((measRaw & qubitMask) != 0) meas |= mask;
444 mask <<= 1ULL;
445 }
446
447 ++result[meas];
448 }
449
450 ClearAlias();
451 } else
452 for (size_t shot = 0; shot < shots; ++shot) {
453 const auto measRaw = MeasureNoCollapse();
454
455 size_t meas = 0;
456 size_t mask = 1ULL;
457 for (auto q : qubits) {
458 const size_t qubitMask = 1ULL << q;
459 if ((measRaw & qubitMask) != 0) meas |= mask;
460 mask <<= 1ULL;
461 }
462
463 ++result[meas];
464 }
465
467
468 Notify();
469 NotifyObservers(qubits);
470
471 return result;
472 }
473
485 double ExpectationValue(const std::string &pauliString) override {
486 std::unordered_map<size_t, std::string> pauliStrings;
487
488 for (size_t q = 0; q < pauliString.size(); ++q) {
489 const char op = toupper(pauliString[q]);
490 if (op == 'I') continue;
491
492 const size_t simId = qubitsMap[q];
493 const size_t localQubit = simulators[simId]->GetQubitsMap().at(q);
494
495 if (pauliStrings[simId].size() <= localQubit)
496 pauliStrings[simId].resize(localQubit + 1, 'I');
497
498 pauliStrings[simId][localQubit] = op;
499 }
500
501 double result = 1.0;
502 for (auto &[id, localPauliString] : pauliStrings)
503 result *= simulators[id]->ExpectationValue(localPauliString);
504
505 return result;
506 }
507
515 SimulatorType GetType() const override {
516#ifdef NO_QISKIT_AER
517 return SimulatorType::kCompositeQCSim;
518#else
519 if (type != SimulatorType::kQiskitAer)
520 return SimulatorType::kCompositeQCSim;
521
522 return SimulatorType::kCompositeQiskitAer;
523#endif
524 }
525
534 SimulationType GetSimulationType() const override {
535 return SimulationType::kStatevector;
536 }
537
545 void Flush() override {
546 for (auto &[id, simulator] : simulators) simulator->Flush();
547 }
548
549 // YES, all one qubit gates are that easy:
550
558 void ApplyP(Types::qubit_t qubit, double lambda) override {
559 GetSimulator(qubit)->ApplyP(qubit, lambda);
560 NotifyObservers({qubit});
561 }
562
569 void ApplyX(Types::qubit_t qubit) override {
570 GetSimulator(qubit)->ApplyX(qubit);
571 NotifyObservers({qubit});
572 }
573
580 void ApplyY(Types::qubit_t qubit) override {
581 GetSimulator(qubit)->ApplyY(qubit);
582 NotifyObservers({qubit});
583 }
584
591 void ApplyZ(Types::qubit_t qubit) override {
592 GetSimulator(qubit)->ApplyZ(qubit);
593 NotifyObservers({qubit});
594 }
595
602 void ApplyH(Types::qubit_t qubit) override {
603 GetSimulator(qubit)->ApplyH(qubit);
604 NotifyObservers({qubit});
605 }
606
613 void ApplyS(Types::qubit_t qubit) override {
614 GetSimulator(qubit)->ApplyS(qubit);
615 NotifyObservers({qubit});
616 }
617
624 void ApplySDG(Types::qubit_t qubit) override {
625 GetSimulator(qubit)->ApplySDG(qubit);
626 NotifyObservers({qubit});
627 }
628
635 void ApplyT(Types::qubit_t qubit) override {
636 GetSimulator(qubit)->ApplyT(qubit);
637 NotifyObservers({qubit});
638 }
639
646 void ApplyTDG(Types::qubit_t qubit) override {
647 GetSimulator(qubit)->ApplyTDG(qubit);
648 NotifyObservers({qubit});
649 }
650
657 void ApplySx(Types::qubit_t qubit) override {
658 GetSimulator(qubit)->ApplySx(qubit);
659 NotifyObservers({qubit});
660 }
661
668 void ApplySxDAG(Types::qubit_t qubit) override {
669 GetSimulator(qubit)->ApplySxDAG(qubit);
670 NotifyObservers({qubit});
671 }
672
679 void ApplyK(Types::qubit_t qubit) override {
680 GetSimulator(qubit)->ApplyK(qubit);
681 NotifyObservers({qubit});
682 }
683
691 void ApplyRx(Types::qubit_t qubit, double theta) override {
692 GetSimulator(qubit)->ApplyRx(qubit, theta);
693 NotifyObservers({qubit});
694 }
695
703 void ApplyRy(Types::qubit_t qubit, double theta) override {
704 GetSimulator(qubit)->ApplyRy(qubit, theta);
705 NotifyObservers({qubit});
706 }
707
715 void ApplyRz(Types::qubit_t qubit, double theta) override {
716 GetSimulator(qubit)->ApplyRz(qubit, theta);
717 NotifyObservers({qubit});
718 }
719
730 void ApplyU(Types::qubit_t qubit, double theta, double phi, double lambda,
731 double gamma) override {
732 GetSimulator(qubit)->ApplyU(qubit, theta, phi, lambda, gamma);
733 NotifyObservers({qubit});
734 }
735
736 // the gates that operate on more than one qubit need joining of the
737 // simulators, if the qubits are in different simulators
738
746 void ApplyCX(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
747 JoinIfNeeded(ctrl_qubit, tgt_qubit);
748 GetSimulator(ctrl_qubit)->ApplyCX(ctrl_qubit, tgt_qubit);
749 NotifyObservers({tgt_qubit, ctrl_qubit});
750 }
751
759 void ApplyCY(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
760 JoinIfNeeded(ctrl_qubit, tgt_qubit);
761 GetSimulator(ctrl_qubit)->ApplyCY(ctrl_qubit, tgt_qubit);
762 NotifyObservers({tgt_qubit, ctrl_qubit});
763 }
764
772 void ApplyCZ(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
773 JoinIfNeeded(ctrl_qubit, tgt_qubit);
774 GetSimulator(ctrl_qubit)->ApplyCZ(ctrl_qubit, tgt_qubit);
775 NotifyObservers({tgt_qubit, ctrl_qubit});
776 }
777
786 void ApplyCP(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
787 double lambda) override {
788 JoinIfNeeded(ctrl_qubit, tgt_qubit);
789 GetSimulator(ctrl_qubit)->ApplyCP(ctrl_qubit, tgt_qubit, lambda);
790 NotifyObservers({tgt_qubit, ctrl_qubit});
791 }
792
801 void ApplyCRx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
802 double theta) override {
803 JoinIfNeeded(ctrl_qubit, tgt_qubit);
804 GetSimulator(ctrl_qubit)->ApplyCRx(ctrl_qubit, tgt_qubit, theta);
805 NotifyObservers({tgt_qubit, ctrl_qubit});
806 }
807
816 void ApplyCRy(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
817 double theta) override {
818 JoinIfNeeded(ctrl_qubit, tgt_qubit);
819 GetSimulator(ctrl_qubit)->ApplyCRy(ctrl_qubit, tgt_qubit, theta);
820 NotifyObservers({tgt_qubit, ctrl_qubit});
821 }
822
831 void ApplyCRz(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
832 double theta) override {
833 JoinIfNeeded(ctrl_qubit, tgt_qubit);
834 GetSimulator(ctrl_qubit)->ApplyCRz(ctrl_qubit, tgt_qubit, theta);
835 NotifyObservers({tgt_qubit, ctrl_qubit});
836 }
837
845 void ApplyCH(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
846 JoinIfNeeded(ctrl_qubit, tgt_qubit);
847 GetSimulator(ctrl_qubit)->ApplyCH(ctrl_qubit, tgt_qubit);
848 NotifyObservers({tgt_qubit, ctrl_qubit});
849 }
850
858 void ApplyCSx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit) override {
859 JoinIfNeeded(ctrl_qubit, tgt_qubit);
860 GetSimulator(ctrl_qubit)->ApplyCSx(ctrl_qubit, tgt_qubit);
861 NotifyObservers({tgt_qubit, ctrl_qubit});
862 }
863
871 void ApplyCSxDAG(Types::qubit_t ctrl_qubit,
872 Types::qubit_t tgt_qubit) override {
873 JoinIfNeeded(ctrl_qubit, tgt_qubit);
874 GetSimulator(ctrl_qubit)->ApplyCSxDAG(ctrl_qubit, tgt_qubit);
875 NotifyObservers({tgt_qubit, ctrl_qubit});
876 }
877
885 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1) override {
886 JoinIfNeeded(qubit0, qubit1);
887 GetSimulator(qubit0)->ApplySwap(qubit0, qubit1);
888 NotifyObservers({qubit1, qubit0});
889 }
890
899 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1,
900 Types::qubit_t qubit2) override {
901 // TODO: See if it's worth optimizing to joing all three simulators at once,
902 // if needed (that is, there is a different one for each qubit)
903 JoinIfNeeded(qubit0, qubit1);
904 JoinIfNeeded(qubit0, qubit2);
905 GetSimulator(qubit0)->ApplyCCX(qubit0, qubit1, qubit2);
906 NotifyObservers({qubit2, qubit1, qubit0});
907 }
908
917 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0,
918 Types::qubit_t qubit1) override {
919 // TODO: See if it's worth optimizing to joing all three simulators at once,
920 // if needed (that is, there is a different one for each qubit)
921 JoinIfNeeded(ctrl_qubit, qubit0);
922 JoinIfNeeded(ctrl_qubit, qubit1);
923 GetSimulator(ctrl_qubit)->ApplyCSwap(ctrl_qubit, qubit0, qubit1);
924 NotifyObservers({qubit1, qubit0, ctrl_qubit});
925 }
926
938 void ApplyCU(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
939 double theta, double phi, double lambda, double gamma) override {
940 JoinIfNeeded(ctrl_qubit, tgt_qubit);
941 GetSimulator(ctrl_qubit)
942 ->ApplyCU(ctrl_qubit, tgt_qubit, theta, phi, lambda, gamma);
943 NotifyObservers({tgt_qubit, ctrl_qubit});
944 }
945
946 void ApplyNop() { GetSimulator(0)->ApplyNop(); }
947
956 void SetMultithreading(bool multithreading = true) override {
957 enableMultithreading = multithreading;
958 for (auto &[id, simulator] : simulators)
959 simulator->SetMultithreading(multithreading);
960 }
961
969 bool GetMultithreading() const override { return enableMultithreading; }
970
981 bool IsQcsim() const override {
983 }
984
999 void SaveState() override { savedState = Clone(); }
1000
1014 void RestoreState() override {
1015 if (savedState) {
1016 const CompositeSimulator *savedStatePtr =
1017 static_cast<CompositeSimulator *>(savedState.get());
1018
1019 type =
1020 savedStatePtr->type;
1021 qubitsMap =
1022 savedStatePtr
1023 ->qubitsMap;
1026 nrQubits =
1027 savedStatePtr->nrQubits;
1028 nextId = savedStatePtr
1029 ->nextId;
1030 enableMultithreading =
1031 savedStatePtr
1032 ->enableMultithreading;
1035 simulators.clear();
1036 for (auto &[id, simulator] : savedStatePtr->simulators) {
1037 auto isim = simulator->Clone();
1038 simulators[id] = std::unique_ptr<IndividualSimulator>(
1039 static_cast<IndividualSimulator *>(isim.release()));
1040 }
1041 }
1042 }
1043
1057 Types::qubit_t MeasureNoCollapse() override {
1058 Types::qubit_t res = 0;
1059
1060 for (auto &[id, simulator] : simulators) {
1061 const Types::qubit_t meas = simulator->MeasureNoCollapse();
1062 res |= meas;
1063 }
1064
1065 return res;
1066 }
1067
1078 std::unique_ptr<ISimulator> Clone() override {
1079 auto clone = std::make_unique<CompositeSimulator>(type);
1080
1081 clone->type = type;
1082 clone->qubitsMap =
1083 qubitsMap;
1086 clone->nrQubits = nrQubits;
1087 clone->nextId = nextId;
1088 clone->enableMultithreading =
1089 enableMultithreading;
1092 for (auto &[id, simulator] : simulators) {
1093 auto isim = simulator->Clone();
1094 clone->simulators[id] = std::unique_ptr<IndividualSimulator>(
1095 static_cast<IndividualSimulator *>(isim.release()));
1096 }
1097
1098 if (savedState) clone->savedState = savedState->Clone();
1099
1100 return clone;
1101 }
1102
1103 private:
1104 void InitializeAlias() {
1105 for (auto &[id, simulator] : simulators) simulator->InitializeAlias();
1106 }
1107
1108 void ClearAlias() {
1109 for (auto &[id, simulator] : simulators) simulator->ClearAlias();
1110 }
1111
1120 inline std::unique_ptr<IndividualSimulator> &GetSimulator(size_t qubit) {
1121 assert(qubitsMap.size() > qubit);
1122 assert(simulators.find(qubitsMap[qubit]) != simulators.end());
1123
1124 // assume it was called with a valid qubit
1125 return simulators[qubitsMap[qubit]];
1126 }
1127
1128 // if executing a gate on two or three qubits, use this to see if it can be
1129 // executed directly if it returns true, join the two simulators together and
1130 // execute the gate (for three qubits, do that once again for the third qubit,
1131 // before execution)
1142 inline bool JoinNeeded(size_t qubit1, size_t qubit2) {
1143 // TODO: Not really needed for all gates that act on multiple qubits, is
1144 // this worth pursuing? the obvious example is the identity gate, which does
1145 // nothing, so a join is not needed
1146 return qubitsMap[qubit1] != qubitsMap[qubit2];
1147 }
1148
1157 inline void JoinIfNeeded(size_t qubit1, size_t qubit2) {
1158 if (JoinNeeded(qubit1, qubit2)) {
1159 const size_t simId = qubitsMap[qubit1];
1160 const size_t eraseSimId = qubitsMap[qubit2];
1161 auto &sim1 = GetSimulator(qubit1);
1162 const auto &sim2 = GetSimulator(qubit2);
1163
1164 sim1->Join(simId, sim2, qubitsMap, enableMultithreading);
1165
1166 simulators.erase(eraseSimId);
1167 }
1168 }
1169
1180 inline void Split(size_t qubit, bool qubitOutcome = false) {
1181 auto &sim = GetSimulator(
1182 qubit); // get the simulator for the qubit, this one will be split
1183 if (sim->GetNumberOfQubits() ==
1184 1) // no need to split it, it's already for a single qubit
1185 return;
1186
1187 qubitsMap[qubit] = nextId; // the qubit will be in the new simulator
1188 simulators[nextId] = sim->Split(qubit, qubitOutcome, enableMultithreading);
1189
1190 ++nextId;
1191 }
1192
1193 SimulatorType type;
1194 std::vector<size_t>
1195 qubitsMap;
1197 std::unordered_map<size_t, std::unique_ptr<IndividualSimulator>>
1198 simulators;
1199 size_t nrQubits = 0;
1200 size_t nextId = 0;
1201 bool enableMultithreading =
1202 true;
1204 std::unique_ptr<ISimulator> savedState;
1205};
1206
1207} // namespace Private
1208} // namespace Simulators
1209
1210#endif
1211#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
@ kQiskitAer
qiskit aer simulator type