Maestro 0.1.0
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
SimpleDisconnectedNetwork.h
Go to the documentation of this file.
1
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
22#include "../Estimators/SimulatorsEstimatorInterface.h"
23#include "NetworkJob.h"
24
25namespace Network {
26
40template <typename Time = Types::time_type,
41 class Controller = SimpleController<Time>>
42class SimpleDisconnectedNetwork : public INetwork<Time> {
43 public:
57 SimpleDisconnectedNetwork(const std::vector<Types::qubit_t> &qubits = {},
58 const std::vector<size_t> &cbits = {}) {
59 if (!qubits.empty()) CreateNetwork(qubits, cbits);
60 }
61
71 void CreateNetwork(const std::vector<Types::qubit_t> &qubits,
72 const std::vector<size_t> &cbits) {
73 size_t qubitsOffset = 0;
74 size_t cbitsOffset = 0;
75
76 for (size_t i = 0; i < qubits.size(); ++i) {
77 const size_t numQubits = qubits[i];
78 const size_t numBits = (i < cbits.size() ? cbits[i] : 0);
79 hosts.emplace_back(std::make_shared<SimpleHost<Time>>(
80 i, qubitsOffset, numQubits, cbitsOffset, numBits));
81 qubitsOffset += numQubits;
82 cbitsOffset += numBits;
83 }
84
85 for (size_t i = 0; i < hosts.size(); ++i) {
86 std::static_pointer_cast<SimpleHost<Time>>(hosts[i])->SetEntangledQubitId(
87 qubitsOffset);
88 std::static_pointer_cast<SimpleHost<Time>>(hosts[i])
89 ->SetEntangledQubitMeasurementBit(cbitsOffset);
90 ++qubitsOffset;
91 ++cbitsOffset;
92 }
93
94 controller = std::make_shared<Controller>();
95 }
96
108 const std::shared_ptr<Circuits::Circuit<Time>> &circuit) override {
109 const auto recreate = recreateIfNeeded;
110
113 size_t numQubits = 2;
114 if (simulator) {
115 simType = simulator->GetType();
116 method = simulator->GetSimulationType();
117 numQubits = simulator->GetNumberOfQubits();
118 }
119
120 recreateIfNeeded = false;
121
122 const auto res = RepeatedExecute(circuit, 1);
123
124 recreateIfNeeded = recreate;
125
126 // put the results in the state
127 if (!res.empty()) {
128 const auto &first = *res.begin();
129 GetState().SetResultsInOrder(first.first);
130 }
131
132 if (recreate &&
133 (!simulator ||
134 (simulator && (simType != simulator->GetType() ||
135 method != simulator->GetSimulationType() ||
136 simulator->GetNumberOfQubits() != numQubits))))
137 CreateSimulator(simType, method);
138 }
139
152 void ExecuteOnHost(const std::shared_ptr<Circuits::Circuit<Time>> &circuit,
153 size_t hostId) override {
154 const auto recreate = recreateIfNeeded;
155
158 size_t numQubits = 2;
159 if (simulator) {
160 simType = simulator->GetType();
161 method = simulator->GetSimulationType();
162 numQubits = simulator->GetNumberOfQubits();
163 }
164
165 recreateIfNeeded = false;
166
167 const auto res = RepeatedExecuteOnHost(circuit, hostId, 1);
168
169 recreateIfNeeded = recreate;
170
171 // put the results in the state
172 if (!res.empty()) {
173 const auto &first = *res.begin();
174 GetState().SetResultsInOrder(first.first);
175 }
176
177 if (recreate &&
178 (!simulator ||
179 (simulator && (simType != simulator->GetType() ||
180 method != simulator->GetSimulationType() ||
181 simulator->GetNumberOfQubits() != numQubits))))
182 CreateSimulator(simType, method);
183 }
184
200 std::vector<double> ExecuteExpectations(
201 const std::shared_ptr<Circuits::Circuit<Time>> &circuit,
202 const std::vector<std::string> &paulis) override {
203 const auto recreate = recreateIfNeeded;
204
207 size_t numQubits = 2;
208 if (simulator) {
209 simType = simulator->GetType();
210 method = simulator->GetSimulationType();
211 numQubits = simulator->GetNumberOfQubits();
212 }
213
214 recreateIfNeeded = false;
215
216 pauliStrings = &paulis;
217 const auto res = RepeatedExecute(circuit, 1);
218 pauliStrings = nullptr;
219
220 recreateIfNeeded = recreate;
221
222 // put the results in the state
223 if (!res.empty()) {
224 const auto &first = *res.begin();
225 GetState().SetResultsInOrder(first.first);
226 }
227
228 std::vector<double> expectations(paulis.size());
229 if (simulator) {
230 // translate the pauli strings to the mapped order of qubits
231 const size_t numOps = simulator->GetNumberOfQubits();
232
233 auto optimiser = controller->GetOptimiser();
234 if (optimiser) {
235 // convert the classical state results back to the expected order
236 const auto &qubitsMap = optimiser->GetQubitsMap();
237
238 for (size_t i = 0; i < paulis.size(); ++i) {
239 std::string translated(numOps, 'I');
240
241 for (size_t j = 0; j < paulis[i].size(); ++j) {
242 const auto pos = qubitsMap.find(j);
243 if (pos != qubitsMap.end())
244 translated[pos->second] = paulis[i][j];
245 else
246 translated[j] = paulis[i][j];
247 }
248
249 expectations[i] = simulator->ExpectationValue(translated);
250 }
251 } else {
252 for (size_t i = 0; i < paulis.size(); ++i)
253 expectations[i] = simulator->ExpectationValue(paulis[i]);
254 }
255 }
256
257 if (recreate && (!simulator || simType != simulator->GetType() ||
258 method != simulator->GetSimulationType() ||
259 simulator->GetNumberOfQubits() != numQubits))
260 CreateSimulator(simType, method);
261
262 return expectations;
263 }
264
280 std::vector<double> ExecuteOnHostExpectations(
281 const std::shared_ptr<Circuits::Circuit<Time>> &circuit, size_t hostId,
282 const std::vector<std::string> &paulis) {
283 const auto recreate = recreateIfNeeded;
284
287 size_t numQubits = 2;
288 if (simulator) {
289 simType = simulator->GetType();
290 method = simulator->GetSimulationType();
291 numQubits = simulator->GetNumberOfQubits();
292 }
293
294 recreateIfNeeded = false;
295 pauliStrings = &paulis;
296 const auto res = RepeatedExecuteOnHost(circuit, hostId, 1);
297 pauliStrings = nullptr;
298
299 recreateIfNeeded = recreate;
300
301 // put the results in the state
302 if (!res.empty()) {
303 const auto &first = *res.begin();
304 GetState().SetResultsInOrder(first.first);
305 }
306
307 // for (const auto& m : qubitsMapOnHost)
308 // std::cout << "Mapping qubit " << m.first << " to " << m.second <<
309 // std::endl;
310
311 const size_t offsetBase = qubitsMapOnHost.size();
312
313 std::vector<double> expectations(paulis.size(), 1.);
314 if (simulator) {
315 // translate the pauli strings to the mapped order of qubits
316 const size_t numOps = simulator->GetNumberOfQubits();
317
318 // convert the pauli strings to the actual qubits order
319 for (size_t i = 0; i < paulis.size(); ++i) {
320 std::string translated(std::max(numOps, paulis[i].size()), 'I');
321
322 size_t offset = offsetBase;
323
324 for (size_t j = 0; j < paulis[i].size(); ++j) {
325 auto pos = qubitsMapOnHost.find(j);
326 if (pos != qubitsMapOnHost.end())
327 translated[pos->second] = paulis[i][j];
328 else {
329 translated[offset] = paulis[i][j];
330 ++offset;
331 }
332 }
333
334 // std::cout << "Translated pauli string: " << translated << std::endl;
335
336 expectations[i] = simulator->ExpectationValue(translated);
337 }
338 }
339
340 if (recreate && (!simulator || simType != simulator->GetType() ||
341 method != simulator->GetSimulationType() ||
342 simulator->GetNumberOfQubits() != numQubits))
343 CreateSimulator(simType, method);
344
345 return expectations;
346 }
347
362 const std::shared_ptr<Circuits::Circuit<Time>> &circuit,
363 size_t shots = 1000) override {
364 if (!controller || !circuit) return {};
365
366 distCirc = controller->DistributeCircuit(BaseClass::getptr(), circuit);
367 if (!distCirc) return {};
368
369#ifdef _DEBUG
370 for (auto q : distCirc->AffectedQubits()) {
371 if (q >= GetNumQubits()) {
372 std::cout
373 << "This is a distributed circuit, using entanglement or cutting"
374 << std::endl;
375 break;
376 }
377 }
378#endif
379
380 if (!simulator) return {};
381
382 auto simType = simulator->GetType();
383 if (distCirc->HasOpsAfterMeasurements() &&
384 (
385#ifndef NO_QISKIT_AER
387#endif
389 distCirc->MoveMeasurementsAndResets();
390
391 auto method = simulator->GetSimulationType();
392
393 const auto saveSimType = simType;
394 const auto saveMethod = method;
395
396 if (GetOptimizeSimulator() && distCirc->IsClifford() &&
398 // this is for the gpu simulator, as it doesn't support stabilizer
399#ifdef __linux__
401#endif
402 ) {
404
407#ifndef NO_QISKIT_AER
410#endif
411 }
412
413 ExecuteResults res;
414 const size_t nrQubits = GetNumQubits() + GetNumNetworkEntangledQubits();
415 const size_t nrCbitsResults = GetNumClassicalBits();
416
417 maxBondDim =
418 simulator->GetConfiguration("matrix_product_state_max_bond_dimension");
419 singularValueThreshold = simulator->GetConfiguration(
420 "matrix_product_state_truncation_threshold");
421 mpsSample = simulator->GetConfiguration("mps_sample_measure_algorithm");
422
423 // do that only if the optimization for simulator is on and the estimator is
424 // available, ortherwise an 'optimal' simulator won't be created
426 simulatorsEstimator->IsInitialized()) {
427 simulator->Clear();
428 GetState().Clear();
429 }
430
431 std::vector<bool> executed;
432 auto optSim =
433 ChooseBestSimulator(distCirc, shots, nrQubits, nrQubits, nrCbitsResults,
434 simType, method, executed);
435
436 lastSimulatorType = simType;
437 lastMethod = method;
438
439 size_t nrThreads = GetMaxSimulators();
440
441#ifdef __linux__
442 if (simType == Simulators::SimulatorType::kGpuSim) nrThreads = 1;
443#endif
445 !distCirc->HasOpsAfterMeasurements())
446 nrThreads = 1;
447
448 nrThreads = std::min(nrThreads, std::max<size_t>(shots, 1ULL));
449
450 std::mutex resultsMutex;
451
452 const auto dcirc = distCirc;
453
454 if (nrThreads > 1) {
455 // since it's going to execute on multiple threads, free the memory from
456 // the network's simulator and state, it's going to use other ones,
457 // created in the threads if optimization already exists, it will be
458 // cloned in the threads, otherwise a new one will be created in the
459 // threads
462 ->IsInitialized()) // otherwise it was already cleared
463 {
464 simulator->Clear();
465 GetState().Clear();
466 }
467
468 const size_t cntPerThread = std::max<size_t>(shots / nrThreads, 1ULL);
469
470 threadsPool.Resize(nrThreads);
471 threadsPool.SetFinishLimit(shots);
472
473 while (shots > 0) {
474 const size_t curCnt = std::min(cntPerThread, shots);
475
476 shots -= curCnt;
477
478 auto job = std::make_shared<ExecuteJob<Time>>(
479 dcirc, res, curCnt, nrQubits, nrQubits, nrCbitsResults, simType,
480 method, resultsMutex);
481 job->optimiseMultipleShotsExecution = GetOptimizeSimulator();
482
483 job->maxBondDim = maxBondDim;
484 job->mpsSample = mpsSample;
485 job->singularValueThreshold = singularValueThreshold;
486
487 if (optSim) {
488 job->optSim = optSim->Clone();
489 job->executedGates = executed;
490 }
491
492 threadsPool.AddRunJob(std::move(job));
493 }
494
495 threadsPool.WaitForFinish();
496 threadsPool.Stop();
497 } else {
498 const size_t curCnt = shots;
499
500 auto job = std::make_shared<ExecuteJob<Time>>(
501 dcirc, res, curCnt, nrQubits, nrQubits, nrCbitsResults, simType,
502 method, resultsMutex);
503 job->optimiseMultipleShotsExecution = GetOptimizeSimulator();
504
505 job->maxBondDim = maxBondDim;
506 job->mpsSample = mpsSample;
507 job->singularValueThreshold = singularValueThreshold;
508
509 if (optSim) {
510 optSim->SetMultithreading(true);
511 job->optSim = optSim;
512 job->executedGates = executed;
513 } else {
514 if (simulator && method == saveMethod && simType == saveSimType) {
515 // use the already created simulator
516 optSim = simulator;
517 job->optSim = optSim;
518 job->executedGates.resize(distCirc->size(),
519 false); // no gates executed yet
520 simulator = nullptr;
521 }
522 }
523
524 job->DoWorkNoLock();
525 if (!recreateIfNeeded) simulator = job->optSim;
526 }
527
528 if (recreateIfNeeded) CreateSimulator(saveSimType, saveMethod);
529
531
532 return res;
533 }
534
551 const std::shared_ptr<Circuits::Circuit<Time>> &circuit, size_t hostId,
552 size_t shots = 1000) override {
553 if (!circuit || hostId >= GetNumHosts()) return {};
554
555 size_t nrQubits = 0;
556 size_t nrCbits = 0;
557
558 std::shared_ptr<Circuits::Circuit<Time>> optCircuit;
559 if (GetController()->GetOptimizeCircuit()) {
560 optCircuit =
561 std::static_pointer_cast<Circuits::Circuit<Time>>(circuit->Clone());
562 optCircuit->Optimize();
563 }
564 const auto reverseQubitsMap = MapCircuitOnHost(
565 GetController()->GetOptimizeCircuit() ? optCircuit : circuit, hostId,
566 nrQubits, nrCbits, true);
567 if (nrCbits == 0) nrCbits = nrQubits;
568
569 if (!simulator || !distCirc) return {};
570
571 auto simType = simulator->GetType();
572
573 maxBondDim =
574 simulator->GetConfiguration("matrix_product_state_max_bond_dimension");
575 singularValueThreshold = simulator->GetConfiguration(
576 "matrix_product_state_truncation_threshold");
577 mpsSample = simulator->GetConfiguration("mps_sample_measure_algorithm");
578
579 if (distCirc->HasOpsAfterMeasurements() &&
580 (
581#ifndef NO_QISKIT_AER
583#endif
585 distCirc->MoveMeasurementsAndResets();
586
587 auto method = simulator->GetSimulationType();
588 const auto saveSimType = simType;
589 const auto saveMethod = method;
590
591 if (GetOptimizeSimulator() && distCirc->IsClifford() &&
593 // this is for the gpu simulator, as it doesn't support stabilizer
594#ifdef __linux__
596#endif
597 ) {
599
602#ifndef NO_QISKIT_AER
605#endif
606 }
607
608 ExecuteResults res;
609
610 // since it's going to execute on multiple threads, free the memory from the
611 // network's simulator and state, it's going to use other ones, created in
612 // the threads
613 simulator->Clear();
614 GetState().Clear();
615
616 std::vector<bool> executed;
617 auto optSim = ChooseBestSimulator(distCirc, shots, nrQubits, nrCbits,
618 nrCbits, simType, method, executed);
619
620 lastSimulatorType = simType;
621 lastMethod = method;
622
623 size_t nrThreads = GetMaxSimulators();
624
625#ifdef __linux__
627 nrThreads = 1;
628 else
629#endif
631 !distCirc->HasOpsAfterMeasurements())
632 nrThreads = 1;
633
634 nrThreads = std::min(nrThreads, std::max<size_t>(shots, 1ULL));
635
636 // WARNING: be sure to not put this above ChooseBestSimulator, as that one
637 // can change the shots value!
638
639 std::mutex resultsMutex;
640
641 const auto dcirc = distCirc;
642
643 if (nrThreads > 1) {
644 // this rounds up, rounding down is better
645 // const size_t cntPerThread = static_cast<size_t>((shots - 1) / nrThreads
646 // + 1);
647 const size_t cntPerThread = std::max<size_t>(shots / nrThreads, 1ULL);
648
649 threadsPool.Resize(nrThreads);
650 threadsPool.SetFinishLimit(shots);
651
652 while (shots > 0) {
653 const size_t curCnt = std::min(cntPerThread, shots);
654 shots -= curCnt;
655
656 auto job = std::make_shared<ExecuteJob<Time>>(
657 dcirc, res, curCnt, nrQubits, nrCbits, nrCbits, simType, method,
658 resultsMutex);
659 job->optimiseMultipleShotsExecution = GetOptimizeSimulator();
660
661 job->maxBondDim = maxBondDim;
662 job->mpsSample = mpsSample;
663 job->singularValueThreshold = singularValueThreshold;
664
665 if (optSim) {
666 job->optSim = optSim->Clone();
667 job->executedGates = executed;
668 }
669
670 threadsPool.AddRunJob(std::move(job));
671 }
672
673 threadsPool.WaitForFinish();
674 threadsPool.Stop();
675 } else {
676 const size_t curCnt = shots;
677
678 auto job = std::make_shared<ExecuteJob<Time>>(
679 dcirc, res, curCnt, nrQubits, nrCbits, nrCbits, simType, method,
680 resultsMutex);
681 job->optimiseMultipleShotsExecution = GetOptimizeSimulator();
682
683 job->maxBondDim = maxBondDim;
684 job->mpsSample = mpsSample;
685 job->singularValueThreshold = singularValueThreshold;
686
687 if (optSim) {
688 optSim->SetMultithreading(true);
689 job->optSim = optSim;
690 job->executedGates = executed;
691 }
692
693 job->DoWorkNoLock();
694 if (!recreateIfNeeded) simulator = job->optSim;
695 }
696
697 if (recreateIfNeeded) CreateSimulator(saveSimType, saveMethod);
698
699 if (!reverseQubitsMap.empty()) ConvertBackResults(res, reverseQubitsMap);
700
701 return res;
702 }
703
713 const std::shared_ptr<Circuits::Circuit<Time>> &circuit) const override {
714 if (!circuit) return 0;
715
716 size_t distgates = 0;
717
718 for (const auto &op : circuit->GetOperations())
719 if (!IsLocalOperation(op)) ++distgates;
720
721 return distgates;
722 }
723
740 std::vector<ExecuteResults> ExecuteScheduled(
741 const std::vector<Schedulers::ExecuteCircuit<Time>> &circuits) override {
742 // create a default one if not set
743 if (!GetScheduler()) {
745
746 if (!GetScheduler()) return {};
747 }
748
749 return GetScheduler()->ExecuteScheduled(circuits);
750 }
751
773 Simulators::SimulationType simExecType =
775 size_t nrQubits = 0) override {
779
780 simulator =
782
783 if (simulator) {
784 if (!maxBondDim.empty())
785 simulator->Configure("matrix_product_state_max_bond_dimension",
786 maxBondDim.c_str());
787 if (!singularValueThreshold.empty())
788 simulator->Configure("matrix_product_state_truncation_threshold",
789 singularValueThreshold.c_str());
790 if (!mpsSample.empty())
791 simulator->Configure("mps_sample_measure_algorithm", mpsSample.c_str());
792
793 simulator->AllocateQubits(
794 nrQubits == 0 ? GetNumQubits() + GetNumNetworkEntangledQubits()
795 : nrQubits);
796 simulator->Initialize();
797 }
798 }
799
809 void Configure(const char *key, const char *value) override {
810 if (!key || !value) return;
811
812 if (std::string("matrix_product_state_max_bond_dimension") == key)
813 maxBondDim = value;
814 else if (std::string("matrix_product_state_truncation_threshold") == key)
816 else if (std::string("mps_sample_measure_algorithm") == key)
817 mpsSample = value;
818 else if (std::string("max_simulators") == key)
819 maxSimulators = std::stoull(value);
820
821 if (simulator) simulator->Configure(key, value);
822 }
823
832 std::shared_ptr<Simulators::ISimulator> GetSimulator() const override {
833 return simulator;
834 }
835
845
858 SchedulerType schType =
860 if (!controller) return;
861
862 controller->CreateScheduler(BaseClass::getptr(), schType);
863 }
864
873 std::shared_ptr<Schedulers::IScheduler<Time>> GetScheduler() const override {
874 if (!controller) return nullptr;
875
876 return controller->GetScheduler();
877 }
878
888 const std::shared_ptr<IHost<Time>> GetHost(size_t hostId) const override {
889 if (hostId >= hosts.size()) return nullptr;
890
891 return hosts[hostId];
892 }
893
902 const std::shared_ptr<IController<Time>> GetController() const override {
903 return controller;
904 }
905
913 size_t GetNumHosts() const override { return hosts.size(); }
914
923 size_t GetNumQubits() const override {
924 size_t res = 0;
925
926 for (const auto &host : hosts) res += host->GetNumQubits();
927
928 return res;
929 }
930
940 size_t GetNumQubitsForHost(size_t hostId) const override {
941 if (hostId >= hosts.size()) return 0;
942
943 return hosts[hostId]->GetNumQubits();
944 }
945
954 size_t GetNumNetworkEntangledQubits() const override {
955 size_t res = 0;
956
957 for (const auto &host : hosts) res += host->GetNumNetworkEntangledQubits();
958
959 return res;
960 }
961
974 size_t GetNumNetworkEntangledQubitsForHost(size_t hostId) const override {
975 if (hostId >= hosts.size()) return 0;
976
977 return hosts[hostId]->GetNumNetworkEntangledQubits();
978 }
979
988 size_t GetNumClassicalBits() const override {
989 size_t res = 0;
990
991 for (const auto &host : hosts) res += host->GetNumClassicalBits();
992
993 return res;
994 }
995
1007 size_t GetNumClassicalBitsForHost(size_t hostId) const override {
1008 if (hostId >= hosts.size()) return 0;
1009
1010 return hosts[hostId]->GetNumClassicalBits();
1011 }
1012
1022 std::vector<std::shared_ptr<IHost<Time>>> &GetHosts() { return hosts; }
1023
1031 void SetController(const std::shared_ptr<IController<Time>> &cntrl) {
1032 controller = cntrl;
1033 }
1034
1048 bool SendPacket(size_t fromHostId, size_t toHostId,
1049 const std::vector<uint8_t> &packet) override {
1050 return false;
1051 }
1052
1060 NetworkType GetType() const override {
1062 }
1063
1075 const std::shared_ptr<Circuits::IOperation<Time>> &op) const override {
1076 const auto qubits = op->AffectedQubits();
1077
1078 if (qubits.empty()) return true;
1079
1080 size_t firstQubit = qubits[0];
1081
1082 for (size_t q = 1; q < qubits.size(); ++q)
1083 if (!AreQubitsOnSameHost(firstQubit, qubits[q])) return false;
1084
1085 return true;
1086 }
1087
1101 const std::shared_ptr<Circuits::IOperation<Time>> &op) const override {
1102 const auto qubits = op->AffectedQubits();
1103
1104 if (qubits.empty()) return false;
1105
1106 // grab the first qubit that is on a host (skip over network entangled
1107 // qubits)
1108 size_t firstQubit = qubits[0];
1109 size_t q = 1;
1110 for (; IsNetworkEntangledQubit(firstQubit) && q < qubits.size(); ++q)
1111 firstQubit = qubits[q];
1112
1113 // check to see one of the other qubits is on a different host, but ignore
1114 // the network entangled qubits
1115 for (; q < qubits.size(); ++q)
1116 if (!IsNetworkEntangledQubit(qubits[q]) &&
1117 !AreQubitsOnSameHost(firstQubit, qubits[q]))
1118 return true;
1119
1120 return false;
1121 }
1122
1135 const std::shared_ptr<Circuits::IOperation<Time>> &op) const override {
1136 const auto qubits = op->AffectedQubits();
1137
1138 if (qubits.empty()) return false;
1139
1140 for (size_t q = 0; q < qubits.size(); ++q)
1141 if (IsNetworkEntangledQubit(qubits[q])) return true;
1142
1143 return false;
1144 }
1145
1156 const std::shared_ptr<Circuits::IOperation<Time>> &op) const override {
1157 if (op->GetType() != Circuits::OperationType::kGate) return false;
1158 const auto qubits = op->AffectedQubits();
1159 if (qubits.size() != 2) return false;
1160
1161 return IsNetworkEntangledQubit(qubits[0]) &&
1162 IsNetworkEntangledQubit(qubits[1]);
1163 }
1164
1176 const std::shared_ptr<Circuits::IOperation<Time>> &op) const override {
1177 if (!op->IsConditional()) return false;
1178
1179 const auto qubits = op->AffectedQubits();
1180
1181 const std::shared_ptr<Circuits::IConditionalOperation<Time>> condOp =
1182 std::static_pointer_cast<Circuits::IConditionalOperation<Time>>(op);
1183 const auto &classicalBits = condOp->GetCondition()->GetBitsIndices();
1184
1185 if (qubits.empty() && classicalBits.empty())
1186 throw std::runtime_error(
1187 "No classical bits specified!"); // this would be odd!
1188
1189 // consider it on the host where it has the first qubit (or bit, if there
1190 // are no qubits)
1191
1192 const size_t hostId = GetHostIdForAnyQubit(qubits[0]);
1193
1194 // now check the classical bits
1195 for (const auto bit : classicalBits)
1196 if (hostId != GetHostIdForClassicalBit(bit)) return true;
1197
1198 return false;
1199 }
1200
1212 const std::shared_ptr<Circuits::IOperation<Time>> &op) const override {
1213 if (!op->IsConditional())
1214 throw std::runtime_error("Operation is not conditional!");
1215
1216 std::shared_ptr<Circuits::IConditionalOperation<Time>> condOp =
1217 std::static_pointer_cast<Circuits::IConditionalOperation<Time>>(op);
1218 const auto classicalBits = condOp->AffectedBits();
1219
1220 if (classicalBits.empty())
1221 throw std::runtime_error("No classical bits specified!");
1222
1223 return GetHostIdForClassicalBit(classicalBits[0]);
1224 }
1225
1234 bool AreQubitsOnSameHost(size_t qubitId1, size_t qubitId2) const override {
1235 for (const auto &host : hosts) {
1236 const bool present1 = host->IsQubitOnHost(qubitId1);
1237 const bool present2 = host->IsQubitOnHost(qubitId2);
1238
1239 if (present1 && present2)
1240 return true;
1241 else if (present1 || present2)
1242 return false;
1243 }
1244
1245 return false;
1246 }
1247
1257 bool AreClassicalBitsOnSameHost(size_t bitId1, size_t bitId2) const override {
1258 for (const auto &host : hosts) {
1259 const bool present1 = host->IsClassicalBitOnHost(bitId1);
1260 const bool present2 = host->IsClassicalBitOnHost(bitId2);
1261
1262 if (present1 && present2)
1263 return true;
1264 else if (present1 || present2)
1265 return false;
1266 }
1267
1268 return false;
1269 }
1270
1282 size_t bitId) const override {
1283 for (const auto &host : hosts) {
1284 const bool present1 = host->IsQubitOnHost(qubitId);
1285 const bool present2 = host->IsClassicalBitOnHost(bitId);
1286
1287 if (present1 && present2)
1288 return true;
1289 else if (present1 || present2)
1290 return false;
1291 }
1292
1293 return false;
1294 }
1295
1305 size_t GetHostIdForQubit(size_t qubitId) const override {
1306 for (const auto &host : hosts)
1307 if (host->IsQubitOnHost(qubitId)) return host->GetId();
1308
1309 return std::numeric_limits<size_t>::max();
1310 }
1311
1324 size_t GetHostIdForEntangledQubit(size_t qubitId) const override {
1325 for (const auto &host : hosts)
1326 if (host->IsEntangledQubitOnHost(qubitId)) return host->GetId();
1327
1328 return std::numeric_limits<size_t>::max();
1329 }
1330
1340 size_t GetHostIdForAnyQubit(size_t qubitId) const override {
1341 if (IsNetworkEntangledQubit(qubitId))
1342 return GetHostIdForEntangledQubit(qubitId);
1343
1344 return GetHostIdForQubit(qubitId);
1345 }
1346
1356 size_t GetHostIdForClassicalBit(size_t classicalBitId) const override {
1357 for (const auto &host : hosts)
1358 if (host->IsClassicalBitOnHost(classicalBitId)) return host->GetId();
1359
1360 return std::numeric_limits<size_t>::max();
1361 }
1362
1371 std::vector<size_t> GetQubitsIds(size_t hostId) const override {
1372 if (hostId >= hosts.size()) return std::vector<size_t>();
1373
1374 return hosts[hostId]->GetQubitsIds();
1375 }
1376
1387 std::vector<size_t> GetNetworkEntangledQubitsIds(
1388 size_t hostId) const override {
1389 if (hostId >= hosts.size()) return std::vector<size_t>();
1390
1391 return hosts[hostId]->GetNetworkEntangledQubitsIds();
1392 }
1393
1403 std::vector<size_t> GetClassicalBitsIds(size_t hostId) const override {
1404 if (hostId >= hosts.size()) return std::vector<size_t>();
1405
1406 return hosts[hostId]->GetClassicalBitsIds();
1407 }
1408
1420 size_t hostId) const override {
1421 if (hostId >= hosts.size()) return std::vector<size_t>();
1422
1423 return hosts[hostId]->GetEntangledQubitMeasurementBitIds();
1424 }
1425
1437 bool IsNetworkEntangledQubit(size_t qubitId) const override {
1438 return qubitId >= GetNumQubits();
1439 }
1440
1453 bool IsEntanglementQubitBusy(size_t qubitId) const override { return false; }
1454
1470 bool AreEntanglementQubitsBusy(size_t qubitId1,
1471 size_t qubitId2) const override {
1472 return false;
1473 }
1474
1487 void MarkEntangledQubitsBusy(size_t qubitId1, size_t qubitId2) override {
1488 throw std::runtime_error(
1489 "Entanglement between hosts is not supported in the simple network");
1490 }
1491
1503 void MarkEntangledQubitFree(size_t qubitId) override {
1504 throw std::runtime_error(
1505 "Entanglement between hosts is not supported in the simple network");
1506 }
1507
1517 void ClearEntanglements() override {
1518 throw std::runtime_error(
1519 "Entanglement between hosts is not supported in the simple network");
1520 }
1521
1531 std::shared_ptr<Circuits::Circuit<Time>> GetDistributedCircuit()
1532 const override {
1533 return distCirc;
1534 }
1535
1546
1555 return lastMethod;
1556 }
1557
1568 size_t GetMaxSimulators() const override { return maxSimulators; }
1569
1581 void SetMaxSimulators(size_t val) override {
1582 if (val < 1)
1583 val = 1;
1584 else if (val > (size_t)QC::QubitRegisterCalculator<>::GetNumberOfThreads())
1585 val = (size_t)QC::QubitRegisterCalculator<>::GetNumberOfThreads();
1586
1587 maxSimulators = val;
1588 }
1589
1599 void SetOptimizeSimulator(bool optimize = true) override {
1600 optimizeSimulator = optimize;
1601 }
1602
1610 bool GetOptimizeSimulator() const override { return optimizeSimulator; }
1611
1620 const typename BaseClass::SimulatorsSet &GetSimulatorsSet() const override {
1622 }
1623
1634 Simulators::SimulationType kind) override {
1635 simulatorsForOptimizations.insert({type, kind});
1636 }
1637
1650
1667
1680 Simulators::SimulationType kind) const override {
1681 if (simulatorsForOptimizations.empty()) return true;
1682
1683 return simulatorsForOptimizations.find({type, kind}) !=
1685 }
1686
1693 std::shared_ptr<INetwork<Time>> Clone() const override {
1694 const size_t numHosts = GetNumHosts();
1695
1696 std::vector<Types::qubit_t> qubits(numHosts);
1697 std::vector<size_t> cbits(numHosts);
1698
1699 for (size_t h = 0; h < numHosts; ++h) {
1700 qubits[h] = GetNumQubitsForHost(h);
1701 cbits[h] = GetNumClassicalBitsForHost(h);
1702 }
1703
1704 const auto cloned =
1705 std::make_shared<SimpleDisconnectedNetwork<Time, Controller>>(qubits,
1706 cbits);
1707
1708 cloned->maxBondDim = maxBondDim;
1709 cloned->singularValueThreshold = singularValueThreshold;
1710 cloned->mpsSample = mpsSample;
1711
1712 // cloned->optimizeSimulator = optimizeSimulator;
1713 // cloned->simulatorsForOptimizations = simulatorsForOptimizations;
1714
1715 if (GetSimulator())
1716 cloned->CreateSimulator(GetSimulator()->GetType(),
1717 GetSimulator()->GetSimulationType());
1718
1719 return cloned;
1720 }
1721
1722 std::shared_ptr<Simulators::ISimulator> ChooseBestSimulator(
1723 const std::shared_ptr<Circuits::Circuit<Time>> &dcirc, size_t &counts,
1724 size_t nrQubits, size_t nrCbits, size_t nrResultCbits,
1726 std::vector<bool> &executed, bool multithreading = false,
1727 bool dontRunCircuitStart = false) const override {
1728 if (!optimizeSimulator) return nullptr;
1729
1730 if ((!simulatorsEstimator || !simulatorsEstimator->IsInitialized()) &&
1731 simulatorsForOptimizations.size() != 1)
1732 return nullptr;
1733
1734 // when multithreading is set to true it means it needs a multithreaded
1735 // simulator
1736
1737 std::vector<
1738 std::pair<Simulators::SimulatorType, Simulators::SimulationType>>
1739 simulatorTypes;
1740
1741 const bool checkTensorNetwork =
1743
1744 // the others are to be picked between statevector, composite, tensor
1745 // networks and mps, for now at least for tensor networks in the future it's
1746 // worth checking different contractors!!!!
1747 //
1748 // clifford was decided at higher level
1750 // compare qcsim with qiskit aer if qiskit aer is available, let the best
1751 // one win
1754 simulatorTypes.emplace_back(Simulators::SimulatorType::kQCSim,
1756
1757#ifndef NO_QISKIT_AER
1758 // if the number of shots is too small, probably it's not worth it, it's
1759 // going to be better to just execute them multithreading
1762 simulatorTypes.emplace_back(Simulators::SimulatorType::kQiskitAer,
1764#endif
1765 }
1766
1769 simulatorTypes.emplace_back(Simulators::SimulatorType::kQCSim,
1771
1774 simulatorTypes.emplace_back(Simulators::SimulatorType::kCompositeQCSim,
1776
1777 if (checkTensorNetwork &&
1780 simulatorTypes.emplace_back(Simulators::SimulatorType::kQCSim,
1782
1786 (nrQubits <= 4 || !maxBondDim.empty()))
1787 simulatorTypes.emplace_back(
1790
1791#ifndef NO_QISKIT_AER
1792 // tensor networks are out of the picture for now for qiskit aer, since they
1793 // are available with cuda library, and work only on linux (obviously when
1794 // compiled properly and if there is the right hw an driver installed)
1795
1798 simulatorTypes.emplace_back(Simulators::SimulatorType::kQiskitAer,
1800
1804 simulatorTypes.emplace_back(
1807
1811 (nrQubits <= 4 || !maxBondDim.empty()))
1812 simulatorTypes.emplace_back(
1815#endif
1816
1817#ifdef __linux__
1821 simulatorTypes.emplace_back(Simulators::SimulatorType::kGpuSim,
1826 simulatorTypes.emplace_back(
1832 simulatorTypes.emplace_back(Simulators::SimulatorType::kGpuSim,
1834 }
1835#endif
1836
1837 if (simulatorTypes.empty())
1838 return nullptr;
1839 else if (simulatorTypes.size() == 1) {
1840 simType = simulatorTypes[0].first;
1841 method = simulatorTypes[0].second;
1842
1843 std::shared_ptr<Simulators::ISimulator> sim =
1845 if (sim) {
1847 if (!maxBondDim.empty())
1848 sim->Configure("matrix_product_state_max_bond_dimension",
1849 maxBondDim.c_str());
1850 if (!singularValueThreshold.empty())
1851 sim->Configure("matrix_product_state_truncation_threshold",
1852 singularValueThreshold.c_str());
1853 if (!mpsSample.empty())
1854 sim->Configure("mps_sample_measure_algorithm", mpsSample.c_str());
1855 }
1856 sim->SetMultithreading(true);
1857 if (!dontRunCircuitStart)
1859 Time>::ExecuteUpToMeasurements(dcirc, nrQubits, nrCbits,
1860 nrResultCbits, sim, executed,
1861 multithreading);
1862
1863 return sim;
1864 }
1865 }
1866
1867 return simulatorsEstimator->ChooseBestSimulator(
1868 simulatorTypes, dcirc, counts, nrQubits, nrCbits, nrResultCbits,
1869 simType, method, executed, maxBondDim, singularValueThreshold,
1870 mpsSample, GetMaxSimulators(), pauliStrings, multithreading,
1871 dontRunCircuitStart);
1872 }
1873
1874 protected:
1884 auto optimiser = controller->GetOptimiser();
1885 if (optimiser) {
1886 // convert the classical state results back to the expected order
1887 const auto &qubitsMap = optimiser->GetReverseQubitsMap();
1888
1889 ConvertBackState(qubitsMap);
1890 }
1891 }
1892
1905 const std::unordered_map<Types::qubit_t, Types::qubit_t> &qubitsMap) {
1906 // might not be the one stored in the network, might exist in the DES
1907 Circuits::OperationState &theClassicalState = GetState();
1908
1909 theClassicalState.Remap(qubitsMap);
1910 }
1911
1923 auto optimiser = controller->GetOptimiser();
1924 if (optimiser) {
1925 // convert the classical state results back to the expected order
1926 const auto &qubitsMap = optimiser->GetReverseQubitsMap();
1927
1928 ConvertBackResults(res, qubitsMap);
1929 }
1930 }
1931
1945 ExecuteResults &res,
1946 const std::unordered_map<Types::qubit_t, Types::qubit_t> &bitsMap) const {
1947 ExecuteResults translatedRes;
1948
1949 size_t numClassicalBits = 0;
1950 for (const auto &[q, b] : bitsMap)
1951 if (b >= numClassicalBits) numClassicalBits = b + 1;
1952
1953 numClassicalBits = std::max(numClassicalBits, GetNumClassicalBits());
1954
1955 for (const auto &r : res) {
1956 Circuits::OperationState translatedState(r.first);
1957
1958 translatedState.Remap(bitsMap, false, numClassicalBits);
1959 translatedRes[translatedState.GetAllBits()] = r.second;
1960 }
1961
1962 res.swap(translatedRes);
1963 }
1964
1976 std::unordered_map<Types::qubit_t, Types::qubit_t> MapCircuitOnHost(
1977 const std::shared_ptr<Circuits::Circuit<Time>> &circuit, size_t hostId,
1978 size_t &nrQubits, size_t &nrCbits, bool useSeparateSimForHosts = false) {
1979 qubitsMapOnHost.clear();
1980 nrQubits = 0;
1981 nrCbits = 0;
1982 if (!circuit) return {};
1983
1984 const auto host =
1985 std::static_pointer_cast<SimpleHost<Time>>(GetHost(hostId));
1986 const size_t hostNrQubits = host->GetNumQubits();
1987
1988 std::unordered_map<Types::qubit_t, Types::qubit_t> reverseQubitsMap;
1989
1990 if (!useSeparateSimForHosts) {
1991 size_t mxq = 0;
1992 size_t mnq = std::numeric_limits<size_t>::max();
1993 size_t mxb = 0;
1994 size_t mnb = std::numeric_limits<size_t>::max();
1995
1996 for (const auto &op : circuit->GetOperations()) {
1997 const auto qbits = op->AffectedQubits();
1998 for (auto q : qbits) {
1999 if (q > mxq) mxq = q;
2000 if (q < mnq) mnq = q;
2001 }
2002 const auto cbits = op->AffectedBits();
2003 for (auto b : cbits) {
2004 if (b > mxb) mxb = b;
2005 if (b < mnb) mnb = b;
2006 }
2007 }
2008
2009 if (mnq > mxq) mnq = 0;
2010 if (mnb > mxb) mnb = 0;
2011
2012 nrQubits = mxq - mnq + 1;
2013 nrCbits = mxb - mnb + 1;
2014 if (nrCbits < nrQubits) nrCbits = nrQubits;
2015
2016 const size_t startQubit = host->GetStartQubitId();
2017
2018 if (mnq < startQubit || mxq >= startQubit + hostNrQubits) {
2019 if (nrQubits >
2020 hostNrQubits +
2021 1) // the host has an additional 'special' qubit for the
2022 // entanglement or other operations (like those for cutting)
2023 throw std::runtime_error("Circuit does not fit on the host!");
2024
2025 for (size_t i = 0; i < nrCbits; ++i) {
2026 const size_t mapFrom = mnq + i;
2027 const size_t mapTo = startQubit + i;
2028
2029 qubitsMapOnHost[mapFrom] = mapTo;
2030 reverseQubitsMap[mapTo] = mapFrom;
2031 }
2032
2033 distCirc = std::static_pointer_cast<Circuits::Circuit<Time>>(
2034 circuit->Remap(qubitsMapOnHost, qubitsMapOnHost));
2035 }
2036
2037 return reverseQubitsMap;
2038 }
2039
2040 distCirc = circuit->RemapToContinuous(qubitsMapOnHost, reverseQubitsMap,
2041 nrQubits, nrCbits);
2042
2043 assert(nrQubits == qubitsMapOnHost.size());
2044
2045 if (nrQubits == 0) nrQubits = 1;
2046
2047 if (nrQubits >
2048 hostNrQubits +
2049 1) // the host has an additional 'special' qubit for the
2050 // entanglement or other operations (like those for cutting)
2051 throw std::runtime_error("Circuit does not fit on the host!");
2052
2053 return reverseQubitsMap;
2054 }
2055
2056 bool optimizeSimulator = true;
2058
2065 std::string maxBondDim;
2067 std::string mpsSample;
2068
2069 size_t maxSimulators = QC::QubitRegisterCalculator<>::
2070 GetNumberOfThreads();
2075 std::shared_ptr<Simulators::ISimulator>
2078 std::shared_ptr<Circuits::Circuit<Time>>
2081 std::shared_ptr<IController<Time>>
2083 // TODO: depending on the network topology, we will have adiacency lists, etc.
2084 // or simply a vector of hosts for a totally connected network (or where the
2085 // communication details do not matter so much)
2086 std::vector<std::shared_ptr<IHost<Time>>>
2089 std::unique_ptr<Estimators::SimulatorsEstimatorInterface<Time>>
2092 private:
2094 threadsPool;
2095 bool recreateIfNeeded =
2096 true;
2097 std::unordered_map<Types::qubit_t, Types::qubit_t>
2098 qubitsMapOnHost;
2101 const std::vector<std::string> *pauliStrings =
2102 nullptr;
2104};
2105
2106} // namespace Network
2107
2108#endif // !_SIMPLE_NETWORK_H_
Circuit class for holding the sequence of operations.
Definition Circuit.h:45
The operation interface.
Definition Operations.h:357
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:213
void AllocateBits(size_t numBits)
Allocate more bits.
Definition Operations.h:159
void Clear()
Clear the classical state.
Definition Operations.h:168
void SetResultsInOrder(const std::vector< bool > &results)
Set the classical bits.
Definition Operations.h:252
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:296
The controller host interface.
Definition Controller.h:105
The network interface.
Definition Network.h:56
std::unordered_set< SimulatorPair, boost::hash< SimulatorPair > > SimulatorsSet
Definition Network.h:62
std::shared_ptr< INetwork< Time > > getptr()
Get a shared pointer to this object.
Definition Network.h:733
typename Circuits::Circuit< Time >::ExecuteResults ExecuteResults
Definition Network.h:58
The simple network implementation.
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.
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.
typename BaseClass::ExecuteResults ExecuteResults
The execute results type.
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
Choose the best simulator for the given circuit.
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.
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:77
ThreadsPool class for holding and controlling a pool of threads.
Definition ThreadsPool.h:39
@ kGate
the usual quantum gate, result stays in simulator's state
NetworkType
The type of the network.
Definition Network.h:32
@ kSimpleDisconnectedNetwork
Simple network, no communication among hosts, sequential simulation.
SchedulerType
The type of the network scheduler for scheduling execution of multiple circuits.
Definition Controller.h:85
SimulationType
The type of simulation.
Definition State.h:79
@ kStatevector
statevector simulation type
@ kMatrixProductState
matrix product state simulation type
@ kStabilizer
Clifford gates simulation type.
@ kTensorNetwork
Tensor network simulation type.
SimulatorType
The type of simulator.
Definition State.h:63
@ kCompositeQCSim
composite qcsim simulator type
@ kQCSim
qcsim simulator type
@ kQiskitAer
qiskit aer simulator type
@ kCompositeQiskitAer
composite qiskit aer simulator type
@ kGpuSim
gpu simulator type
A way to pack together a circuit and the number of shots for its execution.
Definition Controller.h:60