15#ifdef INCLUDED_BY_FACTORY
17#include "../Utils/Alias.h"
19#include <unordered_map>
28class CompositeSimulator;
38class IndividualSimulator :
public ISimulator {
39 friend class CompositeSimulator;
48 IndividualSimulator(SimulatorType type =
55 : simulator(SimulatorsFactory::CreateSimulatorUnique(
66 void Reset()
override { simulator->Reset(); }
79 inline void Join(
size_t simId,
80 const std::unique_ptr<IndividualSimulator> &other,
81 std::vector<size_t> &qubitsMapToSim,
82 bool enableMultithreading) {
87 const size_t nrBasisStates1 = 1ULL << nrQubits1;
88 const size_t nrQubits2 = other->GetNumberOfQubits();
89 const size_t nrBasisStates2 = 1ULL << nrQubits2;
91 const size_t newNrQubits = nrQubits1 + nrQubits2;
92 const size_t nrBasisStates = 1ULL << newNrQubits;
95 other->SaveStateToInternalDestructive();
97 if (GetType() == SimulatorType::kQCSim) {
98 if (enableMultithreading && nrBasisStates > OmpLimitJoin)
99 JoinOmpQcsim(nrQubits1, nrBasisStates1, nrBasisStates2, newNrQubits,
100 nrBasisStates, other, enableMultithreading);
102 Eigen::VectorXcd newAmplitudes;
103 newAmplitudes.resize(nrBasisStates);
105 for (
size_t state2 = 0; state2 < nrBasisStates2; ++state2) {
106 const auto ampl2 = other->AmplitudeRaw(state2);
107 const size_t state2Mask = state2 << nrQubits1;
108 for (
size_t state1 = 0; state1 < nrBasisStates1; ++state1)
109 newAmplitudes[state2Mask | state1] = AmplitudeRaw(state1) * ampl2;
118 simulator->InitializeState(
127 if (enableMultithreading && nrBasisStates > OmpLimitJoin)
128 JoinOmpAer(nrQubits1, nrBasisStates1, nrBasisStates2, newNrQubits,
129 nrBasisStates, other, enableMultithreading);
131 AER::Vector<std::complex<double>> newAmplitudes(
132 nrBasisStates,
false);
135 for (
size_t state2 = 0; state2 < nrBasisStates2; ++state2) {
136 const auto ampl2 = other->AmplitudeRaw(state2);
137 const size_t state2Mask = state2 << nrQubits1;
138 for (
size_t state1 = 0; state1 < nrBasisStates1; ++state1)
139 newAmplitudes[state2Mask | state1] = AmplitudeRaw(state1) * ampl2;
147 simulator->InitializeState(
155 for (
auto [origq, mapq] : other->GetQubitsMap()) {
156 qubitsMap[origq] = mapq + nrQubits1;
157 qubitsMapToSim[origq] = simId;
174 inline std::unique_ptr<IndividualSimulator> Split(
size_t qubit,
176 bool enableMultithreading) {
178 const size_t newNrQubits = oldNrQubits - 1;
179 const size_t nrBasisStates = 1ULL << newNrQubits;
180 const size_t localQubit = qubitsMap[qubit];
186 auto newSimulator = std::make_unique<IndividualSimulator>(GetType());
187 newSimulator->AllocateQubits(1);
188 newSimulator->GetQubitsMap()[qubit] =
191 newSimulator->SetMultithreading(enableMultithreading);
192 newSimulator->Initialize();
194 newSimulator->ApplyX(qubit);
198 qubitsMap.erase(qubit);
202 if (GetType() == SimulatorType::kQCSim) {
211 Eigen::VectorXcd newAmplitudes;
212 newAmplitudes.resize(nrBasisStates);
216 const size_t localQubitMask = 1ULL << localQubit;
217 const size_t maskLow = localQubitMask - 1ULL;
218 const size_t maskHigh = ~maskLow;
219 const size_t qubitMask = qubitOutcome ? localQubitMask : 0ULL;
221 for (
size_t state = 0; state < nrBasisStates; ++state) {
222 const size_t stateLow = state & maskLow;
223 const size_t stateHigh = (state & maskHigh) << 1ULL;
225 newAmplitudes[state] = AmplitudeRaw(stateLow | stateHigh | qubitMask);
229 simulator->InitializeState(
246 AER::Vector<std::complex<double>> newAmplitudes(
247 nrBasisStates,
false);
251 const size_t localQubitMask = 1ULL << localQubit;
252 const size_t maskLow = localQubitMask - 1ULL;
253 const size_t maskHigh = ~maskLow;
254 const size_t qubitMask = qubitOutcome ? localQubitMask : 0ULL;
256 for (
size_t state = 0; state < nrBasisStates; ++state) {
257 const size_t stateLow = state & maskLow;
258 const size_t stateHigh = (state & maskHigh) << 1ULL;
260 newAmplitudes[state] = AmplitudeRaw(stateLow | stateHigh | qubitMask);
264 simulator->InitializeState(
273 for (
auto &mapped : qubitsMap)
274 if (mapped.second > localQubit) --mapped.second;
288 std::complex<double> AmplitudeRaw(Types::qubit_t outcome)
override {
289 return simulator->AmplitudeRaw(outcome);
302 simulator->SaveStateToInternalDestructive();
312 simulator->RestoreInternalDestructiveSavedState();
324 inline Types::qubits_vector ConvertQubits(
325 const Types::qubits_vector &qubits) {
326 Types::qubits_vector converted;
327 converted.reserve(qubits.size());
329 for (
auto qubit : qubits)
330 if (HasQubit(qubit)) converted.emplace_back(qubitsMap[qubit]);
343 inline bool HasQubit(Types::qubit_t qubit)
const {
344 return qubitsMap.find(qubit) != qubitsMap.end();
355 inline Types::qubit_t ConvertOutcomeFromLocal(Types::qubit_t outcome)
const {
356 Types::qubit_t res = 0;
358 for (
auto [origQubit, localQubit] : qubitsMap)
359 if (outcome & (1ULL << localQubit)) res |= (1ULL << origQubit);
372 inline Types::qubit_t ConvertOutcomeFromGlobal(Types::qubit_t outcome)
const {
373 Types::qubit_t res = 0;
375 for (
auto [origQubit, localQubit] : qubitsMap)
376 if (outcome & (1ULL << origQubit)) res |= (1ULL << localQubit);
387 if (!simulator)
return;
388 const size_t nrBasisStates = 1ULL << simulator->GetNumberOfQubits();
389 savedState.reserve(nrBasisStates);
391 for (Types::qubit_t state = 0; state < nrBasisStates; ++state)
392 savedState.emplace_back(simulator->Amplitude(state));
400 void ClearSavedState() { savedState.clear(); }
408 if (!simulator)
return;
409 const size_t nrQubits = simulator->GetNumberOfQubits();
412 simulator->InitializeState(nrQubits, savedState);
424 inline std::unordered_map<Types::qubit_t, Types::qubit_t> &GetQubitsMap() {
436 inline const std::unordered_map<Types::qubit_t, Types::qubit_t> &
437 GetQubitsMap()
const {
447 void Initialize()
override { simulator->Initialize(); }
461 void InitializeState(
size_t num_qubits,
462 std::vector<std::complex<double>> &litudes)
override {
463 simulator->InitializeState(num_qubits, amplitudes);
499 void InitializeState(
size_t num_qubits,
500 AER::Vector<std::complex<double>> &litudes)
override {
501 simulator->InitializeState(num_qubits, amplitudes);
517 void InitializeState(
size_t num_qubits,
518 Eigen::VectorXcd &litudes)
override {
519 simulator->InitializeState(num_qubits, amplitudes);
530 void Configure(
const char *key,
const char *value)
override {
531 simulator->Configure(key, value);
542 if (!simulator)
return "";
544 return simulator->GetConfiguration(key);
555 return simulator->AllocateQubits(num_qubits);
565 return simulator->GetNumberOfQubits();
575 void Clear()
override { simulator->Clear(); }
586 size_t Measure(
const Types::qubits_vector &qubits)
override {
587 return ConvertOutcomeFromLocal(simulator->Measure(ConvertQubits(qubits)));
596 void ApplyReset(
const Types::qubits_vector &qubits)
override {
597 simulator->ApplyReset(ConvertQubits(qubits));
611 double Probability(Types::qubit_t outcome)
override {
612 return simulator->Probability(ConvertOutcomeFromGlobal(outcome));
625 std::complex<double>
Amplitude(Types::qubit_t outcome)
override {
626 return simulator->Amplitude(ConvertOutcomeFromGlobal(outcome));
639 return simulator->AllProbabilities();
654 const Types::qubits_vector &qubits)
override {
655 return simulator->Probabilities(ConvertQubits(qubits));
673 std::unordered_map<Types::qubit_t, Types::qubit_t>
SampleCounts(
674 const Types::qubits_vector &qubits,
size_t shots = 1000)
override {
675 std::unordered_map<Types::qubit_t, Types::qubit_t> res;
677 const auto sc = simulator->SampleCounts(ConvertQubits(qubits), shots);
679 for (
auto [outcome, count] : sc)
680 res[ConvertOutcomeFromLocal(outcome)] = count;
696 double ExpectationValue(
const std::string &pauliString)
override {
697 return simulator->ExpectationValue(pauliString);
707 SimulatorType GetType()
const override {
return simulator->GetType(); }
718 return SimulationType::kStatevector;
728 void Flush()
override { simulator->Flush(); }
740 void ApplyP(Types::qubit_t qubit,
double lambda)
override {
741 simulator->ApplyP(qubitsMap[qubit], lambda);
750 void ApplyX(Types::qubit_t qubit)
override {
751 simulator->ApplyX(qubitsMap[qubit]);
760 void ApplyY(Types::qubit_t qubit)
override {
761 simulator->ApplyY(qubitsMap[qubit]);
770 void ApplyZ(Types::qubit_t qubit)
override {
771 simulator->ApplyZ(qubitsMap[qubit]);
780 void ApplyH(Types::qubit_t qubit)
override {
781 simulator->ApplyH(qubitsMap[qubit]);
790 void ApplyS(Types::qubit_t qubit)
override {
791 simulator->ApplyS(qubitsMap[qubit]);
800 void ApplySDG(Types::qubit_t qubit)
override {
801 simulator->ApplySDG(qubitsMap[qubit]);
810 void ApplyT(Types::qubit_t qubit)
override {
811 simulator->ApplyT(qubitsMap[qubit]);
820 void ApplyTDG(Types::qubit_t qubit)
override {
821 simulator->ApplyTDG(qubitsMap[qubit]);
830 void ApplySx(Types::qubit_t qubit)
override {
831 simulator->ApplySx(qubitsMap[qubit]);
840 void ApplySxDAG(Types::qubit_t qubit)
override {
841 simulator->ApplySxDAG(qubitsMap[qubit]);
850 void ApplyK(Types::qubit_t qubit)
override {
851 simulator->ApplyK(qubitsMap[qubit]);
861 void ApplyRx(Types::qubit_t qubit,
double theta)
override {
862 simulator->ApplyRx(qubitsMap[qubit], theta);
872 void ApplyRy(Types::qubit_t qubit,
double theta)
override {
873 simulator->ApplyRy(qubitsMap[qubit], theta);
883 void ApplyRz(Types::qubit_t qubit,
double theta)
override {
884 simulator->ApplyRz(qubitsMap[qubit], theta);
897 void ApplyU(Types::qubit_t qubit,
double theta,
double phi,
double lambda,
898 double gamma)
override {
899 simulator->ApplyU(qubitsMap[qubit], theta, phi, lambda, gamma);
909 void ApplyCX(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit)
override {
910 simulator->ApplyCX(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit]);
920 void ApplyCY(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit)
override {
921 simulator->ApplyCY(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit]);
931 void ApplyCZ(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit)
override {
932 simulator->ApplyCZ(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit]);
943 void ApplyCP(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
944 double lambda)
override {
945 simulator->ApplyCP(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit], lambda);
956 void ApplyCRx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
957 double theta)
override {
958 simulator->ApplyCRx(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit], theta);
969 void ApplyCRy(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
970 double theta)
override {
971 simulator->ApplyCRy(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit], theta);
982 void ApplyCRz(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
983 double theta)
override {
984 simulator->ApplyCRz(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit], theta);
994 void ApplyCH(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit)
override {
995 simulator->ApplyCH(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit]);
1005 void ApplyCSx(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit)
override {
1006 simulator->ApplyCSx(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit]);
1016 void ApplyCSxDAG(Types::qubit_t ctrl_qubit,
1017 Types::qubit_t tgt_qubit)
override {
1018 simulator->ApplyCSxDAG(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit]);
1028 void ApplySwap(Types::qubit_t qubit0, Types::qubit_t qubit1)
override {
1029 simulator->ApplySwap(qubitsMap[qubit0], qubitsMap[qubit1]);
1040 void ApplyCCX(Types::qubit_t qubit0, Types::qubit_t qubit1,
1041 Types::qubit_t qubit2)
override {
1042 simulator->ApplyCCX(qubitsMap[qubit0], qubitsMap[qubit1],
1054 void ApplyCSwap(Types::qubit_t ctrl_qubit, Types::qubit_t qubit0,
1055 Types::qubit_t qubit1)
override {
1056 simulator->ApplyCSwap(qubitsMap[ctrl_qubit], qubitsMap[qubit0],
1071 void ApplyCU(Types::qubit_t ctrl_qubit, Types::qubit_t tgt_qubit,
1072 double theta,
double phi,
double lambda,
double gamma)
override {
1073 simulator->ApplyCU(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit], theta, phi,
1077 void ApplyNop()
override { simulator->ApplyNop(); }
1088 if (simulator) simulator->SetMultithreading(multithreading);
1091 multithreading ? QC::QubitRegister<>::GetNumberOfThreads() : 1;
1102 if (simulator)
return simulator->GetMultithreading();
1117 bool IsQcsim()
const override {
1135 return ConvertOutcomeFromLocal(simulator->MeasureNoCollapse());
1148 std::unique_ptr<ISimulator> Clone()
override {
1149 auto cloned = std::make_unique<IndividualSimulator>();
1154 cloned->savedState =
1157 cloned->simulator = simulator->Clone();
1162 Types::qubit_t SampleFromAlias() {
1163 if (!alias || !simulator)
return 0;
1166 if (GetType() == SimulatorType::kQCSim) {
1169 QCSimSimulator *qcsim =
dynamic_cast<QCSimSimulator *
>(simulator.get());
1170 prob = 1. - qcsim->uniformZeroOne(qcsim->rng);
1172#ifndef NO_QISKIT_AER
1176#ifndef NO_QISKIT_AER
1177 AerSimulator *aer =
dynamic_cast<AerSimulator *
>(simulator.get());
1178 prob = 1 - aer->uniformZeroOne(aer->rng);
1185 const size_t measRaw = alias->Sample(prob);
1187 return ConvertOutcomeFromLocal(measRaw);
1191 void InitializeAlias() {
1193 if (GetType() == SimulatorType::kQCSim) {
1196 QCSimSimulator *qcsim =
dynamic_cast<QCSimSimulator *
>(simulator.get());
1198 alias = std::unique_ptr<Utils::Alias>(
1201#ifndef NO_QISKIT_AER
1205#ifndef NO_QISKIT_AER
1206 AerSimulator *aer =
dynamic_cast<AerSimulator *
>(simulator.get());
1208 alias = std::unique_ptr<Utils::Alias>(
1213 throw std::runtime_error(
"Qiskit Aer is disabled in this build.");
1219 void ClearAlias() { alias =
nullptr; }
1233#ifndef NO_QISKIT_AER
1234 inline void JoinOmpAer(
size_t nrQubits1,
size_t nrBasisStates1,
1235 size_t nrBasisStates2,
size_t newNrQubits,
1236 size_t nrBasisStates,
1237 const std::unique_ptr<IndividualSimulator> &other,
1238 bool enableMultithreading) {
1239 AER::Vector<std::complex<double>> newAmplitudes(
1240 nrBasisStates,
false);
1253#pragma omp parallel for num_threads(processor_count)
1254 for (
long long int state2 = 0;
1255 state2 < static_cast<long long int>(nrBasisStates2); ++state2) {
1256 const auto ampl2 = other->AmplitudeRaw(state2);
1257 const size_t state2Mask = state2 << nrQubits1;
1258 for (
size_t state1 = 0; state1 < nrBasisStates1; ++state1)
1259 newAmplitudes[state2Mask | state1] = AmplitudeRaw(state1) * ampl2;
1267 simulator->InitializeState(
1328 inline void JoinOmpQcsim(
size_t nrQubits1,
size_t nrBasisStates1,
1329 size_t nrBasisStates2,
size_t newNrQubits,
1330 size_t nrBasisStates,
1331 const std::unique_ptr<IndividualSimulator> &other,
1332 bool enableMultithreading) {
1333 Eigen::VectorXcd newAmplitudes;
1334 newAmplitudes.resize(nrBasisStates);
1346#pragma omp parallel for num_threads(processor_count)
1347 for (
long long int state2 = 0;
1348 state2 < static_cast<long long int>(nrBasisStates2); ++state2) {
1349 const auto ampl2 = other->AmplitudeRaw(state2);
1350 const size_t state2Mask = state2 << nrQubits1;
1351 for (
size_t state1 = 0; state1 < nrBasisStates1; ++state1)
1352 newAmplitudes[state2Mask | state1] = AmplitudeRaw(state1) * ampl2;
1360 simulator->InitializeState(
1361 newNrQubits, newAmplitudes);
1407 std::unordered_map<Types::qubit_t, Types::qubit_t>
1410 std::unique_ptr<ISimulator> simulator;
1411 std::vector<std::complex<double>>
1415 std::unique_ptr<Utils::Alias>
1418 int processor_count =
1419 QC::QubitRegister<>::GetNumberOfThreads();
1424 constexpr static size_t OmpLimitJoin = 4096 * 2;
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)
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)
SimulationType
The type of simulation.
@ kStatevector
statevector simulation type
SimulatorType
The type of simulator.
@ kQCSim
qcsim simulator type
@ kQiskitAer
qiskit aer simulator type