Maestro 0.1.0
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
SimpleDisconnectedNetwork.h
Go to the documentation of this file.
1
12
13#pragma once
14
15#ifndef _SIMPLE_NETWORK_H_
16#define _SIMPLE_NETWORK_H_
17
18#include "QubitRegister.h"
19#include "SimpleController.h"
20#include "SimpleHost.h"
21
23#include "NetworkJob.h"
24
25namespace Network {
26
40template <typename Time = Types::time_type,
41 class Controller = SimpleController<Time>>
42class SimpleDisconnectedNetwork : public INetwork<Time> {
43public:
47
57 SimpleDisconnectedNetwork(const std::vector<Types::qubit_t> &qubits = {},
58 const std::vector<size_t> &cbits = {}) {
59 if (!qubits.empty())
60 CreateNetwork(qubits, cbits);
61 }
62
72 void CreateNetwork(const std::vector<Types::qubit_t> &qubits,
73 const std::vector<size_t> &cbits) {
74 size_t qubitsOffset = 0;
75 size_t cbitsOffset = 0;
76
77 for (size_t i = 0; i < qubits.size(); ++i) {
78 const size_t numQubits = qubits[i];
79 const size_t numBits = (i < cbits.size() ? cbits[i] : 0);
80 hosts.emplace_back(std::make_shared<SimpleHost<Time>>(
81 i, qubitsOffset, numQubits, cbitsOffset, numBits));
82 qubitsOffset += numQubits;
83 cbitsOffset += numBits;
84 }
85
86 for (size_t i = 0; i < hosts.size(); ++i) {
87 std::static_pointer_cast<SimpleHost<Time>>(hosts[i])->SetEntangledQubitId(
88 qubitsOffset);
89 std::static_pointer_cast<SimpleHost<Time>>(hosts[i])
90 ->SetEntangledQubitMeasurementBit(cbitsOffset);
91 ++qubitsOffset;
92 ++cbitsOffset;
93 }
94
95 controller = std::make_shared<Controller>();
96 }
97
108 void
109 Execute(const std::shared_ptr<Circuits::Circuit<Time>> &circuit) override {
110 const auto recreate = recreateIfNeeded;
111
114 size_t numQubits = 2;
115 if (simulator) {
116 simType = simulator->GetType();
117 method = simulator->GetSimulationType();
118 numQubits = simulator->GetNumberOfQubits();
119 }
120
121 recreateIfNeeded = false;
122
123 const auto res = RepeatedExecute(circuit, 1);
124
125 recreateIfNeeded = recreate;
126
127 // put the results in the state
128 if (!res.empty()) {
129 const auto &first = *res.begin();
130 GetState().SetResultsInOrder(first.first);
131 }
132
133 if (recreate &&
134 (!simulator ||
135 (simulator && (simType != simulator->GetType() ||
136 method != simulator->GetSimulationType() ||
137 simulator->GetNumberOfQubits() != numQubits))))
138 CreateSimulator(simType, method);
139 }
140
153 void ExecuteOnHost(const std::shared_ptr<Circuits::Circuit<Time>> &circuit,
154 size_t hostId) override {
155 const auto recreate = recreateIfNeeded;
156
159 size_t numQubits = 2;
160 if (simulator) {
161 simType = simulator->GetType();
162 method = simulator->GetSimulationType();
163 numQubits = simulator->GetNumberOfQubits();
164 }
165
166 recreateIfNeeded = false;
167
168 const auto res = RepeatedExecuteOnHost(circuit, hostId, 1);
169
170 recreateIfNeeded = recreate;
171
172 // put the results in the state
173 if (!res.empty()) {
174 const auto &first = *res.begin();
175 GetState().SetResultsInOrder(first.first);
176 }
177
178 if (recreate &&
179 (!simulator ||
180 (simulator && (simType != simulator->GetType() ||
181 method != simulator->GetSimulationType() ||
182 simulator->GetNumberOfQubits() != numQubits))))
183 CreateSimulator(simType, method);
184 }
185
201 std::vector<double>
202 ExecuteExpectations(const std::shared_ptr<Circuits::Circuit<Time>> &circuit,
203 const std::vector<std::string> &paulis) override {
204 const auto recreate = recreateIfNeeded;
205
208 size_t numQubits = 2;
209 if (simulator) {
210 simType = simulator->GetType();
211 method = simulator->GetSimulationType();
212 numQubits = simulator->GetNumberOfQubits();
213 }
214
215 recreateIfNeeded = false;
216
217 pauliStrings = &paulis;
218 const auto res = RepeatedExecute(circuit, 1);
219 pauliStrings = nullptr;
220
221 recreateIfNeeded = recreate;
222
223 // put the results in the state
224 if (!res.empty()) {
225 const auto &first = *res.begin();
226 GetState().SetResultsInOrder(first.first);
227 }
228
229 std::vector<double> expectations(paulis.size());
230 if (simulator) {
231 // translate the pauli strings to the mapped order of qubits
232 const size_t numOps = simulator->GetNumberOfQubits();
233
234 auto optimiser = controller->GetOptimiser();
235 if (optimiser) {
236 // convert the classical state results back to the expected order
237 const auto &qubitsMap = optimiser->GetQubitsMap();
238
239 for (size_t i = 0; i < paulis.size(); ++i) {
240 std::string translated(numOps, 'I');
241
242 for (size_t j = 0; j < paulis[i].size(); ++j) {
243 const auto pos = qubitsMap.find(j);
244 if (pos != qubitsMap.end())
245 translated[pos->second] = paulis[i][j];
246 else
247 translated[j] = paulis[i][j];
248 }
249
250 expectations[i] = simulator->ExpectationValue(translated);
251 }
252 } else {
253 for (size_t i = 0; i < paulis.size(); ++i)
254 expectations[i] = simulator->ExpectationValue(paulis[i]);
255 }
256 }
257
258 if (recreate && (!simulator || simType != simulator->GetType() ||
259 method != simulator->GetSimulationType() ||
260 simulator->GetNumberOfQubits() != numQubits))
261 CreateSimulator(simType, method);
262
263 return expectations;
264 }
265
281 std::vector<double> ExecuteOnHostExpectations(
282 const std::shared_ptr<Circuits::Circuit<Time>> &circuit, size_t hostId,
283 const std::vector<std::string> &paulis) {
284 const auto recreate = recreateIfNeeded;
285
288 size_t numQubits = 2;
289 if (simulator) {
290 simType = simulator->GetType();
291 method = simulator->GetSimulationType();
292 numQubits = simulator->GetNumberOfQubits();
293 }
294
295 recreateIfNeeded = false;
296 pauliStrings = &paulis;
297 const auto res = RepeatedExecuteOnHost(circuit, hostId, 1);
298 pauliStrings = nullptr;
299
300 recreateIfNeeded = recreate;
301
302 // put the results in the state
303 if (!res.empty()) {
304 const auto &first = *res.begin();
305 GetState().SetResultsInOrder(first.first);
306 }
307
308 // for (const auto& m : qubitsMapOnHost)
309 // std::cout << "Mapping qubit " << m.first << " to " << m.second <<
310 // std::endl;
311
312 const size_t offsetBase = qubitsMapOnHost.size();
313
314 std::vector<double> expectations(paulis.size(), 1.);
315 if (simulator) {
316 // translate the pauli strings to the mapped order of qubits
317 const size_t numOps = simulator->GetNumberOfQubits();
318
319 // convert the pauli strings to the actual qubits order
320 for (size_t i = 0; i < paulis.size(); ++i) {
321 std::string translated(std::max(numOps, paulis[i].size()), 'I');
322
323 size_t offset = offsetBase;
324
325 for (size_t j = 0; j < paulis[i].size(); ++j) {
326 auto pos = qubitsMapOnHost.find(j);
327 if (pos != qubitsMapOnHost.end())
328 translated[pos->second] = paulis[i][j];
329 else {
330 translated[offset] = paulis[i][j];
331 ++offset;
332 }
333 }
334
335 // std::cout << "Translated pauli string: " << translated << std::endl;
336
337 expectations[i] = simulator->ExpectationValue(translated);
338 }
339 }
340
341 if (recreate && (!simulator || simType != simulator->GetType() ||
342 method != simulator->GetSimulationType() ||
343 simulator->GetNumberOfQubits() != numQubits))
344 CreateSimulator(simType, method);
345
346 return expectations;
347 }
348
363 RepeatedExecute(const std::shared_ptr<Circuits::Circuit<Time>> &circuit,
364 size_t shots = 1000) override {
365 if (!controller || !circuit)
366 return {};
367
368 distCirc = controller->DistributeCircuit(BaseClass::getptr(), circuit);
369
370#ifdef _DEBUG
371 for (auto q : distCirc->AffectedQubits()) {
372 if (q >= GetNumQubits()) {
373 std::cout
374 << "This is a distributed circuit, using entanglement or cutting"
375 << std::endl;
376 break;
377 }
378 }
379#endif
380
381 if (!simulator || distCirc->empty())
382 return {};
383
384 auto simType = simulator->GetType();
385 if (distCirc->HasOpsAfterMeasurements() &&
386 (
387#ifndef NO_QISKIT_AER
389#endif
391 distCirc->MoveMeasurementsAndResets();
392
393 auto method = simulator->GetSimulationType();
394
395 const auto saveSimType = simType;
396 const auto saveMethod = method;
397
398 if (GetOptimizeSimulator() && distCirc->IsClifford() &&
400 // this is for the gpu simulator, as it doesn't support stabilizer
401#ifdef __linux__
402 && simType != Simulators::SimulatorType::kGpuSim
403#endif
404 ) {
406
409#ifndef NO_QISKIT_AER
412#endif
413 }
414
415 ExecuteResults res;
416 const size_t nrQubits = GetNumQubits() + GetNumNetworkEntangledQubits();
417 const size_t nrCbitsResults = GetNumClassicalBits();
418
419 maxBondDim =
420 simulator->GetConfiguration("matrix_product_state_max_bond_dimension");
421 singularValueThreshold = simulator->GetConfiguration(
422 "matrix_product_state_truncation_threshold");
423 mpsSample = simulator->GetConfiguration("mps_sample_measure_algorithm");
424
425 // do that only if the optimization for simulator is on and the estimator is
426 // available, ortherwise an 'optimal' simulator won't be created
428 simulator->Clear();
429 GetState().Clear();
430 }
431
432 std::vector<bool> executed;
433 auto optSim =
434 ChooseBestSimulator(distCirc, shots, nrQubits, nrQubits, nrCbitsResults,
435 simType, method, executed);
436
437 lastSimulatorType = simType;
438 lastMethod = method;
439
440 size_t nrThreads = GetMaxSimulators();
441
442#ifdef __linux__
443 if (simType == Simulators::SimulatorType::kGpuSim)
444 nrThreads = 1;
445#endif
447 !distCirc->HasOpsAfterMeasurements())
448 nrThreads = 1;
449
450 nrThreads = std::min(nrThreads, std::max<size_t>(shots, 1ULL));
451
452 std::mutex resultsMutex;
453
454 const auto dcirc = distCirc;
455
456 if (nrThreads > 1) {
457 // since it's going to execute on multiple threads, free the memory from
458 // the network's simulator and state, it's going to use other ones,
459 // created in the threads if optimization already exists, it will be
460 // cloned in the threads, otherwise a new one will be created in the
461 // threads
462 if (!optimizeSimulator ||
463 !simulatorsEstimator) // otherwise it was already cleared
464 {
465 simulator->Clear();
466 GetState().Clear();
467 }
468
469 const size_t cntPerThread = std::max<size_t>(shots / nrThreads, 1ULL);
470
471 threadsPool.Resize(nrThreads);
472 threadsPool.SetFinishLimit(shots);
473
474 while (shots > 0) {
475 const size_t curCnt = std::min(cntPerThread, shots);
476
477 shots -= curCnt;
478
479 auto job = std::make_shared<ExecuteJob<Time>>(
480 dcirc, res, curCnt, nrQubits, nrQubits, nrCbitsResults, simType,
481 method, resultsMutex);
482 job->optimiseMultipleShotsExecution = GetOptimizeSimulator();
483
484 job->maxBondDim = maxBondDim;
485 job->mpsSample = mpsSample;
486 job->singularValueThreshold = singularValueThreshold;
487
488 if (optSim) {
489 job->optSim = optSim->Clone();
490 job->executedGates = executed;
491 }
492
493 threadsPool.AddRunJob(std::move(job));
494 }
495
496 threadsPool.WaitForFinish();
497 threadsPool.Stop();
498 } else {
499 const size_t curCnt = shots;
500
501 auto job = std::make_shared<ExecuteJob<Time>>(
502 dcirc, res, curCnt, nrQubits, nrQubits, nrCbitsResults, simType,
503 method, resultsMutex);
504 job->optimiseMultipleShotsExecution = GetOptimizeSimulator();
505
506 job->maxBondDim = maxBondDim;
507 job->mpsSample = mpsSample;
508 job->singularValueThreshold = singularValueThreshold;
509
510 if (optSim) {
511 optSim->SetMultithreading(true);
512 job->optSim = optSim;
513 job->executedGates = executed;
514 } else {
515 if (simulator && method == saveMethod && simType == saveSimType) {
516 optSim = simulator;
517 job->optSim = optSim;
518 simulator = nullptr;
519 }
520 }
521
522 job->DoWorkNoLock();
523 if (!recreateIfNeeded)
524 simulator = job->optSim;
525 }
526
527 if (recreateIfNeeded)
528 CreateSimulator(saveSimType, saveMethod);
529
531
532 return res;
533 }
534
551 RepeatedExecuteOnHost(const std::shared_ptr<Circuits::Circuit<Time>> &circuit,
552 size_t hostId, size_t shots = 1000) override {
553 if (!circuit || hostId >= GetNumHosts())
554 return {};
555
556 size_t nrQubits = 0;
557 size_t nrCbits = 0;
558
559 std::shared_ptr<Circuits::Circuit<Time>> optCircuit;
560 if (GetController()->GetOptimizeCircuit()) {
561 optCircuit =
562 std::static_pointer_cast<Circuits::Circuit<Time>>(circuit->Clone());
563 optCircuit->Optimize();
564 }
565 const auto reverseQubitsMap = MapCircuitOnHost(
566 GetController()->GetOptimizeCircuit() ? optCircuit : circuit, hostId,
567 nrQubits, nrCbits, true);
568 if (nrCbits == 0)
569 nrCbits = nrQubits;
570
571 if (!simulator || distCirc->empty())
572 return {};
573
574 auto simType = simulator->GetType();
575
576 maxBondDim =
577 simulator->GetConfiguration("matrix_product_state_max_bond_dimension");
578 singularValueThreshold = simulator->GetConfiguration(
579 "matrix_product_state_truncation_threshold");
580 mpsSample = simulator->GetConfiguration("mps_sample_measure_algorithm");
581
582 if (distCirc->HasOpsAfterMeasurements() &&
583 (
584#ifndef NO_QISKIT_AER
586#endif
588 distCirc->MoveMeasurementsAndResets();
589
590 auto method = simulator->GetSimulationType();
591 const auto saveSimType = simType;
592 const auto saveMethod = method;
593
594 if (GetOptimizeSimulator() && distCirc->IsClifford() &&
596 // this is for the gpu simulator, as it doesn't support stabilizer
597#ifdef __linux__
598 && simType != Simulators::SimulatorType::kGpuSim
599#endif
600 ) {
602
605#ifndef NO_QISKIT_AER
608#endif
609 }
610
611 ExecuteResults res;
612
613 // since it's going to execute on multiple threads, free the memory from the
614 // network's simulator and state, it's going to use other ones, created in
615 // the threads
616 simulator->Clear();
617 GetState().Clear();
618
619 std::vector<bool> executed;
620 auto optSim = ChooseBestSimulator(distCirc, shots, nrQubits, nrCbits,
621 nrCbits, simType, method, executed);
622
623 lastSimulatorType = simType;
624 lastMethod = method;
625
626 size_t nrThreads = GetMaxSimulators();
627
628#ifdef __linux__
629 if (simType == Simulators::SimulatorType::kGpuSim)
630 nrThreads = 1;
631 else
632#endif
634 !distCirc->HasOpsAfterMeasurements())
635 nrThreads = 1;
636
637 nrThreads = std::min(nrThreads, std::max<size_t>(shots, 1ULL));
638
639 // WARNING: be sure to not put this above ChooseBestSimulator, as that one
640 // can change the shots value!
641
642 std::mutex resultsMutex;
643
644 const auto dcirc = distCirc;
645
646 if (nrThreads > 1) {
647 // this rounds up, rounding down is better
648 // const size_t cntPerThread = static_cast<size_t>((shots - 1) / nrThreads
649 // + 1);
650 const size_t cntPerThread = std::max<size_t>(shots / nrThreads, 1ULL);
651
652 threadsPool.Resize(nrThreads);
653 threadsPool.SetFinishLimit(shots);
654
655 while (shots > 0) {
656 const size_t curCnt = std::min(cntPerThread, shots);
657 shots -= curCnt;
658
659 auto job = std::make_shared<ExecuteJob<Time>>(
660 dcirc, res, curCnt, nrQubits, nrCbits, nrCbits, simType, method,
661 resultsMutex);
662 job->optimiseMultipleShotsExecution = GetOptimizeSimulator();
663
664 job->maxBondDim = maxBondDim;
665 job->mpsSample = mpsSample;
666 job->singularValueThreshold = singularValueThreshold;
667
668 if (optSim) {
669 job->optSim = optSim->Clone();
670 job->executedGates = executed;
671 }
672
673 threadsPool.AddRunJob(std::move(job));
674 }
675
676 threadsPool.WaitForFinish();
677 threadsPool.Stop();
678 } else {
679 const size_t curCnt = shots;
680
681 auto job = std::make_shared<ExecuteJob<Time>>(
682 dcirc, res, curCnt, nrQubits, nrCbits, nrCbits, simType, method,
683 resultsMutex);
684 job->optimiseMultipleShotsExecution = GetOptimizeSimulator();
685
686 job->maxBondDim = maxBondDim;
687 job->mpsSample = mpsSample;
688 job->singularValueThreshold = singularValueThreshold;
689
690 if (optSim) {
691 optSim->SetMultithreading(true);
692 job->optSim = optSim;
693 job->executedGates = executed;
694 }
695
696 job->DoWorkNoLock();
697 if (!recreateIfNeeded)
698 simulator = job->optSim;
699 }
700
701 if (recreateIfNeeded)
702 CreateSimulator(saveSimType, saveMethod);
703
704 if (!reverseQubitsMap.empty())
705 ConvertBackResults(res, reverseQubitsMap);
706
707 return res;
708 }
709
719 const std::shared_ptr<Circuits::Circuit<Time>> &circuit) const override {
720 if (!circuit)
721 return 0;
722
723 size_t distgates = 0;
724
725 for (const auto &op : circuit->GetOperations())
726 if (!IsLocalOperation(op))
727 ++distgates;
728
729 return distgates;
730 }
731
748 std::vector<ExecuteResults> ExecuteScheduled(
749 const std::vector<Schedulers::ExecuteCircuit<Time>> &circuits) override {
750 // create a default one if not set
751 if (!GetScheduler()) {
753
754 if (!GetScheduler())
755 return {};
756 }
757
758 return GetScheduler()->ExecuteScheduled(circuits);
759 }
760
782 Simulators::SimulationType simExecType =
784 size_t nrQubits = 0) override {
785 classicalState.Clear();
786 classicalState.AllocateBits(GetNumClassicalBits() +
788
789 simulator =
791
792 if (simulator) {
793 if (!maxBondDim.empty())
794 simulator->Configure("matrix_product_state_max_bond_dimension",
795 maxBondDim.c_str());
796 if (!singularValueThreshold.empty())
797 simulator->Configure("matrix_product_state_truncation_threshold",
798 singularValueThreshold.c_str());
799 if (!mpsSample.empty())
800 simulator->Configure("mps_sample_measure_algorithm", mpsSample.c_str());
801
802 simulator->AllocateQubits(
803 nrQubits == 0 ? GetNumQubits() + GetNumNetworkEntangledQubits()
804 : nrQubits);
805 simulator->Initialize();
806 }
807 }
808
818 void Configure(const char *key, const char *value) override {
819 if (!key || !value)
820 return;
821
822 if (std::string("matrix_product_state_max_bond_dimension") == key)
823 maxBondDim = value;
824 else if (std::string("matrix_product_state_truncation_threshold") == key)
826 else if (std::string("mps_sample_measure_algorithm") == key)
827 mpsSample = value;
828 else if (std::string("max_simulators") == key)
829 maxSimulators = std::stoull(value);
830
831 if (simulator)
832 simulator->Configure(key, value);
833 }
834
843 std::shared_ptr<Simulators::ISimulator> GetSimulator() const override {
844 return simulator;
845 }
846
856
868 void
871 if (!controller)
872 return;
873
874 controller->CreateScheduler(BaseClass::getptr(), schType);
875 }
876
885 std::shared_ptr<Schedulers::IScheduler<Time>> GetScheduler() const override {
886 if (!controller)
887 return nullptr;
888
889 return controller->GetScheduler();
890 }
891
901 const std::shared_ptr<IHost<Time>> GetHost(size_t hostId) const override {
902 if (hostId >= hosts.size())
903 return nullptr;
904
905 return hosts[hostId];
906 }
907
916 const std::shared_ptr<IController<Time>> GetController() const override {
917 return controller;
918 }
919
927 size_t GetNumHosts() const override { return hosts.size(); }
928
937 size_t GetNumQubits() const override {
938 size_t res = 0;
939
940 for (const auto &host : hosts)
941 res += host->GetNumQubits();
942
943 return res;
944 }
945
955 size_t GetNumQubitsForHost(size_t hostId) const override {
956 if (hostId >= hosts.size())
957 return 0;
958
959 return hosts[hostId]->GetNumQubits();
960 }
961
970 size_t GetNumNetworkEntangledQubits() const override {
971 size_t res = 0;
972
973 for (const auto &host : hosts)
974 res += host->GetNumNetworkEntangledQubits();
975
976 return res;
977 }
978
991 size_t GetNumNetworkEntangledQubitsForHost(size_t hostId) const override {
992 if (hostId >= hosts.size())
993 return 0;
994
995 return hosts[hostId]->GetNumNetworkEntangledQubits();
996 }
997
1006 size_t GetNumClassicalBits() const override {
1007 size_t res = 0;
1008
1009 for (const auto &host : hosts)
1010 res += host->GetNumClassicalBits();
1011
1012 return res;
1013 }
1014
1026 size_t GetNumClassicalBitsForHost(size_t hostId) const override {
1027 if (hostId >= hosts.size())
1028 return 0;
1029
1030 return hosts[hostId]->GetNumClassicalBits();
1031 }
1032
1042 std::vector<std::shared_ptr<IHost<Time>>> &GetHosts() { return hosts; }
1043
1051 void SetController(const std::shared_ptr<IController<Time>> &cntrl) {
1052 controller = cntrl;
1053 }
1054
1068 bool SendPacket(size_t fromHostId, size_t toHostId,
1069 const std::vector<uint8_t> &packet) override {
1070 return false;
1071 }
1072
1080 NetworkType GetType() const override {
1082 }
1083
1095 const std::shared_ptr<Circuits::IOperation<Time>> &op) const override {
1096 const auto qubits = op->AffectedQubits();
1097
1098 if (qubits.empty())
1099 return true;
1100
1101 size_t firstQubit = qubits[0];
1102
1103 for (size_t q = 1; q < qubits.size(); ++q)
1104 if (!AreQubitsOnSameHost(firstQubit, qubits[q]))
1105 return false;
1106
1107 return true;
1108 }
1109
1123 const std::shared_ptr<Circuits::IOperation<Time>> &op) const override {
1124 const auto qubits = op->AffectedQubits();
1125
1126 if (qubits.empty())
1127 return false;
1128
1129 // grab the first qubit that is on a host (skip over network entangled
1130 // qubits)
1131 size_t firstQubit = qubits[0];
1132 size_t q = 1;
1133 for (; IsNetworkEntangledQubit(firstQubit) && q < qubits.size(); ++q)
1134 firstQubit = qubits[q];
1135
1136 // check to see one of the other qubits is on a different host, but ignore
1137 // the network entangled qubits
1138 for (; q < qubits.size(); ++q)
1139 if (!IsNetworkEntangledQubit(qubits[q]) &&
1140 !AreQubitsOnSameHost(firstQubit, qubits[q]))
1141 return true;
1142
1143 return false;
1144 }
1145
1158 const std::shared_ptr<Circuits::IOperation<Time>> &op) const override {
1159 const auto qubits = op->AffectedQubits();
1160
1161 if (qubits.empty())
1162 return false;
1163
1164 for (size_t q = 0; q < qubits.size(); ++q)
1165 if (IsNetworkEntangledQubit(qubits[q]))
1166 return true;
1167
1168 return false;
1169 }
1170
1181 const std::shared_ptr<Circuits::IOperation<Time>> &op) const override {
1182 if (op->GetType() != Circuits::OperationType::kGate)
1183 return false;
1184 const auto qubits = op->AffectedQubits();
1185 if (qubits.size() != 2)
1186 return false;
1187
1188 return IsNetworkEntangledQubit(qubits[0]) &&
1189 IsNetworkEntangledQubit(qubits[1]);
1190 }
1191
1203 const std::shared_ptr<Circuits::IOperation<Time>> &op) const override {
1204 if (!op->IsConditional())
1205 return false;
1206
1207 const auto qubits = op->AffectedQubits();
1208
1209 const std::shared_ptr<Circuits::IConditionalOperation<Time>> condOp =
1210 std::static_pointer_cast<Circuits::IConditionalOperation<Time>>(op);
1211 const auto &classicalBits = condOp->GetCondition()->GetBitsIndices();
1212
1213 if (qubits.empty() && classicalBits.empty())
1214 throw std::runtime_error(
1215 "No classical bits specified!"); // this would be odd!
1216
1217 // consider it on the host where it has the first qubit (or bit, if there
1218 // are no qubits)
1219
1220 const size_t hostId = GetHostIdForAnyQubit(qubits[0]);
1221
1222 // now check the classical bits
1223 for (const auto bit : classicalBits)
1224 if (hostId != GetHostIdForClassicalBit(bit))
1225 return true;
1226
1227 return false;
1228 }
1229
1241 const std::shared_ptr<Circuits::IOperation<Time>> &op) const override {
1242 if (!op->IsConditional())
1243 throw std::runtime_error("Operation is not conditional!");
1244
1245 std::shared_ptr<Circuits::IConditionalOperation<Time>> condOp =
1246 std::static_pointer_cast<Circuits::IConditionalOperation<Time>>(op);
1247 const auto classicalBits = condOp->AffectedBits();
1248
1249 if (classicalBits.empty())
1250 throw std::runtime_error("No classical bits specified!");
1251
1252 return GetHostIdForClassicalBit(classicalBits[0]);
1253 }
1254
1263 bool AreQubitsOnSameHost(size_t qubitId1, size_t qubitId2) const override {
1264 for (const auto &host : hosts) {
1265 const bool present1 = host->IsQubitOnHost(qubitId1);
1266 const bool present2 = host->IsQubitOnHost(qubitId2);
1267
1268 if (present1 && present2)
1269 return true;
1270 else if (present1 || present2)
1271 return false;
1272 }
1273
1274 return false;
1275 }
1276
1286 bool AreClassicalBitsOnSameHost(size_t bitId1, size_t bitId2) const override {
1287 for (const auto &host : hosts) {
1288 const bool present1 = host->IsClassicalBitOnHost(bitId1);
1289 const bool present2 = host->IsClassicalBitOnHost(bitId2);
1290
1291 if (present1 && present2)
1292 return true;
1293 else if (present1 || present2)
1294 return false;
1295 }
1296
1297 return false;
1298 }
1299
1311 size_t bitId) const override {
1312 for (const auto &host : hosts) {
1313 const bool present1 = host->IsQubitOnHost(qubitId);
1314 const bool present2 = host->IsClassicalBitOnHost(bitId);
1315
1316 if (present1 && present2)
1317 return true;
1318 else if (present1 || present2)
1319 return false;
1320 }
1321
1322 return false;
1323 }
1324
1334 size_t GetHostIdForQubit(size_t qubitId) const override {
1335 for (const auto &host : hosts)
1336 if (host->IsQubitOnHost(qubitId))
1337 return host->GetId();
1338
1339 return std::numeric_limits<size_t>::max();
1340 }
1341
1354 size_t GetHostIdForEntangledQubit(size_t qubitId) const override {
1355 for (const auto &host : hosts)
1356 if (host->IsEntangledQubitOnHost(qubitId))
1357 return host->GetId();
1358
1359 return std::numeric_limits<size_t>::max();
1360 }
1361
1371 size_t GetHostIdForAnyQubit(size_t qubitId) const override {
1372 if (IsNetworkEntangledQubit(qubitId))
1373 return GetHostIdForEntangledQubit(qubitId);
1374
1375 return GetHostIdForQubit(qubitId);
1376 }
1377
1387 size_t GetHostIdForClassicalBit(size_t classicalBitId) const override {
1388 for (const auto &host : hosts)
1389 if (host->IsClassicalBitOnHost(classicalBitId))
1390 return host->GetId();
1391
1392 return std::numeric_limits<size_t>::max();
1393 }
1394
1403 std::vector<size_t> GetQubitsIds(size_t hostId) const override {
1404 if (hostId >= hosts.size())
1405 return std::vector<size_t>();
1406
1407 return hosts[hostId]->GetQubitsIds();
1408 }
1409
1420 std::vector<size_t>
1421 GetNetworkEntangledQubitsIds(size_t hostId) const override {
1422 if (hostId >= hosts.size())
1423 return std::vector<size_t>();
1424
1425 return hosts[hostId]->GetNetworkEntangledQubitsIds();
1426 }
1427
1437 std::vector<size_t> GetClassicalBitsIds(size_t hostId) const override {
1438 if (hostId >= hosts.size())
1439 return std::vector<size_t>();
1440
1441 return hosts[hostId]->GetClassicalBitsIds();
1442 }
1443
1454 std::vector<size_t>
1455 GetEntangledQubitMeasurementBitIds(size_t hostId) const override {
1456 if (hostId >= hosts.size())
1457 return std::vector<size_t>();
1458
1459 return hosts[hostId]->GetEntangledQubitMeasurementBitIds();
1460 }
1461
1473 bool IsNetworkEntangledQubit(size_t qubitId) const override {
1474 return qubitId >= GetNumQubits();
1475 }
1476
1489 bool IsEntanglementQubitBusy(size_t qubitId) const override { return false; }
1490
1506 bool AreEntanglementQubitsBusy(size_t qubitId1,
1507 size_t qubitId2) const override {
1508 return false;
1509 }
1510
1523 void MarkEntangledQubitsBusy(size_t qubitId1, size_t qubitId2) override {
1524 throw std::runtime_error(
1525 "Entanglement between hosts is not supported in the simple network");
1526 }
1527
1539 void MarkEntangledQubitFree(size_t qubitId) override {
1540 throw std::runtime_error(
1541 "Entanglement between hosts is not supported in the simple network");
1542 }
1543
1553 void ClearEntanglements() override {
1554 throw std::runtime_error(
1555 "Entanglement between hosts is not supported in the simple network");
1556 }
1557
1567 std::shared_ptr<Circuits::Circuit<Time>>
1568 GetDistributedCircuit() const override {
1569 return distCirc;
1570 }
1571
1582
1591 return lastMethod;
1592 }
1593
1604 size_t GetMaxSimulators() const override { return maxSimulators; }
1605
1617 void SetMaxSimulators(size_t val) override {
1618 if (val < 1)
1619 val = 1;
1620 else if (val > (size_t)QC::QubitRegisterCalculator<>::GetNumberOfThreads())
1621 val = (size_t)QC::QubitRegisterCalculator<>::GetNumberOfThreads();
1622
1623 maxSimulators = val;
1624 }
1625
1635 void SetOptimizeSimulator(bool optimize = true) override {
1636 optimizeSimulator = optimize;
1637 }
1638
1646 bool GetOptimizeSimulator() const override { return optimizeSimulator; }
1647
1656 const typename BaseClass::SimulatorsSet &GetSimulatorsSet() const override {
1658 }
1659
1670 Simulators::SimulationType kind) override {
1671 simulatorsForOptimizations.insert({type, kind});
1672 }
1673
1686
1703
1714 bool
1716 Simulators::SimulationType kind) const override {
1717 if (simulatorsForOptimizations.empty())
1718 return true;
1719
1720 return simulatorsForOptimizations.find({type, kind}) !=
1722 }
1723
1730 std::shared_ptr<INetwork<Time>> Clone() const override {
1731 const size_t numHosts = GetNumHosts();
1732
1733 std::vector<Types::qubit_t> qubits(numHosts);
1734 std::vector<size_t> cbits(numHosts);
1735
1736 for (size_t h = 0; h < numHosts; ++h) {
1737 qubits[h] = GetNumQubitsForHost(h);
1738 cbits[h] = GetNumClassicalBitsForHost(h);
1739 }
1740
1741 const auto cloned =
1742 std::make_shared<SimpleDisconnectedNetwork<Time, Controller>>(qubits,
1743 cbits);
1744
1745 cloned->maxBondDim = maxBondDim;
1746 cloned->singularValueThreshold = singularValueThreshold;
1747 cloned->mpsSample = mpsSample;
1748
1749 // cloned->optimizeSimulator = optimizeSimulator;
1750 // cloned->simulatorsForOptimizations = simulatorsForOptimizations;
1751
1752 if (GetSimulator())
1753 cloned->CreateSimulator(GetSimulator()->GetType(),
1755
1756 return cloned;
1757 }
1758
1759 std::shared_ptr<Simulators::ISimulator>
1760 ChooseBestSimulator(const std::shared_ptr<Circuits::Circuit<Time>> &dcirc,
1761 size_t &counts, size_t nrQubits, size_t nrCbits,
1762 size_t nrResultCbits, Simulators::SimulatorType &simType,
1764 std::vector<bool> &executed, bool multithreading = false,
1765 bool dontRunCircuitStart = false) const override {
1766 if (!optimizeSimulator)
1767 return nullptr;
1768
1770 return nullptr;
1771
1772 // when multithreading is set to true it means it needs a multithreaded
1773 // simulator
1774
1775 std::vector<
1776 std::pair<Simulators::SimulatorType, Simulators::SimulationType>>
1777 simulatorTypes;
1778
1779 const bool checkTensorNetwork =
1781
1782 // the others are to be picked between statevector, composite, tensor
1783 // networks and mps, for now at least for tensor networks in the future it's
1784 // worth checking different contractors!!!!
1785 //
1786 // clifford was decided at higher level
1788 // compare qcsim with qiskit aer if qiskit aer is available, let the best
1789 // one win
1792 simulatorTypes.emplace_back(Simulators::SimulatorType::kQCSim,
1794
1795#ifndef NO_QISKIT_AER
1796 // if the number of shots is too small, probably it's not worth it, it's
1797 // going to be better to just execute them multithreading
1800 simulatorTypes.emplace_back(Simulators::SimulatorType::kQiskitAer,
1802#endif
1803 }
1804
1807 simulatorTypes.emplace_back(Simulators::SimulatorType::kQCSim,
1809
1812 simulatorTypes.emplace_back(Simulators::SimulatorType::kCompositeQCSim,
1814
1815 if (checkTensorNetwork &&
1818 simulatorTypes.emplace_back(Simulators::SimulatorType::kQCSim,
1820
1824 (nrQubits <= 4 || !maxBondDim.empty()))
1825 simulatorTypes.emplace_back(
1828
1829#ifndef NO_QISKIT_AER
1830 // tensor networks are out of the picture for now for qiskit aer, since they
1831 // are available with cuda library, and work only on linux (obviously when
1832 // compiled properly and if there is the right hw an driver installed)
1833
1836 simulatorTypes.emplace_back(Simulators::SimulatorType::kQiskitAer,
1838
1842 simulatorTypes.emplace_back(
1845
1849 (nrQubits <= 4 || !maxBondDim.empty()))
1850 simulatorTypes.emplace_back(
1853#endif
1854
1855#ifdef __linux__
1857 if (OptimizationSimulatorExists(Simulators::SimulatorType::kGpuSim,
1859 simulatorTypes.emplace_back(Simulators::SimulatorType::kGpuSim,
1862 Simulators::SimulatorType::kGpuSim,
1864 simulatorTypes.emplace_back(
1865 Simulators::SimulatorType::kGpuSim,
1867 }
1868#endif
1869
1870 if (simulatorTypes.empty())
1871 return nullptr;
1872 else if (simulatorTypes.size() == 1) {
1873 simType = simulatorTypes[0].first;
1874 method = simulatorTypes[0].second;
1875
1876 std::shared_ptr<Simulators::ISimulator> sim =
1878 if (sim) {
1880 if (!maxBondDim.empty())
1881 sim->Configure("matrix_product_state_max_bond_dimension",
1882 maxBondDim.c_str());
1883 if (!singularValueThreshold.empty())
1884 sim->Configure("matrix_product_state_truncation_threshold",
1885 singularValueThreshold.c_str());
1886 if (!mpsSample.empty())
1887 sim->Configure("mps_sample_measure_algorithm", mpsSample.c_str());
1888 }
1889 sim->SetMultithreading(true);
1890 if (!dontRunCircuitStart)
1892 Time>::ExecuteUpToMeasurements(dcirc, nrQubits, nrCbits,
1893 nrResultCbits, sim, executed,
1894 multithreading);
1895
1896 return sim;
1897 }
1898 }
1899
1900 return simulatorsEstimator->ChooseBestSimulator(
1901 simulatorTypes, dcirc, counts, nrQubits, nrCbits, nrResultCbits,
1902 simType, method, executed, maxBondDim, singularValueThreshold,
1903 mpsSample, GetMaxSimulators(), pauliStrings, multithreading,
1904 dontRunCircuitStart);
1905 }
1906
1907protected:
1917 auto optimiser = controller->GetOptimiser();
1918 if (optimiser) {
1919 // convert the classical state results back to the expected order
1920 const auto &qubitsMap = optimiser->GetReverseQubitsMap();
1921
1922 ConvertBackState(qubitsMap);
1923 }
1924 }
1925
1938 const std::unordered_map<Types::qubit_t, Types::qubit_t> &qubitsMap) {
1939 // might not be the one stored in the network, might exist in the DES
1940 Circuits::OperationState &theClassicalState = GetState();
1941
1942 theClassicalState.Remap(qubitsMap);
1943 }
1944
1956 auto optimiser = controller->GetOptimiser();
1957 if (optimiser) {
1958 // convert the classical state results back to the expected order
1959 const auto &qubitsMap = optimiser->GetReverseQubitsMap();
1960
1961 ConvertBackResults(res, qubitsMap);
1962 }
1963 }
1964
1978 ExecuteResults &res,
1979 const std::unordered_map<Types::qubit_t, Types::qubit_t> &bitsMap) const {
1980 ExecuteResults translatedRes;
1981
1982 size_t numClassicalBits = 0;
1983 for (const auto &[q, b] : bitsMap)
1984 if (b >= numClassicalBits)
1985 numClassicalBits = b + 1;
1986
1987 numClassicalBits = std::max(numClassicalBits, GetNumClassicalBits());
1988
1989 for (const auto &r : res) {
1990 Circuits::OperationState translatedState(r.first);
1991
1992 translatedState.Remap(bitsMap, false, numClassicalBits);
1993 translatedRes[translatedState.GetAllBits()] = r.second;
1994 }
1995
1996 res.swap(translatedRes);
1997 }
1998
2010 std::unordered_map<Types::qubit_t, Types::qubit_t>
2011 MapCircuitOnHost(const std::shared_ptr<Circuits::Circuit<Time>> &circuit,
2012 size_t hostId, size_t &nrQubits, size_t &nrCbits,
2013 bool useSeparateSimForHosts = false) {
2014 qubitsMapOnHost.clear();
2015 nrQubits = 0;
2016 nrCbits = 0;
2017 if (!circuit)
2018 return {};
2019
2020 const auto host =
2021 std::static_pointer_cast<SimpleHost<Time>>(GetHost(hostId));
2022 const size_t hostNrQubits = host->GetNumQubits();
2023
2024 std::unordered_map<Types::qubit_t, Types::qubit_t> reverseQubitsMap;
2025
2026 if (!useSeparateSimForHosts) {
2027 size_t mxq = 0;
2028 size_t mnq = std::numeric_limits<size_t>::max();
2029 size_t mxb = 0;
2030 size_t mnb = std::numeric_limits<size_t>::max();
2031
2032 for (const auto &op : circuit->GetOperations()) {
2033 const auto qbits = op->AffectedQubits();
2034 for (auto q : qbits) {
2035 if (q > mxq)
2036 mxq = q;
2037 if (q < mnq)
2038 mnq = q;
2039 }
2040 const auto cbits = op->AffectedBits();
2041 for (auto b : cbits) {
2042 if (b > mxb)
2043 mxb = b;
2044 if (b < mnb)
2045 mnb = b;
2046 }
2047 }
2048
2049 if (mnq > mxq)
2050 mnq = 0;
2051 if (mnb > mxb)
2052 mnb = 0;
2053
2054 nrQubits = mxq - mnq + 1;
2055 nrCbits = mxb - mnb + 1;
2056 if (nrCbits < nrQubits)
2057 nrCbits = nrQubits;
2058
2059 const size_t startQubit = host->GetStartQubitId();
2060
2061 if (mnq < startQubit || mxq >= startQubit + hostNrQubits) {
2062 if (nrQubits >
2063 hostNrQubits +
2064 1) // the host has an additional 'special' qubit for the
2065 // entanglement or other operations (like those for cutting)
2066 throw std::runtime_error("Circuit does not fit on the host!");
2067
2068 for (size_t i = 0; i < nrCbits; ++i) {
2069 const size_t mapFrom = mnq + i;
2070 const size_t mapTo = startQubit + i;
2071
2072 qubitsMapOnHost[mapFrom] = mapTo;
2073 reverseQubitsMap[mapTo] = mapFrom;
2074 }
2075
2076 distCirc = std::static_pointer_cast<Circuits::Circuit<Time>>(
2077 circuit->Remap(qubitsMapOnHost, qubitsMapOnHost));
2078 }
2079
2080 return reverseQubitsMap;
2081 }
2082
2083 distCirc = circuit->RemapToContinuous(qubitsMapOnHost, reverseQubitsMap,
2084 nrQubits, nrCbits);
2085
2086 assert(nrQubits == qubitsMapOnHost.size());
2087
2088 if (nrQubits == 0)
2089 nrQubits = 1;
2090
2091 if (nrQubits >
2092 hostNrQubits +
2093 1) // the host has an additional 'special' qubit for the
2094 // entanglement or other operations (like those for cutting)
2095 throw std::runtime_error("Circuit does not fit on the host!");
2096
2097 return reverseQubitsMap;
2098 }
2099
2100 bool optimizeSimulator = true;
2102
2108
2109 std::string maxBondDim;
2111 std::string mpsSample;
2112
2113 size_t maxSimulators = QC::QubitRegisterCalculator<>::
2114 GetNumberOfThreads();
2116
2119 std::shared_ptr<Simulators::ISimulator>
2121
2122 std::shared_ptr<Circuits::Circuit<Time>>
2124
2125 std::shared_ptr<IController<Time>>
2127 // TODO: depending on the network topology, we will have adiacency lists, etc.
2128 // or simply a vector of hosts for a totally connected network (or where the
2129 // communication details do not matter so much)
2130 std::vector<std::shared_ptr<IHost<Time>>>
2132
2133 std::unique_ptr<Estimators::SimulatorsEstimatorInterface<Time>>
2135
2136private:
2138 threadsPool;
2139 bool recreateIfNeeded =
2140 true;
2141 std::unordered_map<Types::qubit_t, Types::qubit_t>
2142 qubitsMapOnHost;
2145 const std::vector<std::string> *pauliStrings =
2146 nullptr;
2148};
2149
2150} // namespace Network
2151
2152#endif // !_SIMPLE_NETWORK_H_
int GetSimulationType(void *sim)
Circuit class for holding the sequence of operations.
Definition Circuit.h:45
The operation interface.
Definition Operations.h:361
The state class that stores the classical state of a quantum circuit execution.
Definition Operations.h:62
const std::vector< bool > & GetAllBits() const
Get the classical bits.
Definition Operations.h:215
void Clear()
Clear the classical state.
Definition Operations.h:168
void SetResultsInOrder(const std::vector< bool > &results)
Set the classical bits.
Definition Operations.h:255
void Remap(const std::unordered_map< Types::qubit_t, Types::qubit_t > &mapping, bool ignoreNotMapped=false, size_t newSize=0)
Convert the state using the provided mapping.
Definition Operations.h:300
The controller host interface.
Definition Controller.h:100
The network interface.
Definition Network.h:56
std::shared_ptr< INetwork< Time > > getptr()
Definition Network.h:733
std::unordered_set< SimulatorPair, boost::hash< SimulatorPair > > SimulatorsSet
Definition Network.h:61
typename Circuits::Circuit< Time >::ExecuteResults ExecuteResults
Definition Network.h:58
Simulators::SimulatorType GetLastSimulatorType() const override
Get the last used simulator type.
void SetController(const std::shared_ptr< IController< Time > > &cntrl)
Set the network controller host.
std::vector< double > ExecuteExpectations(const std::shared_ptr< Circuits::Circuit< Time > > &circuit, const std::vector< std::string > &paulis) override
Execute the circuit on the network and return the expectation values for the specified Pauli strings.
Simulators::SimulatorType lastSimulatorType
The last simulator type used.
size_t GetHostIdForEntangledQubit(size_t qubitId) const override
Get the host id for the specified qubit used for entanglement between hosts.
std::shared_ptr< Simulators::ISimulator > simulator
The quantum computing simulator for the network.
bool ExpectsClassicalBitFromOtherHost(const std::shared_ptr< Circuits::IOperation< Time > > &op) const override
Checks if a gate expects a classical bit from another host.
void ExecuteOnHost(const std::shared_ptr< Circuits::Circuit< Time > > &circuit, size_t hostId) override
Execute the circuit on the specified host.
size_t GetHostIdForClassicalControl(const std::shared_ptr< Circuits::IOperation< Time > > &op) const override
Get the host id where the classical control bit resides for a conditioned gate.
void MarkEntangledQubitFree(size_t qubitId) override
Mark the specified qubit used for entanglement between hosts as free.
bool OptimizationSimulatorExists(Simulators::SimulatorType type, Simulators::SimulationType kind) const override
Checks if a simulator exists in the optimization set.
size_t GetNumNetworkEntangledQubits() const override
Get the number of qubits used for entanglement between hosts.
std::unordered_map< Types::qubit_t, Types::qubit_t > MapCircuitOnHost(const std::shared_ptr< Circuits::Circuit< Time > > &circuit, size_t hostId, size_t &nrQubits, size_t &nrCbits, bool useSeparateSimForHosts=false)
Map the circuit on the host.
size_t GetNumQubitsForHost(size_t hostId) const override
Get the number of qubits in the network for the specified host.
Circuits::OperationState & GetState() override
Get the classical state of the network.
void AddOptimizationSimulator(Simulators::SimulatorType type, Simulators::SimulationType kind) override
Adds a simulator to the simulators optimization set.
ExecuteResults RepeatedExecuteOnHost(const std::shared_ptr< Circuits::Circuit< Time > > &circuit, size_t hostId, size_t shots=1000) override
Execute the circuit on the specified host, repeatedly.
Simulators::SimulationType lastMethod
The last simulation method used.
ExecuteResults RepeatedExecute(const std::shared_ptr< Circuits::Circuit< Time > > &circuit, size_t shots=1000) override
Execute the circuit on the network, repeatedly.
bool optimizeSimulator
The flag to optimize the simulator.
std::vector< size_t > GetQubitsIds(size_t hostId) const override
Get the qubit ids for the specified host.
std::shared_ptr< Circuits::Circuit< Time > > GetDistributedCircuit() const override
Get the distributed circuit.
size_t GetNumQubits() const override
Get the number of qubits in the network.
bool GetOptimizeSimulator() const override
Returns the 'optimize' flag.
size_t GetNumberOfGatesDistributedOrCut(const std::shared_ptr< Circuits::Circuit< Time > > &circuit) const override
Get the number of gates that span more than one host.
size_t GetHostIdForClassicalBit(size_t classicalBitId) const override
Get the host id for the specified classical bit.
bool IsLocalOperation(const std::shared_ptr< Circuits::IOperation< Time > > &op) const override
Check if the circuit operation is local.
void Configure(const char *key, const char *value) override
Configures the network.
void CreateSimulator(Simulators::SimulatorType simType=Simulators::SimulatorType::kQCSim, Simulators::SimulationType simExecType=Simulators::SimulationType::kMatrixProductState, size_t nrQubits=0) override
Create the simulator for the network.
std::unique_ptr< Estimators::SimulatorsEstimatorInterface< Time > > simulatorsEstimator
The simulators estimator.
const std::shared_ptr< IHost< Time > > GetHost(size_t hostId) const override
Get the host with the specified id.
size_t GetNumHosts() const override
Get the number of hosts in the network.
typename BaseClass::ExecuteResults ExecuteResults
The execute results type.
size_t GetHostIdForQubit(size_t qubitId) const override
Get the host id for the specified qubit.
bool IsNetworkEntangledQubit(size_t qubitId) const override
Check if the specified qubit id is for a qubit used for entanglement between hosts.
void RemoveOptimizationSimulator(Simulators::SimulatorType type, Simulators::SimulationType kind) override
Removes a simulator from the simulators optimization set.
std::shared_ptr< INetwork< Time > > Clone() const override
Clone the network.
Simulators::SimulationType GetLastSimulationType() const override
Get the last used simulation type.
void SetMaxSimulators(size_t val) override
Set the maximum number of simulators that can be used in the network.
bool AreQubitAndClassicalBitOnSameHost(size_t qubitId, size_t bitId) const override
Check if the specified qubit and classical bit are on the same host.
void SetOptimizeSimulator(bool optimize=true) override
Allows using an optimized simulator.
size_t GetNumClassicalBitsForHost(size_t hostId) const override
Get the number of classical bits in the network for the specified host.
bool IsEntanglingGate(const std::shared_ptr< Circuits::IOperation< Time > > &op) const override
Checks if a gate is an entangling gate.
void Execute(const std::shared_ptr< Circuits::Circuit< Time > > &circuit) override
Execute the circuit on the network.
std::vector< std::shared_ptr< IHost< Time > > > hosts
The hosts in the network.
bool AreQubitsOnSameHost(size_t qubitId1, size_t qubitId2) const override
Check if the specified qubits are on the same host.
std::vector< ExecuteResults > ExecuteScheduled(const std::vector< Schedulers::ExecuteCircuit< Time > > &circuits) override
Schedule and execute circuits on the network.
size_t GetHostIdForAnyQubit(size_t qubitId) const override
Get the host id for the specified qubit.
size_t GetNumNetworkEntangledQubitsForHost(size_t hostId) const override
Get the number of qubits used for entanglement between hosts for the specified host.
Circuits::OperationState classicalState
The classical state of the network.
void ConvertBackResults(ExecuteResults &res, const std::unordered_map< Types::qubit_t, Types::qubit_t > &bitsMap) const
Converts back the results using the passed qubits map.
void ConvertBackState()
Converts back the state from the optimized network distribution mapping.
std::vector< double > ExecuteOnHostExpectations(const std::shared_ptr< Circuits::Circuit< Time > > &circuit, size_t hostId, const std::vector< std::string > &paulis)
Execute the circuit on the specified host and return the expectation values for the specified Pauli s...
std::shared_ptr< Simulators::ISimulator > ChooseBestSimulator(const std::shared_ptr< Circuits::Circuit< Time > > &dcirc, size_t &counts, size_t nrQubits, size_t nrCbits, size_t nrResultCbits, Simulators::SimulatorType &simType, Simulators::SimulationType &method, std::vector< bool > &executed, bool multithreading=false, bool dontRunCircuitStart=false) const override
std::shared_ptr< Circuits::Circuit< Time > > distCirc
The distributed circuit.
std::shared_ptr< Schedulers::IScheduler< Time > > GetScheduler() const override
Get the scheduler for the network.
size_t GetNumClassicalBits() const override
Get the number of classical bits in the network.
const std::shared_ptr< IController< Time > > GetController() const override
Get the controller for the network.
bool IsDistributedOperation(const std::shared_ptr< Circuits::IOperation< Time > > &op) const override
Check if the circuit operation is distributed.
std::vector< std::shared_ptr< IHost< Time > > > & GetHosts()
Get the hosts in the network.
bool SendPacket(size_t fromHostId, size_t toHostId, const std::vector< uint8_t > &packet) override
Sends a packet between two hosts.
const BaseClass::SimulatorsSet & GetSimulatorsSet() const override
Get the optimizations simulators set.
std::shared_ptr< Simulators::ISimulator > GetSimulator() const override
Get the simulator for the network.
bool OperatesWithNetworkEntangledQubit(const std::shared_ptr< Circuits::IOperation< Time > > &op) const override
Check if the circuit operation operates on the entanglement qubits between hosts.
size_t GetMaxSimulators() const override
Get the maximum number of simulators that can be used in the network.
void MarkEntangledQubitsBusy(size_t qubitId1, size_t qubitId2) override
Mark the pair of the specified qubits used for entanglement between hosts as busy.
void CreateScheduler(SchedulerType schType=SchedulerType::kNoEntanglementQubitsParallel) override
Create the scheduler for the network.
std::vector< size_t > GetClassicalBitsIds(size_t hostId) const override
Get the classical bit ids for the specified host.
std::vector< size_t > GetEntangledQubitMeasurementBitIds(size_t hostId) const override
Get the classical bit ids used for measurement of entanglement qubits between the hosts for the speci...
bool AreEntanglementQubitsBusy(size_t qubitId1, size_t qubitId2) const override
Check if any of the two specified qubits used for entanglement between hosts are busy.
INetwork< Time > BaseClass
The base class type.
size_t maxSimulators
The maximum number of simulators that can be used in the network.
std::shared_ptr< IController< Time > > controller
The controller for the network.
void ClearEntanglements() override
Clear all entanglements between hosts in the network.
void ConvertBackResults(ExecuteResults &res)
Converts back the results from the optimized network distribution mapping.
bool IsEntanglementQubitBusy(size_t qubitId) const override
Check if the specified qubit used for entanglement between hosts is busy.
void RemoveAllOptimizationSimulatorsAndAdd(Simulators::SimulatorType type, Simulators::SimulationType kind) override
Removes all simulators from the simulators optimization set and adds the one specified.
void CreateNetwork(const std::vector< Types::qubit_t > &qubits, const std::vector< size_t > &cbits)
Creates the network hosts and controller.
SimpleDisconnectedNetwork(const std::vector< Types::qubit_t > &qubits={}, const std::vector< size_t > &cbits={})
The constructor.
std::vector< size_t > GetNetworkEntangledQubitsIds(size_t hostId) const override
Get the qubit ids used for entanglement between hosts for the specified host.
void ConvertBackState(const std::unordered_map< Types::qubit_t, Types::qubit_t > &qubitsMap)
Converts back the state using the passed qubits map.
NetworkType GetType() const override
Get the type of the network.
bool AreClassicalBitsOnSameHost(size_t bitId1, size_t bitId2) const override
Check if the specified classical bits are on the same host.
The simple host implementation.
Definition SimpleHost.h:44
static std::shared_ptr< ISimulator > CreateSimulator(SimulatorType t=SimulatorType::kQCSim, SimulationType method=SimulationType::kMatrixProductState)
Create a quantum computing simulator.
Definition Factory.cpp:78
ThreadsPool class for holding and controlling a pool of threads.
Definition ThreadsPool.h:38
@ kGate
the usual quantum gate, result stays in simulator's state
Definition Operations.h:27
NetworkType
The type of the network.
Definition Network.h:32
@ kSimpleDisconnectedNetwork
Simple network, no communication among hosts, sequential simulation.
Definition Network.h:33
SchedulerType
The type of the network scheduler for scheduling execution of multiple circuits.
Definition Controller.h:81
SimulationType
The type of simulation.
Definition State.h:82
@ kStatevector
statevector simulation type
Definition State.h:83
@ kMatrixProductState
matrix product state simulation type
Definition State.h:84
@ kStabilizer
Clifford gates simulation type.
Definition State.h:85
@ kTensorNetwork
Tensor network simulation type.
Definition State.h:86
SimulatorType
The type of simulator.
Definition State.h:63
@ kCompositeQCSim
composite qcsim simulator type
Definition State.h:71
@ kQCSim
qcsim simulator type
Definition State.h:67
@ kQiskitAer
qiskit aer simulator type
Definition State.h:65
@ kCompositeQiskitAer
composite qiskit aer simulator type
Definition State.h:69
double time_type
The type of time.
Definition Types.h:23
A way to pack together a circuit and the number of shots for its execution.
Definition Controller.h:56