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));
312 if (qubits.size() >
sizeof(
size_t) * 8)
314 <<
"Warning: The number of qubits to measure is larger than the "
315 "number of bits in the size_t type, the outcome will be undefined"
323 const bool outcome =
GetSimulator(qubit)->Measure({qubit}) != 0;
324 if (outcome) res |= mask;
327 Split(qubit, outcome);
331 NotifyObservers(qubits);
343 std::vector<bool> res(qubits.size(),
false);
346 for (
size_t q = 0; q < qubits.size(); ++q) {
348 const bool outcome =
GetSimulator(qubit)->Measure({qubit}) != 0;
349 if (outcome) res[q] =
true;
351 Split(qubit, outcome);
355 NotifyObservers(qubits);
374 NotifyObservers(qubits);
399 std::complex<double> res = 1.0;
401 for (
auto &[
id, simulator] : simulators)
402 res *= simulator->Amplitude(outcome);
420 std::complex<double> ProjectOnZero()
override {
421 std::complex<double> res = 1.0;
423 for (
auto &[
id, simulator] : simulators)
424 res *= simulator->ProjectOnZero();
437 const size_t nrBasisStates = 1ULL << nrQubits;
438 std::vector<double> result;
440 for (
size_t i = 0; i < nrBasisStates; ++i)
457 std::vector<double> result;
459 for (
size_t i = 0; i < qubits.size(); ++i)
481 std::unordered_map<Types::qubit_t, Types::qubit_t>
SampleCounts(
485 <<
"Warning: The number of qubits to measure is larger than the "
486 "number of bits in the Types::qubit_t type, the outcome will be "
490 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
498 for (
size_t shot = 0; shot < shots; ++shot) {
500 for (
auto &[
id, simulator] : simulators)
501 measRaw |= simulator->SampleFromAlias();
505 for (
auto q : qubits) {
506 const size_t qubitMask = 1ULL << q;
507 if ((measRaw & qubitMask) != 0) meas |= mask;
516 for (
size_t shot = 0; shot < shots; ++shot) {
521 for (
auto q : qubits) {
522 const size_t qubitMask = 1ULL << q;
523 if ((measRaw & qubitMask) != 0) meas |= mask;
533 NotifyObservers(qubits);
551 std::unordered_map<std::vector<bool>,
Types::qubit_t> SampleCountsMany(
557 std::vector<bool> meas(qubits.size());
561 for (
size_t shot = 0; shot < shots; ++shot) {
563 for (
auto &[
id, simulator] : simulators)
564 measRaw |= simulator->SampleFromAlias();
566 for (
size_t i = 0; i < qubits.size(); ++i)
567 meas[i] = ((measRaw >> qubits[i]) & 1) == 1;
574 for (
size_t shot = 0; shot < shots; ++shot) {
575 const auto measRaw = MeasureNoCollapseMany();
577 for (
size_t i = 0; i < qubits.size(); ++i) meas[i] = measRaw[qubits[i]];
586 NotifyObservers(qubits);
601 double ExpectationValue(
const std::string &pauliString)
override {
602 std::unordered_map<size_t, std::string> pauliStrings;
604 for (
size_t q = 0; q < pauliString.size(); ++q) {
605 const char op = toupper(pauliString[q]);
606 if (op ==
'I')
continue;
608 const size_t simId = qubitsMap[q];
609 const size_t localQubit = simulators[simId]->GetQubitsMap().at(q);
611 if (pauliStrings[simId].size() <= localQubit)
612 pauliStrings[simId].resize(localQubit + 1,
'I');
614 pauliStrings[simId][localQubit] = op;
618 for (
auto &[
id, localPauliString] : pauliStrings)
619 result *= simulators[
id]->ExpectationValue(localPauliString);
631 SimulatorType GetType()
const override {
633 return SimulatorType::kCompositeQCSim;
635 if (type != SimulatorType::kQiskitAer)
636 return SimulatorType::kCompositeQCSim;
638 return SimulatorType::kCompositeQiskitAer;
651 return SimulationType::kStatevector;
661 void Flush()
override {
662 for (
auto &[
id, simulator] : simulators) simulator->Flush();
676 NotifyObservers({qubit});
687 NotifyObservers({qubit});
698 NotifyObservers({qubit});
709 NotifyObservers({qubit});
720 NotifyObservers({qubit});
731 NotifyObservers({qubit});
742 NotifyObservers({qubit});
753 NotifyObservers({qubit});
764 NotifyObservers({qubit});
775 NotifyObservers({qubit});
786 NotifyObservers({qubit});
797 NotifyObservers({qubit});
809 NotifyObservers({qubit});
821 NotifyObservers({qubit});
833 NotifyObservers({qubit});
847 double gamma)
override {
848 GetSimulator(qubit)->ApplyU(qubit, theta, phi, lambda, gamma);
849 NotifyObservers({qubit});
863 JoinIfNeeded(ctrl_qubit, tgt_qubit);
864 GetSimulator(ctrl_qubit)->ApplyCX(ctrl_qubit, tgt_qubit);
865 NotifyObservers({tgt_qubit, ctrl_qubit});
876 JoinIfNeeded(ctrl_qubit, tgt_qubit);
877 GetSimulator(ctrl_qubit)->ApplyCY(ctrl_qubit, tgt_qubit);
878 NotifyObservers({tgt_qubit, ctrl_qubit});
889 JoinIfNeeded(ctrl_qubit, tgt_qubit);
890 GetSimulator(ctrl_qubit)->ApplyCZ(ctrl_qubit, tgt_qubit);
891 NotifyObservers({tgt_qubit, ctrl_qubit});
903 double lambda)
override {
904 JoinIfNeeded(ctrl_qubit, tgt_qubit);
905 GetSimulator(ctrl_qubit)->ApplyCP(ctrl_qubit, tgt_qubit, lambda);
906 NotifyObservers({tgt_qubit, ctrl_qubit});
918 double theta)
override {
919 JoinIfNeeded(ctrl_qubit, tgt_qubit);
920 GetSimulator(ctrl_qubit)->ApplyCRx(ctrl_qubit, tgt_qubit, theta);
921 NotifyObservers({tgt_qubit, ctrl_qubit});
933 double theta)
override {
934 JoinIfNeeded(ctrl_qubit, tgt_qubit);
935 GetSimulator(ctrl_qubit)->ApplyCRy(ctrl_qubit, tgt_qubit, theta);
936 NotifyObservers({tgt_qubit, ctrl_qubit});
948 double theta)
override {
949 JoinIfNeeded(ctrl_qubit, tgt_qubit);
950 GetSimulator(ctrl_qubit)->ApplyCRz(ctrl_qubit, tgt_qubit, theta);
951 NotifyObservers({tgt_qubit, ctrl_qubit});
962 JoinIfNeeded(ctrl_qubit, tgt_qubit);
963 GetSimulator(ctrl_qubit)->ApplyCH(ctrl_qubit, tgt_qubit);
964 NotifyObservers({tgt_qubit, ctrl_qubit});
975 JoinIfNeeded(ctrl_qubit, tgt_qubit);
976 GetSimulator(ctrl_qubit)->ApplyCSx(ctrl_qubit, tgt_qubit);
977 NotifyObservers({tgt_qubit, ctrl_qubit});
989 JoinIfNeeded(ctrl_qubit, tgt_qubit);
990 GetSimulator(ctrl_qubit)->ApplyCSxDAG(ctrl_qubit, tgt_qubit);
991 NotifyObservers({tgt_qubit, ctrl_qubit});
1002 JoinIfNeeded(qubit0, qubit1);
1004 NotifyObservers({qubit1, qubit0});
1019 JoinIfNeeded(qubit0, qubit1);
1020 JoinIfNeeded(qubit0, qubit2);
1021 GetSimulator(qubit0)->ApplyCCX(qubit0, qubit1, qubit2);
1022 NotifyObservers({qubit2, qubit1, qubit0});
1037 JoinIfNeeded(ctrl_qubit, qubit0);
1038 JoinIfNeeded(ctrl_qubit, qubit1);
1039 GetSimulator(ctrl_qubit)->ApplyCSwap(ctrl_qubit, qubit0, qubit1);
1040 NotifyObservers({qubit1, qubit0, ctrl_qubit});
1055 double theta,
double phi,
double lambda,
double gamma)
override {
1056 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1058 ->ApplyCU(ctrl_qubit, tgt_qubit, theta, phi, lambda, gamma);
1059 NotifyObservers({tgt_qubit, ctrl_qubit});
1062 void ApplyNop()
override {
GetSimulator(0)->ApplyNop(); }
1073 enableMultithreading = multithreading;
1074 for (
auto &[
id, simulator] : simulators)
1075 simulator->SetMultithreading(multithreading);
1097 bool IsQcsim()
const override {
1115 void SaveState()
override { savedState = Clone(); }
1132 const CompositeSimulator *savedStatePtr =
1133 static_cast<CompositeSimulator *
>(savedState.get());
1136 savedStatePtr->type;
1143 savedStatePtr->nrQubits;
1144 nextId = savedStatePtr
1146 enableMultithreading =
1148 ->enableMultithreading;
1152 for (
auto &[
id, simulator] : savedStatePtr->simulators) {
1153 auto isim = simulator->Clone();
1154 simulators[id] = std::unique_ptr<IndividualSimulator>(
1155 static_cast<IndividualSimulator *
>(isim.release()));
1181 <<
"Warning: The number of qubits to measure is larger than the "
1182 "number of bits in the Types::qubit_t type, the outcome will be "
1186 for (
auto &[
id, simulator] : simulators) {
1208 std::vector<bool> MeasureNoCollapseMany()
override {
1209 std::vector<bool> res(nrQubits,
false);
1210 for (
auto &[
id, simulator] : simulators) {
1211 const std::vector<bool> meas = simulator->MeasureNoCollapseMany();
1212 for (
size_t i = 0; i < meas.size(); ++i)
1213 if (meas[i]) res[i] =
true;
1228 std::unique_ptr<ISimulator> Clone()
override {
1229 auto clone = std::make_unique<CompositeSimulator>(type);
1236 clone->nrQubits = nrQubits;
1237 clone->nextId = nextId;
1238 clone->enableMultithreading =
1239 enableMultithreading;
1242 for (
auto &[
id, simulator] : simulators) {
1243 auto isim = simulator->Clone();
1244 clone->simulators[id] = std::unique_ptr<IndividualSimulator>(
1245 static_cast<IndividualSimulator *
>(isim.release()));
1248 if (savedState) clone->savedState = savedState->Clone();
1254 void InitializeAlias() {
1255 for (
auto &[
id, simulator] : simulators) simulator->InitializeAlias();
1259 for (
auto &[
id, simulator] : simulators) simulator->ClearAlias();
1270 inline std::unique_ptr<IndividualSimulator> &
GetSimulator(
size_t qubit) {
1271 assert(qubitsMap.size() > qubit);
1272 assert(simulators.find(qubitsMap[qubit]) != simulators.end());
1275 return simulators[qubitsMap[qubit]];
1292 inline bool JoinNeeded(
size_t qubit1,
size_t qubit2) {
1296 return qubitsMap[qubit1] != qubitsMap[qubit2];
1307 inline void JoinIfNeeded(
size_t qubit1,
size_t qubit2) {
1308 if (JoinNeeded(qubit1, qubit2)) {
1309 const size_t simId = qubitsMap[qubit1];
1310 const size_t eraseSimId = qubitsMap[qubit2];
1314 sim1->Join(simId, sim2, qubitsMap, enableMultithreading);
1316 simulators.erase(eraseSimId);
1330 inline void Split(
size_t qubit,
bool qubitOutcome =
false) {
1333 if (sim->GetNumberOfQubits() ==
1337 qubitsMap[qubit] = nextId;
1338 simulators[nextId] = sim->Split(qubit, qubitOutcome, enableMultithreading);
1347 std::unordered_map<size_t, std::unique_ptr<IndividualSimulator>>
1349 size_t nrQubits = 0;
1351 bool enableMultithreading =
1354 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
uint_fast64_t qubit_t
The type of a qubit.
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.