20#ifdef INCLUDED_BY_FACTORY
44class CompositeSimulator :
public ISimulator {
53 CompositeSimulator(SimulatorType type =
71 type != SimulatorType::kQiskitAer &&
73 type != SimulatorType::kQCSim)
90 void Initialize()
override {
91 qubitsMap.resize(nrQubits);
94 for (
size_t q = 0; q < nrQubits; ++q) {
96 auto sim = std::make_unique<IndividualSimulator>(type);
97 sim->AllocateQubits(1);
101 sim->Configure(
"method",
"statevector");
104 sim->SetMultithreading(enableMultithreading);
106 sim->GetQubitsMap()[q] = 0;
107 simulators[q] = std::move(sim);
118 void Reset()
override { Initialize(); }
132 void InitializeState(
size_t num_qubits,
133 std::vector<std::complex<double>> &litudes)
override {
134 throw std::runtime_error(
135 "CompositeSimulator::InitializeState not supported");
172 void InitializeState(
size_t num_qubits,
173 AER::Vector<std::complex<double>> &litudes)
override {
174 throw std::runtime_error(
175 "CompositeSimulator::InitializeState not supported");
191 void InitializeState(
size_t num_qubits,
192 Eigen::VectorXcd &litudes)
override {
193 throw std::runtime_error(
194 "CompositeSimulator::InitializeState not supported");
207 void Configure(
const char *key,
const char *value)
override {
209 if (std::string(
"method") == key)
return;
211 config.SetConfiguration(key, value);
213 if (std::string(
"seed") == key) {
214 const uint64_t seed = std::stoull(value);
215 for (
auto &[
id, simulator] : simulators)
216 simulator->SetSeed(DeriveSeed(seed,
id));
218 for (
auto &[
id, simulator] : simulators) simulator->Configure(key, value);
230 if (simulators.empty())
return "";
232 return config.GetConfiguration(key);
244 if (!simulators.empty())
return 0;
246 const size_t oldNrQubits = nrQubits;
247 nrQubits += num_qubits;
266 void Clear()
override {
278 for (
auto &[
id, simulator] : simulators)
279 simulator->SaveStateToInternalDestructive();
289 for (
auto &[
id, simulator] : simulators)
290 simulator->RestoreInternalDestructiveSavedState();
301 std::complex<double> AmplitudeRaw(
Types::qubit_t outcome)
override {
302 std::complex<double> res = 1.0;
304 for (
auto &[
id, simulator] : simulators)
306 simulator->AmplitudeRaw(simulator->ConvertOutcomeFromGlobal(outcome));
322 if (qubits.size() >
sizeof(
size_t) * 8)
324 <<
"Warning: The number of qubits to measure is larger than the "
325 "number of bits in the size_t type, the outcome will be undefined"
333 const bool outcome =
GetSimulator(qubit)->Measure({qubit}) != 0;
334 if (outcome) res |= mask;
337 Split(qubit, outcome);
341 NotifyObservers(qubits);
353 std::vector<bool> res(qubits.size(),
false);
356 for (
size_t q = 0; q < qubits.size(); ++q) {
358 const bool outcome =
GetSimulator(qubit)->Measure({qubit}) != 0;
359 if (outcome) res[q] =
true;
361 Split(qubit, outcome);
365 NotifyObservers(qubits);
384 NotifyObservers(qubits);
409 std::complex<double> res = 1.0;
411 for (
auto &[
id, simulator] : simulators)
412 res *= simulator->Amplitude(outcome);
430 std::complex<double> ProjectOnZero()
override {
431 std::complex<double> res = 1.0;
433 for (
auto &[
id, simulator] : simulators)
434 res *= simulator->ProjectOnZero();
447 const size_t nrBasisStates = 1ULL << nrQubits;
448 std::vector<double> result;
450 for (
size_t i = 0; i < nrBasisStates; ++i)
467 std::vector<double> result;
469 for (
size_t i = 0; i < qubits.size(); ++i)
491 std::unordered_map<Types::qubit_t, Types::qubit_t>
SampleCounts(
495 <<
"Warning: The number of qubits to measure is larger than the "
496 "number of bits in the Types::qubit_t type, the outcome will be "
500 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
508 for (
size_t shot = 0; shot < shots; ++shot) {
510 for (
auto &[
id, simulator] : simulators)
511 measRaw |= simulator->SampleFromAlias();
515 for (
auto q : qubits) {
516 const size_t qubitMask = 1ULL << q;
517 if ((measRaw & qubitMask) != 0) meas |= mask;
526 for (
size_t shot = 0; shot < shots; ++shot) {
531 for (
auto q : qubits) {
532 const size_t qubitMask = 1ULL << q;
533 if ((measRaw & qubitMask) != 0) meas |= mask;
543 NotifyObservers(qubits);
561 std::unordered_map<std::vector<bool>,
Types::qubit_t> SampleCountsMany(
567 std::vector<bool> meas(qubits.size());
571 for (
size_t shot = 0; shot < shots; ++shot) {
573 for (
auto &[
id, simulator] : simulators)
574 measRaw |= simulator->SampleFromAlias();
576 for (
size_t i = 0; i < qubits.size(); ++i)
577 meas[i] = ((measRaw >> qubits[i]) & 1) == 1;
584 for (
size_t shot = 0; shot < shots; ++shot) {
585 const auto measRaw = MeasureNoCollapseMany();
587 for (
size_t i = 0; i < qubits.size(); ++i) meas[i] = measRaw[qubits[i]];
596 NotifyObservers(qubits);
611 double ExpectationValue(
const std::string &pauliString)
override {
612 std::unordered_map<size_t, std::string> pauliStrings;
614 for (
size_t q = 0; q < pauliString.size(); ++q) {
615 const char op = toupper(pauliString[q]);
616 if (op ==
'I')
continue;
618 const size_t simId = qubitsMap[q];
619 const size_t localQubit = simulators[simId]->GetQubitsMap().at(q);
621 if (pauliStrings[simId].size() <= localQubit)
622 pauliStrings[simId].resize(localQubit + 1,
'I');
624 pauliStrings[simId][localQubit] = op;
628 for (
auto &[
id, localPauliString] : pauliStrings)
629 result *= simulators[id]->ExpectationValue(localPauliString);
641 SimulatorType GetType()
const override {
643 return SimulatorType::kCompositeQCSim;
645 if (type != SimulatorType::kQiskitAer)
646 return SimulatorType::kCompositeQCSim;
648 return SimulatorType::kCompositeQiskitAer;
661 return SimulationType::kStatevector;
671 void Flush()
override {
672 for (
auto &[
id, simulator] : simulators) simulator->Flush();
682 const Eigen::Matrix2cd& gate)
override {
683 GetSimulator(qubit)->ApplyGenericOneQubitGate(qubit, gate);
684 NotifyObservers({qubit});
694 const Eigen::Matrix4cd& gate)
override {
695 JoinIfNeeded(qubit0, qubit1);
696 GetSimulator(qubit0)->ApplyGenericTwoQubitGate(qubit0, qubit1, gate);
697 NotifyObservers({qubit0, qubit1});
711 NotifyObservers({qubit});
722 NotifyObservers({qubit});
733 NotifyObservers({qubit});
744 NotifyObservers({qubit});
755 NotifyObservers({qubit});
766 NotifyObservers({qubit});
777 NotifyObservers({qubit});
788 NotifyObservers({qubit});
799 NotifyObservers({qubit});
810 NotifyObservers({qubit});
821 NotifyObservers({qubit});
832 NotifyObservers({qubit});
844 NotifyObservers({qubit});
856 NotifyObservers({qubit});
868 NotifyObservers({qubit});
882 double gamma)
override {
883 GetSimulator(qubit)->ApplyU(qubit, theta, phi, lambda, gamma);
884 NotifyObservers({qubit});
898 JoinIfNeeded(ctrl_qubit, tgt_qubit);
899 GetSimulator(ctrl_qubit)->ApplyCX(ctrl_qubit, tgt_qubit);
900 NotifyObservers({tgt_qubit, ctrl_qubit});
911 JoinIfNeeded(ctrl_qubit, tgt_qubit);
912 GetSimulator(ctrl_qubit)->ApplyCY(ctrl_qubit, tgt_qubit);
913 NotifyObservers({tgt_qubit, ctrl_qubit});
924 JoinIfNeeded(ctrl_qubit, tgt_qubit);
925 GetSimulator(ctrl_qubit)->ApplyCZ(ctrl_qubit, tgt_qubit);
926 NotifyObservers({tgt_qubit, ctrl_qubit});
938 double lambda)
override {
939 JoinIfNeeded(ctrl_qubit, tgt_qubit);
940 GetSimulator(ctrl_qubit)->ApplyCP(ctrl_qubit, tgt_qubit, lambda);
941 NotifyObservers({tgt_qubit, ctrl_qubit});
953 double theta)
override {
954 JoinIfNeeded(ctrl_qubit, tgt_qubit);
955 GetSimulator(ctrl_qubit)->ApplyCRx(ctrl_qubit, tgt_qubit, theta);
956 NotifyObservers({tgt_qubit, ctrl_qubit});
968 double theta)
override {
969 JoinIfNeeded(ctrl_qubit, tgt_qubit);
970 GetSimulator(ctrl_qubit)->ApplyCRy(ctrl_qubit, tgt_qubit, theta);
971 NotifyObservers({tgt_qubit, ctrl_qubit});
983 double theta)
override {
984 JoinIfNeeded(ctrl_qubit, tgt_qubit);
985 GetSimulator(ctrl_qubit)->ApplyCRz(ctrl_qubit, tgt_qubit, theta);
986 NotifyObservers({tgt_qubit, ctrl_qubit});
997 JoinIfNeeded(ctrl_qubit, tgt_qubit);
998 GetSimulator(ctrl_qubit)->ApplyCH(ctrl_qubit, tgt_qubit);
999 NotifyObservers({tgt_qubit, ctrl_qubit});
1010 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1011 GetSimulator(ctrl_qubit)->ApplyCSx(ctrl_qubit, tgt_qubit);
1012 NotifyObservers({tgt_qubit, ctrl_qubit});
1024 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1025 GetSimulator(ctrl_qubit)->ApplyCSxDAG(ctrl_qubit, tgt_qubit);
1026 NotifyObservers({tgt_qubit, ctrl_qubit});
1037 JoinIfNeeded(qubit0, qubit1);
1039 NotifyObservers({qubit1, qubit0});
1054 JoinIfNeeded(qubit0, qubit1);
1055 JoinIfNeeded(qubit0, qubit2);
1056 GetSimulator(qubit0)->ApplyCCX(qubit0, qubit1, qubit2);
1057 NotifyObservers({qubit2, qubit1, qubit0});
1072 JoinIfNeeded(ctrl_qubit, qubit0);
1073 JoinIfNeeded(ctrl_qubit, qubit1);
1074 GetSimulator(ctrl_qubit)->ApplyCSwap(ctrl_qubit, qubit0, qubit1);
1075 NotifyObservers({qubit1, qubit0, ctrl_qubit});
1090 double theta,
double phi,
double lambda,
double gamma)
override {
1091 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1093 ->ApplyCU(ctrl_qubit, tgt_qubit, theta, phi, lambda, gamma);
1094 NotifyObservers({tgt_qubit, ctrl_qubit});
1097 void ApplyNop()
override {
GetSimulator(0)->ApplyNop(); }
1108 enableMultithreading = multithreading;
1109 for (
auto &[
id, simulator] : simulators)
1110 simulator->SetMultithreading(multithreading);
1132 bool IsQcsim()
const override {
1150 void SaveState()
override { savedState = Clone(); }
1167 const CompositeSimulator *savedStatePtr =
1168 static_cast<CompositeSimulator *
>(savedState.get());
1171 savedStatePtr->type;
1178 savedStatePtr->nrQubits;
1179 nextId = savedStatePtr
1181 enableMultithreading =
1183 ->enableMultithreading;
1187 for (
auto &[
id, simulator] : savedStatePtr->simulators) {
1188 auto isim = simulator->Clone();
1189 simulators[id] = std::unique_ptr<IndividualSimulator>(
1190 static_cast<IndividualSimulator *
>(isim.release()));
1216 <<
"Warning: The number of qubits to measure is larger than the "
1217 "number of bits in the Types::qubit_t type, the outcome will be "
1221 for (
auto &[
id, simulator] : simulators) {
1243 std::vector<bool> MeasureNoCollapseMany()
override {
1244 std::vector<bool> res(nrQubits,
false);
1245 for (
auto &[
id, simulator] : simulators) {
1246 const std::vector<bool> meas = simulator->MeasureNoCollapseMany();
1247 for (
size_t i = 0; i < meas.size(); ++i)
1248 if (meas[i]) res[i] =
true;
1263 std::unique_ptr<ISimulator> Clone()
override {
1264 auto clone = std::make_unique<CompositeSimulator>(type);
1271 clone->nrQubits = nrQubits;
1272 clone->nextId = nextId;
1273 clone->enableMultithreading =
1274 enableMultithreading;
1277 clone->config = config;
1279 for (
auto &[
id, simulator] : simulators) {
1280 auto isim = simulator->Clone();
1281 clone->simulators[id] = std::unique_ptr<IndividualSimulator>(
1282 static_cast<IndividualSimulator *
>(isim.release()));
1285 if (savedState) clone->savedState = savedState->Clone();
1292 const std::unordered_map<std::string, std::string>& GetConfigMap()
1294 return config.GetConfigMap();
1298 void InitializeAlias() {
1299 for (
auto &[
id, simulator] : simulators) simulator->InitializeAlias();
1303 for (
auto &[
id, simulator] : simulators) simulator->ClearAlias();
1314 inline std::unique_ptr<IndividualSimulator> &
GetSimulator(
size_t qubit) {
1315 assert(qubitsMap.size() > qubit);
1316 assert(simulators.find(qubitsMap[qubit]) != simulators.end());
1319 return simulators[qubitsMap[qubit]];
1336 inline bool JoinNeeded(
size_t qubit1,
size_t qubit2) {
1340 return qubitsMap[qubit1] != qubitsMap[qubit2];
1351 inline void JoinIfNeeded(
size_t qubit1,
size_t qubit2) {
1352 if (JoinNeeded(qubit1, qubit2)) {
1353 const size_t simId = qubitsMap[qubit1];
1354 const size_t eraseSimId = qubitsMap[qubit2];
1358 sim1->Join(simId, sim2, qubitsMap, enableMultithreading);
1360 simulators.erase(eraseSimId);
1374 inline void Split(
size_t qubit,
bool qubitOutcome =
false) {
1377 if (sim->GetNumberOfQubits() ==
1381 qubitsMap[qubit] = nextId;
1382 simulators[nextId] = sim->Split(qubit, qubitOutcome, enableMultithreading);
1391 std::unordered_map<size_t, std::unique_ptr<IndividualSimulator>>
1393 size_t nrQubits = 0;
1395 bool enableMultithreading =
1398 std::unique_ptr<ISimulator> savedState;
1400 Configuration config;
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
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
uint_fast64_t qubit_t
The type of a qubit.