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)
210 for (
auto &[
id, simulator] : simulators)
211 simulator->Configure(key, value);
222 if (simulators.empty())
225 return simulators.begin()->second->GetConfiguration(key);
237 if (!simulators.empty())
240 const size_t oldNrQubits = nrQubits;
241 nrQubits += num_qubits;
260 void Clear()
override {
272 for (
auto &[
id, simulator] : simulators)
273 simulator->SaveStateToInternalDestructive();
283 for (
auto &[
id, simulator] : simulators)
284 simulator->RestoreInternalDestructiveSavedState();
295 std::complex<double> AmplitudeRaw(
Types::qubit_t outcome)
override {
296 std::complex<double> res = 1.0;
298 for (
auto &[
id, simulator] : simulators)
300 simulator->AmplitudeRaw(simulator->ConvertOutcomeFromGlobal(outcome));
318 const bool outcome =
GetSimulator(qubit)->Measure({qubit}) != 0;
323 Split(qubit, outcome);
327 NotifyObservers(qubits);
346 NotifyObservers(qubits);
371 std::complex<double> res = 1.0;
373 for (
auto &[
id, simulator] : simulators)
374 res *= simulator->Amplitude(outcome);
387 const size_t nrBasisStates = 1ULL << nrQubits;
388 std::vector<double> result;
390 for (
size_t i = 0; i < nrBasisStates; ++i)
407 std::vector<double> result;
409 for (
size_t i = 0; i < qubits.size(); ++i)
428 std::unordered_map<Types::qubit_t, Types::qubit_t>
430 size_t shots = 1000)
override {
432 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
440 for (
size_t shot = 0; shot < shots; ++shot) {
442 for (
auto &[
id, simulator] : simulators)
443 measRaw |= simulator->SampleFromAlias();
447 for (
auto q : qubits) {
448 const size_t qubitMask = 1ULL << q;
449 if ((measRaw & qubitMask) != 0)
459 for (
size_t shot = 0; shot < shots; ++shot) {
464 for (
auto q : qubits) {
465 const size_t qubitMask = 1ULL << q;
466 if ((measRaw & qubitMask) != 0)
477 NotifyObservers(qubits);
493 double ExpectationValue(
const std::string &pauliString)
override {
494 std::unordered_map<size_t, std::string> pauliStrings;
496 for (
size_t q = 0; q < pauliString.size(); ++q) {
497 const char op = toupper(pauliString[q]);
501 const size_t simId = qubitsMap[q];
502 const size_t localQubit = simulators[simId]->GetQubitsMap().at(q);
504 if (pauliStrings[simId].size() <= localQubit)
505 pauliStrings[simId].resize(localQubit + 1,
'I');
507 pauliStrings[simId][localQubit] = op;
511 for (
auto &[
id, localPauliString] : pauliStrings)
512 result *= simulators[id]->ExpectationValue(localPauliString);
524 SimulatorType GetType()
const override {
526 return SimulatorType::kCompositeQCSim;
528 if (type != SimulatorType::kQiskitAer)
529 return SimulatorType::kCompositeQCSim;
531 return SimulatorType::kCompositeQiskitAer;
544 return SimulationType::kStatevector;
554 void Flush()
override {
555 for (
auto &[
id, simulator] : simulators)
570 NotifyObservers({qubit});
581 NotifyObservers({qubit});
592 NotifyObservers({qubit});
603 NotifyObservers({qubit});
614 NotifyObservers({qubit});
625 NotifyObservers({qubit});
636 NotifyObservers({qubit});
647 NotifyObservers({qubit});
658 NotifyObservers({qubit});
669 NotifyObservers({qubit});
680 NotifyObservers({qubit});
691 NotifyObservers({qubit});
703 NotifyObservers({qubit});
715 NotifyObservers({qubit});
727 NotifyObservers({qubit});
741 double gamma)
override {
742 GetSimulator(qubit)->ApplyU(qubit, theta, phi, lambda, gamma);
743 NotifyObservers({qubit});
757 JoinIfNeeded(ctrl_qubit, tgt_qubit);
758 GetSimulator(ctrl_qubit)->ApplyCX(ctrl_qubit, tgt_qubit);
759 NotifyObservers({tgt_qubit, ctrl_qubit});
770 JoinIfNeeded(ctrl_qubit, tgt_qubit);
771 GetSimulator(ctrl_qubit)->ApplyCY(ctrl_qubit, tgt_qubit);
772 NotifyObservers({tgt_qubit, ctrl_qubit});
783 JoinIfNeeded(ctrl_qubit, tgt_qubit);
784 GetSimulator(ctrl_qubit)->ApplyCZ(ctrl_qubit, tgt_qubit);
785 NotifyObservers({tgt_qubit, ctrl_qubit});
797 double lambda)
override {
798 JoinIfNeeded(ctrl_qubit, tgt_qubit);
799 GetSimulator(ctrl_qubit)->ApplyCP(ctrl_qubit, tgt_qubit, lambda);
800 NotifyObservers({tgt_qubit, ctrl_qubit});
812 double theta)
override {
813 JoinIfNeeded(ctrl_qubit, tgt_qubit);
814 GetSimulator(ctrl_qubit)->ApplyCRx(ctrl_qubit, tgt_qubit, theta);
815 NotifyObservers({tgt_qubit, ctrl_qubit});
827 double theta)
override {
828 JoinIfNeeded(ctrl_qubit, tgt_qubit);
829 GetSimulator(ctrl_qubit)->ApplyCRy(ctrl_qubit, tgt_qubit, theta);
830 NotifyObservers({tgt_qubit, ctrl_qubit});
842 double theta)
override {
843 JoinIfNeeded(ctrl_qubit, tgt_qubit);
844 GetSimulator(ctrl_qubit)->ApplyCRz(ctrl_qubit, tgt_qubit, theta);
845 NotifyObservers({tgt_qubit, ctrl_qubit});
856 JoinIfNeeded(ctrl_qubit, tgt_qubit);
857 GetSimulator(ctrl_qubit)->ApplyCH(ctrl_qubit, tgt_qubit);
858 NotifyObservers({tgt_qubit, ctrl_qubit});
869 JoinIfNeeded(ctrl_qubit, tgt_qubit);
870 GetSimulator(ctrl_qubit)->ApplyCSx(ctrl_qubit, tgt_qubit);
871 NotifyObservers({tgt_qubit, ctrl_qubit});
883 JoinIfNeeded(ctrl_qubit, tgt_qubit);
884 GetSimulator(ctrl_qubit)->ApplyCSxDAG(ctrl_qubit, tgt_qubit);
885 NotifyObservers({tgt_qubit, ctrl_qubit});
896 JoinIfNeeded(qubit0, qubit1);
898 NotifyObservers({qubit1, qubit0});
913 JoinIfNeeded(qubit0, qubit1);
914 JoinIfNeeded(qubit0, qubit2);
916 NotifyObservers({qubit2, qubit1, qubit0});
931 JoinIfNeeded(ctrl_qubit, qubit0);
932 JoinIfNeeded(ctrl_qubit, qubit1);
933 GetSimulator(ctrl_qubit)->ApplyCSwap(ctrl_qubit, qubit0, qubit1);
934 NotifyObservers({qubit1, qubit0, ctrl_qubit});
949 double theta,
double phi,
double lambda,
double gamma)
override {
950 JoinIfNeeded(ctrl_qubit, tgt_qubit);
952 ->ApplyCU(ctrl_qubit, tgt_qubit, theta, phi, lambda, gamma);
953 NotifyObservers({tgt_qubit, ctrl_qubit});
967 enableMultithreading = multithreading;
968 for (
auto &[
id, simulator] : simulators)
969 simulator->SetMultithreading(multithreading);
991 bool IsQcsim()
const override {
1009 void SaveState()
override { savedState = Clone(); }
1026 const CompositeSimulator *savedStatePtr =
1027 static_cast<CompositeSimulator *
>(savedState.get());
1030 savedStatePtr->type;
1037 savedStatePtr->nrQubits;
1038 nextId = savedStatePtr
1040 enableMultithreading =
1042 ->enableMultithreading;
1046 for (
auto &[
id, simulator] : savedStatePtr->simulators) {
1047 auto isim = simulator->Clone();
1048 simulators[id] = std::unique_ptr<IndividualSimulator>(
1049 static_cast<IndividualSimulator *
>(isim.release()));
1070 for (
auto &[
id, simulator] : simulators) {
1088 std::unique_ptr<ISimulator> Clone()
override {
1089 auto clone = std::make_unique<CompositeSimulator>(type);
1096 clone->nrQubits = nrQubits;
1097 clone->nextId = nextId;
1098 clone->enableMultithreading =
1099 enableMultithreading;
1102 for (
auto &[
id, simulator] : simulators) {
1103 auto isim = simulator->Clone();
1104 clone->simulators[id] = std::unique_ptr<IndividualSimulator>(
1105 static_cast<IndividualSimulator *
>(isim.release()));
1109 clone->savedState = savedState->Clone();
1115 void InitializeAlias() {
1116 for (
auto &[
id, simulator] : simulators)
1117 simulator->InitializeAlias();
1121 for (
auto &[
id, simulator] : simulators)
1122 simulator->ClearAlias();
1133 inline std::unique_ptr<IndividualSimulator> &
GetSimulator(
size_t qubit) {
1134 assert(qubitsMap.size() > qubit);
1135 assert(simulators.find(qubitsMap[qubit]) != simulators.end());
1138 return simulators[qubitsMap[qubit]];
1155 inline bool JoinNeeded(
size_t qubit1,
size_t qubit2) {
1159 return qubitsMap[qubit1] != qubitsMap[qubit2];
1170 inline void JoinIfNeeded(
size_t qubit1,
size_t qubit2) {
1171 if (JoinNeeded(qubit1, qubit2)) {
1172 const size_t simId = qubitsMap[qubit1];
1173 const size_t eraseSimId = qubitsMap[qubit2];
1177 sim1->Join(simId, sim2, qubitsMap, enableMultithreading);
1179 simulators.erase(eraseSimId);
1193 inline void Split(
size_t qubit,
bool qubitOutcome =
false) {
1196 if (sim->GetNumberOfQubits() ==
1200 qubitsMap[qubit] = nextId;
1201 simulators[nextId] = sim->Split(qubit, qubitOutcome, enableMultithreading);
1210 std::unordered_map<size_t, std::unique_ptr<IndividualSimulator>>
1212 size_t nrQubits = 0;
1214 bool enableMultithreading =
1217 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
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
uint_fast64_t qubit_t
The type of a qubit.