15#ifdef INCLUDED_BY_FACTORY
21#include <unordered_map>
32class ImmediateCompositeSimulator;
42class IndividualSimulator :
public ISimulator
44 friend class ImmediateCompositeSimulator;
53 IndividualSimulator(SimulatorType type =
60 : simulator(SimulatorsFactory::CreateImmediateSimulatorUnique(type))
87 inline void Join(
size_t simId,
const std::unique_ptr<IndividualSimulator> &other, std::vector<size_t> &qubitsMapToSim,
bool enableMultithreading)
93 const size_t nrBasisStates1 = 1ULL << nrQubits1;
94 const size_t nrQubits2 = other->GetNumberOfQubits();
95 const size_t nrBasisStates2 = 1ULL << nrQubits2;
97 const size_t newNrQubits = nrQubits1 + nrQubits2;
98 const size_t nrBasisStates = 1ULL << newNrQubits;
101 other->SaveStateToInternalDestructive();
103 if (GetType() == SimulatorType::kQCSim)
105 if (enableMultithreading && nrBasisStates > OmpLimitJoin)
106 JoinOmpQcsim(nrQubits1, nrBasisStates1, nrBasisStates2, newNrQubits, nrBasisStates, other, enableMultithreading);
109 Eigen::VectorXcd newAmplitudes;
110 newAmplitudes.resize(nrBasisStates);
112 for (
size_t state2 = 0; state2 < nrBasisStates2; ++state2)
114 const auto ampl2 = other->AmplitudeRaw(state2);
115 const size_t state2Mask = state2 << nrQubits1;
116 for (
size_t state1 = 0; state1 < nrBasisStates1; ++state1)
117 newAmplitudes[state2Mask | state1] = AmplitudeRaw(state1) * ampl2;
126 static_cast<QCSimStatevectorSimulator *
>(simulator.get())
127 ->ReplaceState(newNrQubits,
136 if (enableMultithreading && nrBasisStates > OmpLimitJoin)
137 JoinOmpAer(nrQubits1, nrBasisStates1, nrBasisStates2, newNrQubits, nrBasisStates, other, enableMultithreading);
140 AER::Vector<std::complex<double>> newAmplitudes(nrBasisStates,
false);
143 for (
size_t state2 = 0; state2 < nrBasisStates2; ++state2)
145 const auto ampl2 = other->AmplitudeRaw(state2);
146 const size_t state2Mask = state2 << nrQubits1;
147 for (
size_t state1 = 0; state1 < nrBasisStates1; ++state1)
148 newAmplitudes[state2Mask | state1] = AmplitudeRaw(state1) * ampl2;
156 simulator->InitializeState(newNrQubits,
163 for (
auto [origq, mapq] : other->GetQubitsMap())
165 qubitsMap[origq] = mapq + nrQubits1;
166 qubitsMapToSim[origq] = simId;
183 inline std::unique_ptr<IndividualSimulator> Split(
size_t qubit,
bool qubitOutcome,
bool enableMultithreading, uint64_t splitSeed)
186 const size_t newNrQubits = oldNrQubits - 1;
187 const size_t nrBasisStates = 1ULL << newNrQubits;
188 const size_t localQubit = qubitsMap[qubit];
194 auto newSimulator = std::make_unique<IndividualSimulator>(GetType());
195 newSimulator->AllocateQubits(1);
196 newSimulator->GetQubitsMap()[qubit] = 0;
198 newSimulator->SetMultithreading(enableMultithreading);
200 for (
const auto &[key, value] : GetConfigMap())
202 newSimulator->Configure(key.c_str(), value.c_str());
203 newSimulator->SetSeed(splitSeed);
205 newSimulator->Initialize();
208 newSimulator->ApplyX(qubit);
212 qubitsMap.erase(qubit);
216 if (GetType() == SimulatorType::kQCSim)
226 Eigen::VectorXcd newAmplitudes;
227 newAmplitudes.resize(nrBasisStates);
231 const size_t localQubitMask = 1ULL << localQubit;
232 const size_t maskLow = localQubitMask - 1ULL;
233 const size_t maskHigh = ~maskLow;
234 const size_t qubitMask = qubitOutcome ? localQubitMask : 0ULL;
236 for (
size_t state = 0; state < nrBasisStates; ++state)
238 const size_t stateLow = state & maskLow;
239 const size_t stateHigh = (state & maskHigh) << 1ULL;
241 newAmplitudes[state] = AmplitudeRaw(stateLow | stateHigh | qubitMask);
245 static_cast<QCSimStatevectorSimulator *
>(simulator.get())
246 ->ReplaceState(newNrQubits,
263 AER::Vector<std::complex<double>> newAmplitudes(nrBasisStates,
false);
267 const size_t localQubitMask = 1ULL << localQubit;
268 const size_t maskLow = localQubitMask - 1ULL;
269 const size_t maskHigh = ~maskLow;
270 const size_t qubitMask = qubitOutcome ? localQubitMask : 0ULL;
272 for (
size_t state = 0; state < nrBasisStates; ++state)
274 const size_t stateLow = state & maskLow;
275 const size_t stateHigh = (state & maskHigh) << 1ULL;
277 newAmplitudes[state] = AmplitudeRaw(stateLow | stateHigh | qubitMask);
281 simulator->InitializeState(newNrQubits,
289 for (
auto &mapped : qubitsMap)
290 if (mapped.second > localQubit)
305 std::complex<double> AmplitudeRaw(
Types::qubit_t outcome)
override
307 return simulator->AmplitudeRaw(outcome);
321 simulator->SaveStateToInternalDestructive();
332 simulator->RestoreInternalDestructiveSavedState();
347 converted.reserve(qubits.size());
349 for (
auto qubit : qubits)
351 converted.emplace_back(qubitsMap[qubit]);
366 return qubitsMap.find(qubit) != qubitsMap.end();
381 for (
auto [origQubit, localQubit] : qubitsMap)
382 if (outcome & (1ULL << localQubit))
383 res |= (1ULL << origQubit);
400 for (
auto [origQubit, localQubit] : qubitsMap)
401 if (outcome & (1ULL << origQubit))
402 res |= (1ULL << localQubit);
415 inline std::vector<bool> ConvertOutcomeFromLocal(
const std::vector<bool> &outcome)
const
417 std::vector<bool> res;
420 for (
auto [origQubit, localQubit] : qubitsMap)
421 if (origQubit > maxQubit)
422 maxQubit = origQubit;
423 res.resize(maxQubit + 1,
false);
425 for (
auto [origQubit, localQubit] : qubitsMap)
426 if (outcome[localQubit])
427 res[origQubit] =
true;
440 inline std::vector<bool> ConvertOutcomeFromGlobal(
const std::vector<bool> &outcome)
const
442 const size_t nrQubits = simulator->GetNumberOfQubits();
443 std::vector<bool> res(nrQubits,
false);
445 for (
auto [origQubit, localQubit] : qubitsMap)
446 if (outcome[origQubit])
447 res[localQubit] =
true;
461 const size_t nrBasisStates = 1ULL << simulator->GetNumberOfQubits();
462 savedState.resize(nrBasisStates);
465 savedState[state] = simulator->Amplitude(state);
473 void ClearSavedState()
485 if (!simulator || savedState.empty())
487 const size_t nrQubits = simulator->GetNumberOfQubits();
489 if (GetType() == SimulatorType::kQCSim)
491 Eigen::VectorXcd amplitudes(Eigen::Map<const Eigen::VectorXcd>(savedState.data(), savedState.size()));
492 static_cast<QCSimStatevectorSimulator *
>(simulator.get())->ReplaceState(nrQubits, amplitudes);
497 simulator->InitializeState(nrQubits, savedState);
510 inline std::unordered_map<Types::qubit_t, Types::qubit_t> &GetQubitsMap()
523 inline const std::unordered_map<Types::qubit_t, Types::qubit_t> &GetQubitsMap()
const
534 void Initialize()
override
536 simulator->Initialize();
551 void InitializeState(
size_t num_qubits, std::vector<std::complex<double>> &litudes)
override
553 simulator->InitializeState(num_qubits, amplitudes);
589 void InitializeState(
size_t num_qubits, AER::Vector<std::complex<double>> &litudes)
override
591 simulator->InitializeState(num_qubits, amplitudes);
607 void InitializeState(
size_t num_qubits, Eigen::VectorXcd &litudes)
override
609 simulator->InitializeState(num_qubits, amplitudes);
620 void Configure(
const char *key,
const char *value)
override
622 if (std::string(
"seed") == key)
624 const uint64_t seed = std::stoull(value);
625 SeedAuxiliaryRng(seed);
626 simulator->SetSeed(seed);
630 simulator->Configure(key, value);
646 return simulator->GetConfiguration(key);
658 return simulator->AllocateQubits(num_qubits);
669 return simulator->GetNumberOfQubits();
679 void Clear()
override
697 return ConvertOutcomeFromLocal(simulator->Measure(ConvertQubits(qubits)));
710 return ConvertOutcomeFromLocal(simulator->MeasureMany(ConvertQubits(qubits)));
721 simulator->ApplyReset(ConvertQubits(qubits));
737 return simulator->Probability(ConvertOutcomeFromGlobal(outcome));
752 return simulator->Amplitude(ConvertOutcomeFromGlobal(outcome));
768 std::complex<double> ProjectOnZero()
override
784 return simulator->AllProbabilities();
800 return simulator->Probabilities(ConvertQubits(qubits));
824 return simulator->SampleCounts(ConvertQubits(qubits), shots);
842 return simulator->SampleCountsMany(ConvertQubits(qubits), shots);
856 double ExpectationValue(
const std::string &pauliString)
override
858 return simulator->ExpectationValue(pauliString);
870 return simulator->GetType();
883 return SimulationType::kStatevector;
893 void Flush()
override
908 simulator->ApplyGenericOneQubitGate(qubitsMap[qubit], gate);
919 simulator->ApplyGenericTwoQubitGate(qubitsMap[qubit0], qubitsMap[qubit1], gate);
924 simulator->ApplyGenericThreeQubitGate(qubitsMap.at(q0), qubitsMap.at(q1), qubitsMap.at(q2), gate);
936 simulator->ApplyP(qubitsMap[qubit], lambda);
947 simulator->ApplyX(qubitsMap[qubit]);
958 simulator->ApplyY(qubitsMap[qubit]);
969 simulator->ApplyZ(qubitsMap[qubit]);
980 simulator->ApplyH(qubitsMap[qubit]);
991 simulator->ApplyS(qubitsMap[qubit]);
1002 simulator->ApplySDG(qubitsMap[qubit]);
1013 simulator->ApplyT(qubitsMap[qubit]);
1024 simulator->ApplyTDG(qubitsMap[qubit]);
1035 simulator->ApplySx(qubitsMap[qubit]);
1046 simulator->ApplySxDAG(qubitsMap[qubit]);
1057 simulator->ApplyK(qubitsMap[qubit]);
1069 simulator->ApplyRx(qubitsMap[qubit], theta);
1081 simulator->ApplyRy(qubitsMap[qubit], theta);
1093 simulator->ApplyRz(qubitsMap[qubit], theta);
1106 void ApplyU(
Types::qubit_t qubit,
double theta,
double phi,
double lambda,
double gamma)
override
1108 simulator->ApplyU(qubitsMap[qubit], theta, phi, lambda, gamma);
1120 simulator->ApplyCX(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit]);
1132 simulator->ApplyCY(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit]);
1144 simulator->ApplyCZ(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit]);
1157 simulator->ApplyCP(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit], lambda);
1170 simulator->ApplyCRx(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit], theta);
1183 simulator->ApplyCRy(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit], theta);
1196 simulator->ApplyCRz(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit], theta);
1208 simulator->ApplyCH(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit]);
1220 simulator->ApplyCSx(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit]);
1232 simulator->ApplyCSxDAG(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit]);
1244 simulator->ApplySwap(qubitsMap[qubit0], qubitsMap[qubit1]);
1257 simulator->ApplyCCX(qubitsMap[qubit0], qubitsMap[qubit1], qubitsMap[qubit2]);
1270 simulator->ApplyCSwap(qubitsMap[ctrl_qubit], qubitsMap[qubit0], qubitsMap[qubit1]);
1286 simulator->ApplyCU(qubitsMap[ctrl_qubit], qubitsMap[tgt_qubit], theta, phi, lambda, gamma);
1289 void ApplyNop()
override
1291 simulator->ApplyNop();
1305 simulator->SetMultithreading(multithreading);
1307 processor_count = multithreading ? QC::QubitRegister<>::GetNumberOfThreads() : 1;
1320 return simulator->GetMultithreading();
1358 return ConvertOutcomeFromLocal(simulator->MeasureNoCollapse());
1375 std::vector<bool> MeasureNoCollapseMany()
override
1377 auto res = simulator->MeasureNoCollapseMany();
1378 return ConvertOutcomeFromLocal(res);
1391 std::unique_ptr<ISimulator> Clone()
override
1393 auto cloned = std::make_unique<IndividualSimulator>();
1395 cloned->qubitsMap = qubitsMap;
1397 cloned->savedState = savedState;
1399 cloned->simulator = simulator->Clone();
1404 std::unique_ptr<ISimulator> CloneForExecution(uint64_t seed)
override
1406 auto cloned = std::make_unique<IndividualSimulator>();
1407 cloned->qubitsMap = qubitsMap;
1408 cloned->savedState = savedState;
1409 cloned->simulator = simulator->CloneForExecution(seed);
1415 if (!alias || !simulator)
1419 if (GetType() == SimulatorType::kQCSim)
1423 QCSimStatevectorSimulator *qcsim =
dynamic_cast<QCSimStatevectorSimulator *
>(simulator.get());
1424 prob = 1. - qcsim->uniformZeroOne(qcsim->rng);
1426#ifndef NO_QISKIT_AER
1431#ifndef NO_QISKIT_AER
1432 AerSimulator *aer =
dynamic_cast<AerSimulator *
>(simulator.get());
1433 prob = 1 - aer->uniformZeroOne(aer->rng);
1440 const size_t measRaw = alias->Sample(prob);
1442 return ConvertOutcomeFromLocal(measRaw);
1445 const std::unordered_map<std::string, std::string> &GetConfigMap()
const override
1449 static const std::unordered_map<std::string, std::string> emptyMap;
1453 return simulator->GetConfigMap();
1459 QCSimStatevectorSimulator &SamplingStatevector()
const
1461 return *
static_cast<QCSimStatevectorSimulator *
>(simulator.get());
1464 size_t SamplingRows()
const
1466 return size_t{1} << SamplingStatevector().samplingSupportQubits;
1469 Utils::Sampling::Options SamplingOptions()
const
1471 return SamplingStatevector().SamplingOptions();
1474 std::mt19937_64 &SamplingRng()
1476 return SamplingStatevector().rng;
1479 QCSimStatevectorSimulator::SamplingPlan PrepareSampling(
size_t shots, Utils::Sampling::Options options)
const
1481 return {SamplingRows(), shots, {&SamplingStatevector().state->getRegisterStorage()}, options};
1484 size_t SampleLocalOnce()
1486 auto &backend = *SamplingStatevector().state;
1488 struct RestoreThreading
1490 QC::QubitRegister<> &backend;
1495 backend.SetMultithreading(enabled);
1497 } restore{backend, simulator->GetMultithreading()};
1499 backend.SetMultithreading(
false);
1500 return backend.MeasureNoCollapse();
1503 void DiscardLocalMeasurementDraw()
1505 SamplingStatevector().state->DiscardMeasurementDraw();
1508 void InitializeAlias()
1510 if (GetType() == SimulatorType::kQCSim)
1514 QCSimStatevectorSimulator *qcsim =
dynamic_cast<QCSimStatevectorSimulator *
>(simulator.get());
1515 alias = std::make_unique<Utils::Alias>(qcsim->state->getRegisterStorage());
1517#ifndef NO_QISKIT_AER
1522#ifndef NO_QISKIT_AER
1523 AerSimulator *aer =
dynamic_cast<AerSimulator *
>(simulator.get());
1526 alias = std::unique_ptr<Utils::Alias>(
new Utils::Alias(aer->savedAmplitudes));
1530 throw std::runtime_error(
"Qiskit Aer is disabled in this build.");
1553#ifndef NO_QISKIT_AER
1554 inline void JoinOmpAer(
size_t nrQubits1,
size_t nrBasisStates1,
size_t nrBasisStates2,
size_t newNrQubits,
size_t nrBasisStates,
1555 const std::unique_ptr<IndividualSimulator> &other,
bool enableMultithreading)
1557 AER::Vector<std::complex<double>> newAmplitudes(nrBasisStates,
false);
1570#pragma omp parallel for num_threads(processor_count)
1571 for (
long long int state2 = 0; state2 < static_cast<long long int>(nrBasisStates2); ++state2)
1573 const auto ampl2 = other->AmplitudeRaw(state2);
1574 const size_t state2Mask = state2 << nrQubits1;
1575 for (
size_t state1 = 0; state1 < nrBasisStates1; ++state1)
1576 newAmplitudes[state2Mask | state1] = AmplitudeRaw(state1) * ampl2;
1584 simulator->InitializeState(newNrQubits,
1644 inline void JoinOmpQcsim(
size_t nrQubits1,
size_t nrBasisStates1,
size_t nrBasisStates2,
size_t newNrQubits,
size_t nrBasisStates,
1645 const std::unique_ptr<IndividualSimulator> &other,
bool enableMultithreading)
1647 Eigen::VectorXcd newAmplitudes;
1648 newAmplitudes.resize(nrBasisStates);
1660#pragma omp parallel for num_threads(processor_count)
1661 for (
long long int state2 = 0; state2 < static_cast<long long int>(nrBasisStates2); ++state2)
1663 const auto ampl2 = other->AmplitudeRaw(state2);
1664 const size_t state2Mask = state2 << nrQubits1;
1665 for (
size_t state1 = 0; state1 < nrBasisStates1; ++state1)
1666 newAmplitudes[state2Mask | state1] = AmplitudeRaw(state1) * ampl2;
1674 static_cast<QCSimStatevectorSimulator *
>(simulator.get())->ReplaceState(newNrQubits, newAmplitudes);
1720 std::unordered_map<Types::qubit_t, Types::qubit_t> qubitsMap;
1722 std::unique_ptr<ISimulator> simulator;
1723 std::vector<std::complex<double>> savedState;
1726 std::unique_ptr<Utils::Alias> alias;
1728 int processor_count = QC::QubitRegister<>::GetNumberOfThreads();
1733 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 ApplyGenericThreeQubitGate(void *sim, unsigned long q0, unsigned long q1, unsigned long q2, const double *buffer)
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)
int ApplyGenericOneQubitGate(void *sim, unsigned long q0, const double *buffer)
int ApplyGenericTwoQubitGate(void *sim, unsigned long q0, unsigned long q1, const double *buffer)
Bounded online routing based on current physical bond dimensions.
SimulationType
The type of simulation.
SimulatorType
The type of simulator.
@ kQCSim
qcsim simulator type
@ kQiskitAer
qiskit aer simulator type
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
uint_fast64_t qubit_t
The type of a qubit.