20#ifdef INCLUDED_BY_FACTORY
42class CompositeSimulator :
public ISimulator {
51 CompositeSimulator(SimulatorType type =
69 type != SimulatorType::kQiskitAer &&
71 type != SimulatorType::kQCSim)
88 void Initialize()
override {
89 qubitsMap.resize(nrQubits);
92 for (
size_t q = 0; q < nrQubits; ++q) {
94 auto sim = std::make_unique<IndividualSimulator>(type);
95 sim->AllocateQubits(1);
99 sim->Configure(
"method",
"statevector");
102 sim->SetMultithreading(enableMultithreading);
104 sim->GetQubitsMap()[q] = 0;
105 simulators[q] = std::move(sim);
116 void Reset()
override { Initialize(); }
130 void InitializeState(
size_t num_qubits,
131 std::vector<std::complex<double>> &litudes)
override {
132 throw std::runtime_error(
133 "CompositeSimulator::InitializeState not supported");
170 void InitializeState(
size_t num_qubits,
171 AER::Vector<std::complex<double>> &litudes)
override {
172 throw std::runtime_error(
173 "CompositeSimulator::InitializeState not supported");
189 void InitializeState(
size_t num_qubits,
190 Eigen::VectorXcd &litudes)
override {
191 throw std::runtime_error(
192 "CompositeSimulator::InitializeState not supported");
205 void Configure(
const char *key,
const char *value)
override {
207 if (std::string(
"method") == key)
return;
209 for (
auto &[
id, simulator] : simulators) simulator->Configure(key, value);
220 if (simulators.empty())
return "";
222 return simulators.begin()->second->GetConfiguration(key);
234 if (!simulators.empty())
return 0;
236 const size_t oldNrQubits = nrQubits;
237 nrQubits += num_qubits;
256 void Clear()
override {
268 for (
auto &[
id, simulator] : simulators)
269 simulator->SaveStateToInternalDestructive();
279 for (
auto &[
id, simulator] : simulators)
280 simulator->RestoreInternalDestructiveSavedState();
291 std::complex<double> AmplitudeRaw(Types::qubit_t outcome)
override {
292 std::complex<double> res = 1.0;
294 for (
auto &[
id, simulator] : simulators)
296 simulator->AmplitudeRaw(simulator->ConvertOutcomeFromGlobal(outcome));
308 size_t Measure(
const Types::qubits_vector &qubits)
override {
313 for (Types::qubit_t qubit : qubits) {
314 const bool outcome =
GetSimulator(qubit)->Measure({qubit}) != 0;
315 if (outcome) res |= mask;
318 Split(qubit, outcome);
322 NotifyObservers(qubits);
333 void ApplyReset(
const Types::qubits_vector &qubits)
override {
335 for (Types::qubit_t qubit : qubits) {
341 NotifyObservers(qubits);
353 double Probability(Types::qubit_t outcome)
override {
365 std::complex<double>
Amplitude(Types::qubit_t outcome)
override {
366 std::complex<double> res = 1.0;
368 for (
auto &[
id, simulator] : simulators)
369 res *= simulator->Amplitude(outcome);
382 const size_t nrBasisStates = 1ULL << nrQubits;
383 std::vector<double> result;
385 for (
size_t i = 0; i < nrBasisStates; ++i)
401 const Types::qubits_vector &qubits)
override {
402 std::vector<double> result;
404 for (
size_t i = 0; i < qubits.size(); ++i)
423 std::unordered_map<Types::qubit_t, Types::qubit_t>
SampleCounts(
424 const Types::qubits_vector &qubits,
size_t shots = 1000)
override {
426 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
434 for (
size_t shot = 0; shot < shots; ++shot) {
436 for (
auto &[
id, simulator] : simulators)
437 measRaw |= simulator->SampleFromAlias();
441 for (
auto q : qubits) {
442 const size_t qubitMask = 1ULL << q;
443 if ((measRaw & qubitMask) != 0) meas |= mask;
452 for (
size_t shot = 0; shot < shots; ++shot) {
457 for (
auto q : qubits) {
458 const size_t qubitMask = 1ULL << q;
459 if ((measRaw & qubitMask) != 0) meas |= mask;
469 NotifyObservers(qubits);
485 double ExpectationValue(
const std::string &pauliString)
override {
486 std::unordered_map<size_t, std::string> pauliStrings;
488 for (
size_t q = 0; q < pauliString.size(); ++q) {
489 const char op = toupper(pauliString[q]);
490 if (op ==
'I')
continue;
492 const size_t simId = qubitsMap[q];
493 const size_t localQubit = simulators[simId]->GetQubitsMap().at(q);
495 if (pauliStrings[simId].size() <= localQubit)
496 pauliStrings[simId].resize(localQubit + 1,
'I');
498 pauliStrings[simId][localQubit] = op;
502 for (
auto &[
id, localPauliString] : pauliStrings)
503 result *= simulators[
id]->ExpectationValue(localPauliString);
515 SimulatorType GetType()
const override {
517 return SimulatorType::kCompositeQCSim;
519 if (type != SimulatorType::kQiskitAer)
520 return SimulatorType::kCompositeQCSim;
522 return SimulatorType::kCompositeQiskitAer;
535 return SimulationType::kStatevector;
545 void Flush()
override {
546 for (
auto &[
id, simulator] : simulators) simulator->Flush();
558 void ApplyP(Types::qubit_t qubit,
double lambda)
override {
560 NotifyObservers({qubit});
569 void ApplyX(Types::qubit_t qubit)
override {
571 NotifyObservers({qubit});
580 void ApplyY(Types::qubit_t qubit)
override {
582 NotifyObservers({qubit});
591 void ApplyZ(Types::qubit_t qubit)
override {
593 NotifyObservers({qubit});
602 void ApplyH(Types::qubit_t qubit)
override {
604 NotifyObservers({qubit});
613 void ApplyS(Types::qubit_t qubit)
override {
615 NotifyObservers({qubit});
624 void ApplySDG(Types::qubit_t qubit)
override {
626 NotifyObservers({qubit});
635 void ApplyT(Types::qubit_t qubit)
override {
637 NotifyObservers({qubit});
646 void ApplyTDG(Types::qubit_t qubit)
override {
648 NotifyObservers({qubit});
657 void ApplySx(Types::qubit_t qubit)
override {
659 NotifyObservers({qubit});
668 void ApplySxDAG(Types::qubit_t qubit)
override {
670 NotifyObservers({qubit});
679 void ApplyK(Types::qubit_t qubit)
override {
681 NotifyObservers({qubit});
691 void ApplyRx(Types::qubit_t qubit,
double theta)
override {
693 NotifyObservers({qubit});
703 void ApplyRy(Types::qubit_t qubit,
double theta)
override {
705 NotifyObservers({qubit});
715 void ApplyRz(Types::qubit_t qubit,
double theta)
override {
717 NotifyObservers({qubit});
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});
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});
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});
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});
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});
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});
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});
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});
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});
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});
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});
885 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1)
override {
886 JoinIfNeeded(qubit0, qubit1);
888 NotifyObservers({qubit1, qubit0});
899 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1,
900 Types::qubit_t qubit2)
override {
903 JoinIfNeeded(qubit0, qubit1);
904 JoinIfNeeded(qubit0, qubit2);
906 NotifyObservers({qubit2, qubit1, qubit0});
917 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0,
918 Types::qubit_t qubit1)
override {
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});
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);
942 ->ApplyCU(ctrl_qubit, tgt_qubit, theta, phi, lambda, gamma);
943 NotifyObservers({tgt_qubit, ctrl_qubit});
957 enableMultithreading = multithreading;
958 for (
auto &[
id, simulator] : simulators)
959 simulator->SetMultithreading(multithreading);
981 bool IsQcsim()
const override {
999 void SaveState()
override { savedState = Clone(); }
1016 const CompositeSimulator *savedStatePtr =
1017 static_cast<CompositeSimulator *
>(savedState.get());
1020 savedStatePtr->type;
1027 savedStatePtr->nrQubits;
1028 nextId = savedStatePtr
1030 enableMultithreading =
1032 ->enableMultithreading;
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()));
1058 Types::qubit_t res = 0;
1060 for (
auto &[
id, simulator] : simulators) {
1061 const Types::qubit_t meas = simulator->MeasureNoCollapse();
1078 std::unique_ptr<ISimulator> Clone()
override {
1079 auto clone = std::make_unique<CompositeSimulator>(type);
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()));
1098 if (savedState) clone->savedState = savedState->Clone();
1104 void InitializeAlias() {
1105 for (
auto &[
id, simulator] : simulators) simulator->InitializeAlias();
1109 for (
auto &[
id, simulator] : simulators) simulator->ClearAlias();
1120 inline std::unique_ptr<IndividualSimulator> &
GetSimulator(
size_t qubit) {
1121 assert(qubitsMap.size() > qubit);
1122 assert(simulators.find(qubitsMap[qubit]) != simulators.end());
1125 return simulators[qubitsMap[qubit]];
1142 inline bool JoinNeeded(
size_t qubit1,
size_t qubit2) {
1146 return qubitsMap[qubit1] != qubitsMap[qubit2];
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];
1164 sim1->Join(simId, sim2, qubitsMap, enableMultithreading);
1166 simulators.erase(eraseSimId);
1180 inline void Split(
size_t qubit,
bool qubitOutcome =
false) {
1183 if (sim->GetNumberOfQubits() ==
1187 qubitsMap[qubit] = nextId;
1188 simulators[nextId] = sim->Split(qubit, qubitOutcome, enableMultithreading);
1197 std::unordered_map<size_t, std::unique_ptr<IndividualSimulator>>
1199 size_t nrQubits = 0;
1201 bool enableMultithreading =
1204 std::unique_ptr<ISimulator> savedState;
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)
@ kQCSim
qcsim simulator type
@ kQiskitAer
qiskit aer simulator type