15#ifndef _SIMPLE_NETWORK_H_
16#define _SIMPLE_NETWORK_H_
18#include "QubitRegister.h"
42 class Controller = SimpleController<Time>>
59 const std::vector<size_t> &cbits = {}) {
73 const std::vector<size_t> &cbits) {
74 size_t qubitsOffset = 0;
75 size_t cbitsOffset = 0;
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);
81 i, qubitsOffset, numQubits, cbitsOffset, numBits));
82 qubitsOffset += numQubits;
83 cbitsOffset += numBits;
86 for (
size_t i = 0; i <
hosts.size(); ++i) {
87 std::static_pointer_cast<SimpleHost<Time>>(
hosts[i])->SetEntangledQubitId(
89 std::static_pointer_cast<SimpleHost<Time>>(
hosts[i])
90 ->SetEntangledQubitMeasurementBit(cbitsOffset);
110 const auto recreate = recreateIfNeeded;
114 size_t numQubits = 2;
118 numQubits =
simulator->GetNumberOfQubits();
121 recreateIfNeeded =
false;
125 recreateIfNeeded = recreate;
129 const auto &first = *res.begin();
136 method !=
simulator->GetSimulationType() ||
137 simulator->GetNumberOfQubits() != numQubits))))
154 size_t hostId)
override {
155 const auto recreate = recreateIfNeeded;
159 size_t numQubits = 2;
163 numQubits =
simulator->GetNumberOfQubits();
166 recreateIfNeeded =
false;
170 recreateIfNeeded = recreate;
174 const auto &first = *res.begin();
181 method !=
simulator->GetSimulationType() ||
182 simulator->GetNumberOfQubits() != numQubits))))
203 const std::vector<std::string> &paulis)
override {
204 const auto recreate = recreateIfNeeded;
208 size_t numQubits = 2;
212 numQubits =
simulator->GetNumberOfQubits();
215 recreateIfNeeded =
false;
217 pauliStrings = &paulis;
219 pauliStrings =
nullptr;
221 recreateIfNeeded = recreate;
225 const auto &first = *res.begin();
229 std::vector<double> expectations(paulis.size());
232 const size_t numOps =
simulator->GetNumberOfQubits();
237 const auto &qubitsMap = optimiser->GetQubitsMap();
239 for (
size_t i = 0; i < paulis.size(); ++i) {
240 std::string translated(numOps,
'I');
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];
247 translated[j] = paulis[i][j];
250 expectations[i] =
simulator->ExpectationValue(translated);
253 for (
size_t i = 0; i < paulis.size(); ++i)
254 expectations[i] =
simulator->ExpectationValue(paulis[i]);
259 method !=
simulator->GetSimulationType() ||
260 simulator->GetNumberOfQubits() != numQubits))
283 const std::vector<std::string> &paulis)
override {
284 const auto recreate = recreateIfNeeded;
288 size_t numQubits = 2;
292 numQubits =
simulator->GetNumberOfQubits();
296 struct ScopedRestore {
298 const std::vector<std::string> **ps;
299 ScopedRestore(
bool &f,
const std::vector<std::string> **p)
300 : flag(f), saved(f), ps(p) {
307 } restoreGuard(recreateIfNeeded, &pauliStrings);
309 pauliStrings = &paulis;
314 const auto &first = *res.begin();
322 const size_t offsetBase = qubitsMapOnHost.size();
324 std::vector<double> expectations(paulis.size(), 1.);
327 const size_t numOps =
simulator->GetNumberOfQubits();
330 for (
size_t i = 0; i < paulis.size(); ++i) {
331 std::string translated(std::max(numOps, paulis[i].size()),
'I');
333 size_t offset = offsetBase;
335 for (
size_t j = 0; j < paulis[i].size(); ++j) {
336 auto pos = qubitsMapOnHost.find(j);
337 if (pos != qubitsMapOnHost.end())
338 translated[pos->second] = paulis[i][j];
340 translated[offset] = paulis[i][j];
347 expectations[i] =
simulator->ExpectationValue(translated);
350 throw std::runtime_error(
351 "ExecuteOnHostExpectations: no simulator available after execution.");
355 method !=
simulator->GetSimulationType() ||
356 simulator->GetNumberOfQubits() != numQubits))
375 size_t hostId)
override {
376 const auto recreate = recreateIfNeeded;
380 size_t numQubits = 2;
384 numQubits =
simulator->GetNumberOfQubits();
388 struct ScopedRestoreFlag {
390 ScopedRestoreFlag(
bool &f) : flag(f), saved(f) { flag =
false; }
391 ~ScopedRestoreFlag() { flag = saved; }
392 } restoreGuard(recreateIfNeeded);
397 const auto &first = *res.begin();
402 throw std::runtime_error(
403 "ExecuteOnHostAmplitudes: no simulator available after execution.");
405 std::vector<std::complex<double>> amplitudes;
406 const size_t n =
simulator->GetNumberOfQubits();
407 const size_t dim = 1ULL << n;
408 amplitudes.resize(dim);
409 for (
size_t state = 0; state < dim; ++state)
410 amplitudes[state] =
simulator->Amplitude(state);
414 if (!qubitsMapOnHost.empty()) {
415 const size_t offsetBase = qubitsMapOnHost.size();
419 std::vector<size_t> simToOrig(n);
420 size_t offset = offsetBase;
422 for (
size_t qbit = 0; qbit < n; ++qbit) {
423 auto pos = qubitsMapOnHost.find(qbit);
424 if (pos != qubitsMapOnHost.end())
425 simToOrig[pos->second] = pos->first;
427 simToOrig[qbit] = offset++;
430 std::vector<std::complex<double>> remapped(dim);
432 for (
size_t sim_state = 0; sim_state < dim; ++sim_state) {
433 size_t orig_state = 0;
434 for (
size_t qbit = 0; qbit < n; ++qbit) {
435 if (sim_state & (1ULL << qbit))
436 orig_state |= (1ULL << simToOrig[qbit]);
438 if (orig_state < dim) remapped[orig_state] = amplitudes[sim_state];
440 amplitudes.swap(remapped);
444 method !=
simulator->GetSimulationType() ||
445 simulator->GetNumberOfQubits() != numQubits))
466 size_t hostId)
override {
467 const auto recreate = recreateIfNeeded;
471 size_t numQubits = 2;
475 numQubits =
simulator->GetNumberOfQubits();
479 struct ScopedRestoreFlag {
481 ScopedRestoreFlag(
bool &f) : flag(f), saved(f) { flag =
false; }
482 ~ScopedRestoreFlag() { flag = saved; }
483 } restoreGuard(recreateIfNeeded);
488 const auto &first = *res.begin();
493 throw std::runtime_error(
494 "ExecuteOnHostProjectOnZero: no simulator available after "
497 const std::complex<double> result =
simulator->ProjectOnZero();
500 method !=
simulator->GetSimulationType() ||
501 simulator->GetNumberOfQubits() != numQubits))
522 size_t shots = 1000)
override {
529 for (
auto q :
distCirc->AffectedQubits()) {
532 <<
"This is a distributed circuit, using entanglement or cutting"
542 if (
distCirc->HasOpsAfterMeasurements() &&
548 distCirc->MoveMeasurementsAndResets();
550 auto method =
simulator->GetSimulationType();
552 const auto saveSimType = simType;
553 const auto saveMethod = method;
577 simulator->GetConfiguration(
"matrix_product_state_max_bond_dimension");
579 "matrix_product_state_truncation_threshold");
590 std::vector<bool> executed;
593 simType, method, executed);
606 !
distCirc->HasOpsAfterMeasurements()) ||
610 nrThreads = std::min(nrThreads, std::max<size_t>(shots, 1ULL));
612 std::mutex resultsMutex;
630 const size_t cntPerThread = std::max<size_t>(shots / nrThreads, 1ULL);
632 threadsPool.Resize(nrThreads);
633 threadsPool.SetFinishLimit(shots);
636 const size_t curCnt = std::min(cntPerThread, shots);
640 auto job = std::make_shared<ExecuteJob<Time>>(
641 dcirc, res, curCnt, nrQubits, nrQubits, nrCbitsResults, simType,
642 method, resultsMutex);
652 job->optSim = optSim->Clone();
653 job->executedGates = executed;
656 threadsPool.AddRunJob(std::move(job));
659 threadsPool.WaitForFinish();
662 const size_t curCnt = shots;
664 auto job = std::make_shared<ExecuteJob<Time>>(
665 dcirc, res, curCnt, nrQubits, nrQubits, nrCbitsResults, simType,
666 method, resultsMutex);
676 optSim->SetMultithreading(
true);
677 job->optSim = optSim;
678 job->executedGates = executed;
680 if (
simulator && method == saveMethod && simType == saveSimType) {
684 job->optSim = optSim;
686 optSim->GetNumberOfQubits());
687 job->executedGates.resize(
distCirc->size(),
694 if (!recreateIfNeeded)
simulator = job->optSim;
721 size_t shots = 1000)
override {
722 if (!circuit || hostId >=
GetNumHosts())
return {};
727 std::shared_ptr<Circuits::Circuit<Time>> optCircuit;
730 std::static_pointer_cast<Circuits::Circuit<Time>>(circuit->Clone());
731 optCircuit->Optimize();
734 GetController()->GetOptimizeCircuit() ? optCircuit : circuit, hostId,
735 nrQubits, nrCbits,
true);
736 if (nrCbits == 0) nrCbits = nrQubits;
743 simulator->GetConfiguration(
"matrix_product_state_max_bond_dimension");
745 "matrix_product_state_truncation_threshold");
748 if (
distCirc->HasOpsAfterMeasurements() &&
754 distCirc->MoveMeasurementsAndResets();
756 auto method =
simulator->GetSimulationType();
757 const auto saveSimType = simType;
758 const auto saveMethod = method;
785 std::vector<bool> executed;
787 nrCbits, simType, method, executed);
801 !
distCirc->HasOpsAfterMeasurements()) ||
805 nrThreads = std::min(nrThreads, std::max<size_t>(shots, 1ULL));
810 std::mutex resultsMutex;
818 const size_t cntPerThread = std::max<size_t>(shots / nrThreads, 1ULL);
820 threadsPool.Resize(nrThreads);
821 threadsPool.SetFinishLimit(shots);
824 const size_t curCnt = std::min(cntPerThread, shots);
827 auto job = std::make_shared<ExecuteJob<Time>>(
828 dcirc, res, curCnt, nrQubits, nrCbits, nrCbits, simType, method,
839 job->optSim = optSim->Clone();
840 job->executedGates = executed;
843 threadsPool.AddRunJob(std::move(job));
846 threadsPool.WaitForFinish();
849 const size_t curCnt = shots;
851 auto job = std::make_shared<ExecuteJob<Time>>(
852 dcirc, res, curCnt, nrQubits, nrCbits, nrCbits, simType, method,
863 optSim->SetMultithreading(
true);
864 job->optSim = optSim;
865 job->executedGates = executed;
869 if (!recreateIfNeeded)
simulator = job->optSim;
889 if (!circuit)
return 0;
891 size_t distgates = 0;
893 for (
const auto &op : circuit->GetOperations())
950 size_t nrQubits = 0)
override {
960 simulator->Configure(
"matrix_product_state_max_bond_dimension",
963 simulator->Configure(
"matrix_product_state_truncation_threshold",
985 void Configure(
const char *key,
const char *value)
override {
986 if (!key || !value)
return;
988 if (std::string(
"matrix_product_state_max_bond_dimension") == key)
990 else if (std::string(
"matrix_product_state_truncation_threshold") == key)
992 else if (std::string(
"mps_sample_measure_algorithm") == key)
994 else if (std::string(
"use_double_precision") == key)
996 (std::string(
"1") == value || std::string(
"true") == value);
997 else if (std::string(
"max_simulators") == key)
1052 std::shared_ptr<Schedulers::IScheduler<Time>>
GetScheduler()
const override {
1067 const std::shared_ptr<IHost<Time>>
GetHost(
size_t hostId)
const override {
1068 if (hostId >=
hosts.size())
return nullptr;
1070 return hosts[hostId];
1105 for (
const auto &host :
hosts) res += host->GetNumQubits();
1120 if (hostId >=
hosts.size())
return 0;
1122 return hosts[hostId]->GetNumQubits();
1136 for (
const auto &host :
hosts) res += host->GetNumNetworkEntangledQubits();
1154 if (hostId >=
hosts.size())
return 0;
1156 return hosts[hostId]->GetNumNetworkEntangledQubits();
1170 for (
const auto &host :
hosts) res += host->GetNumClassicalBits();
1187 if (hostId >=
hosts.size())
return 0;
1189 return hosts[hostId]->GetNumClassicalBits();
1228 const std::vector<uint8_t> &packet)
override {
1255 const auto qubits = op->AffectedQubits();
1257 if (qubits.empty())
return true;
1259 size_t firstQubit = qubits[0];
1261 for (
size_t q = 1; q < qubits.size(); ++q)
1281 const auto qubits = op->AffectedQubits();
1283 if (qubits.empty())
return false;
1287 size_t firstQubit = qubits[0];
1290 firstQubit = qubits[q];
1294 for (; q < qubits.size(); ++q)
1315 const auto qubits = op->AffectedQubits();
1317 if (qubits.empty())
return false;
1319 for (
size_t q = 0; q < qubits.size(); ++q)
1337 const auto qubits = op->AffectedQubits();
1338 if (qubits.size() != 2)
return false;
1356 if (!op->IsConditional())
return false;
1358 const auto qubits = op->AffectedQubits();
1360 const std::shared_ptr<Circuits::IConditionalOperation<Time>> condOp =
1361 std::static_pointer_cast<Circuits::IConditionalOperation<Time>>(op);
1362 const auto &classicalBits = condOp->GetCondition()->GetBitsIndices();
1364 if (qubits.empty() && classicalBits.empty())
1365 throw std::runtime_error(
1366 "No classical bits specified!");
1374 for (
const auto bit : classicalBits)
1392 if (!op->IsConditional())
1393 throw std::runtime_error(
"Operation is not conditional!");
1395 std::shared_ptr<Circuits::IConditionalOperation<Time>> condOp =
1396 std::static_pointer_cast<Circuits::IConditionalOperation<Time>>(op);
1397 const auto classicalBits = condOp->AffectedBits();
1399 if (classicalBits.empty())
1400 throw std::runtime_error(
"No classical bits specified!");
1414 for (
const auto &host :
hosts) {
1415 const bool present1 = host->IsQubitOnHost(qubitId1);
1416 const bool present2 = host->IsQubitOnHost(qubitId2);
1418 if (present1 && present2)
1420 else if (present1 || present2)
1437 for (
const auto &host :
hosts) {
1438 const bool present1 = host->IsClassicalBitOnHost(bitId1);
1439 const bool present2 = host->IsClassicalBitOnHost(bitId2);
1441 if (present1 && present2)
1443 else if (present1 || present2)
1461 size_t bitId)
const override {
1462 for (
const auto &host :
hosts) {
1463 const bool present1 = host->IsQubitOnHost(qubitId);
1464 const bool present2 = host->IsClassicalBitOnHost(bitId);
1466 if (present1 && present2)
1468 else if (present1 || present2)
1485 for (
const auto &host :
hosts)
1486 if (host->IsQubitOnHost(qubitId))
return host->GetId();
1488 return std::numeric_limits<size_t>::max();
1504 for (
const auto &host :
hosts)
1505 if (host->IsEntangledQubitOnHost(qubitId))
return host->GetId();
1507 return std::numeric_limits<size_t>::max();
1536 for (
const auto &host :
hosts)
1537 if (host->IsClassicalBitOnHost(classicalBitId))
return host->GetId();
1539 return std::numeric_limits<size_t>::max();
1551 if (hostId >=
hosts.size())
return std::vector<size_t>();
1553 return hosts[hostId]->GetQubitsIds();
1567 size_t hostId)
const override {
1568 if (hostId >=
hosts.size())
return std::vector<size_t>();
1570 return hosts[hostId]->GetNetworkEntangledQubitsIds();
1583 if (hostId >=
hosts.size())
return std::vector<size_t>();
1585 return hosts[hostId]->GetClassicalBitsIds();
1599 size_t hostId)
const override {
1600 if (hostId >=
hosts.size())
return std::vector<size_t>();
1602 return hosts[hostId]->GetEntangledQubitMeasurementBitIds();
1650 size_t qubitId2)
const override {
1667 throw std::runtime_error(
1668 "Entanglement between hosts is not supported in the simple network");
1683 throw std::runtime_error(
1684 "Entanglement between hosts is not supported in the simple network");
1697 throw std::runtime_error(
1698 "Entanglement between hosts is not supported in the simple network");
1763 else if (val > (
size_t)QC::QubitRegisterCalculator<>::GetNumberOfThreads())
1764 val = (size_t)QC::QubitRegisterCalculator<>::GetNumberOfThreads();
1872 std::shared_ptr<INetwork<Time>>
Clone()
const override {
1875 std::vector<Types::qubit_t> qubits(numHosts);
1876 std::vector<size_t> cbits(numHosts);
1878 for (
size_t h = 0; h < numHosts; ++h) {
1884 std::make_shared<SimpleDisconnectedNetwork<Time, Controller>>(qubits,
1903 size_t nrQubits,
size_t nrCbits,
size_t nrResultCbits,
1905 std::vector<bool> &executed,
bool multithreading =
false,
1906 bool dontRunCircuitStart =
false)
const override {
1917 std::pair<Simulators::SimulatorType, Simulators::SimulationType>>
1920 const bool checkTensorNetwork =
1936#ifndef NO_QISKIT_AER
1956 if (checkTensorNetwork &&
1966 simulatorTypes.emplace_back(
1982#ifndef NO_QISKIT_AER
1995 simulatorTypes.emplace_back(
2003 simulatorTypes.emplace_back(
2017 simulatorTypes.emplace_back(
2028 simulatorTypes.emplace_back(
2039 if (simulatorTypes.empty())
2041 else if (simulatorTypes.size() == 1) {
2042 simType = simulatorTypes[0].first;
2043 method = simulatorTypes[0].second;
2045 std::shared_ptr<Simulators::ISimulator> sim =
2050 sim->Configure(
"matrix_product_state_max_bond_dimension",
2053 sim->Configure(
"matrix_product_state_truncation_threshold",
2056 sim->Configure(
"mps_sample_measure_algorithm",
mpsSample.c_str());
2058 sim->AllocateQubits(nrQubits);
2063 sim->AllocateQubits(nrQubits);
2067 if (!dontRunCircuitStart) {
2068 sim->SetMultithreading(
true);
2070 Time>::ExecuteUpToMeasurements(dcirc, nrQubits, nrCbits,
2071 nrResultCbits, sim, executed);
2079 std::shared_ptr<Simulators::ISimulator> sim =
2081 simulatorTypes, dcirc, counts, nrQubits, nrCbits, nrResultCbits,
2086 sim->AllocateQubits(nrQubits);
2091 if (!dontRunCircuitStart) {
2092 sim->SetMultithreading(
true);
2094 dcirc, nrQubits, nrCbits, nrResultCbits, sim, executed);
2103 optimizeInitialQubitsMap = optimize;
2107 return optimizeInitialQubitsMap;
2111 mpsOptimizeSwaps = optimize;
2117 mpsOptimizationBondDimensionThreshold = threshold;
2121 return mpsOptimizationBondDimensionThreshold;
2125 mpsOptimizationQubitsNumberThreshold = threshold;
2129 return mpsOptimizationQubitsNumberThreshold;
2133 if (depth < 0) depth = std::numeric_limits<int>::max();
2135 lookaheadDepth = depth;
2141 if (depth < 0) depth = std::numeric_limits<int>::max();
2143 if (depth > lookaheadDepth) depth = lookaheadDepth;
2145 lookaheadDepthWithHeuristic = depth;
2149 return lookaheadDepthWithHeuristic;
2156 growthFactorSwap = factor;
2160 growthFactorGate = factor;
2165 std::shared_ptr<Simulators::ISimulator> &sim,
2167 if (sim->GetSimulationType() ==
2169 (optimizeInitialQubitsMap || mpsOptimizeSwaps) &&
2170 sim->SupportsMPSSwapOptimization()) {
2171 if (mpsOptimizationQubitsNumberThreshold <= nrQubits) {
2172 const auto maxBondDimValue =
2176 static_cast<int>(mpsOptimizationBondDimensionThreshold) <= maxBondDimValue) {
2178 dcirc->ConvertForCutting();
2179 auto layers = dcirc->ToMultipleQubitsLayersNoClone();
2188 if (optimizeInitialQubitsMap) {
2190 sim->SetInitialQubitsMap(optimalMap);
2194 dcirc->SetOperations(optCirc->GetOperations());
2196 if (mpsOptimizeSwaps) {
2198 int lookaheadDepthLocal = lookaheadDepth;
2200 if (lookaheadDepthLocal == std::numeric_limits<int>::max()) {
2201 double avgTwoQubitGatesPerLayer = 0.0;
2202 for (
const auto &layer : layers) {
2203 int twoQubitGates = 0;
2204 for (
const auto &op : layer->GetOperations()) {
2205 if (op->AffectedQubits().size() >= 2) {
2209 avgTwoQubitGatesPerLayer += twoQubitGates;
2211 avgTwoQubitGatesPerLayer /= layers.size();
2213 int lookaheadVal =
static_cast<int>(4. * avgTwoQubitGatesPerLayer);
2214 if (lookaheadVal > 15) lookaheadVal = 15;
2216 lookaheadDepthLocal = layers.size() < 10 || nrQubits <= 10 ? 0
2217 : layers.size() < 20
2218 ?
static_cast<int>(lookaheadVal)
2219 : layers.size() < 35
2220 ?
static_cast<int>(1.5 * lookaheadVal)
2224 int lookaheadHeuristicDepthLocal = lookaheadDepthWithHeuristic;
2226 if (lookaheadHeuristicDepthLocal == std::numeric_limits<int>::max())
2227 lookaheadHeuristicDepthLocal =
2228 layers.size() < 10 || nrQubits <= 10 ? 0
2229 : layers.size() < 20
2230 ? lookaheadDepthLocal - 1
2231 : lookaheadDepthLocal - 2;
2233 sim->setGrowthFactorGate(growthFactorGate);
2234 sim->setGrowthFactorSwap(growthFactorSwap);
2235 sim->SetUseOptimalMeetingPosition(
true);
2236 sim->SetLookaheadDepth(lookaheadDepthLocal);
2237 sim->SetLookaheadDepthWithHeuristic(lookaheadHeuristicDepthLocal);
2238 sim->SetUpcomingGates(dcirc->GetOperations());
2257 const auto &qubitsMap = optimiser->GetReverseQubitsMap();
2275 const std::unordered_map<Types::qubit_t, Types::qubit_t> &qubitsMap) {
2279 theClassicalState.
Remap(qubitsMap);
2296 const auto &qubitsMap = optimiser->GetReverseQubitsMap();
2316 const std::unordered_map<Types::qubit_t, Types::qubit_t> &bitsMap)
const {
2319 size_t numClassicalBits = 0;
2320 for (
const auto &[q, b] : bitsMap)
2321 if (b >= numClassicalBits) numClassicalBits = b + 1;
2325 for (
const auto &r : res) {
2328 translatedState.
Remap(bitsMap,
false, numClassicalBits);
2329 translatedRes[translatedState.
GetAllBits()] = r.second;
2332 res.swap(translatedRes);
2348 size_t &nrQubits,
size_t &nrCbits,
bool useSeparateSimForHosts =
false) {
2349 qubitsMapOnHost.clear();
2352 if (!circuit)
return {};
2355 std::static_pointer_cast<SimpleHost<Time>>(
GetHost(hostId));
2356 const size_t hostNrQubits = host->GetNumQubits();
2358 std::unordered_map<Types::qubit_t, Types::qubit_t> reverseQubitsMap;
2360 if (!useSeparateSimForHosts) {
2362 size_t mnq = std::numeric_limits<size_t>::max();
2364 size_t mnb = std::numeric_limits<size_t>::max();
2366 for (
const auto &op : circuit->GetOperations()) {
2367 const auto qbits = op->AffectedQubits();
2368 for (
auto q : qbits) {
2369 if (q > mxq) mxq = q;
2370 if (q < mnq) mnq = q;
2372 const auto cbits = op->AffectedBits();
2373 for (
auto b : cbits) {
2374 if (b > mxb) mxb = b;
2375 if (b < mnb) mnb = b;
2379 if (mnq > mxq) mnq = 0;
2380 if (mnb > mxb) mnb = 0;
2382 nrQubits = mxq - mnq + 1;
2383 nrCbits = mxb - mnb + 1;
2384 if (nrCbits < nrQubits) nrCbits = nrQubits;
2386 const size_t startQubit = host->GetStartQubitId();
2388 if (mnq < startQubit || mxq >= startQubit + hostNrQubits) {
2393 throw std::runtime_error(
"Circuit does not fit on the host!");
2395 for (
size_t i = 0; i < nrCbits; ++i) {
2396 const size_t mapFrom = mnq + i;
2397 const size_t mapTo = startQubit + i;
2399 qubitsMapOnHost[mapFrom] = mapTo;
2400 reverseQubitsMap[mapTo] = mapFrom;
2403 distCirc = std::static_pointer_cast<Circuits::Circuit<Time>>(
2404 circuit->Remap(qubitsMapOnHost, qubitsMapOnHost));
2407 return reverseQubitsMap;
2410 distCirc = circuit->RemapToContinuous(qubitsMapOnHost, reverseQubitsMap,
2413 assert(nrQubits == qubitsMapOnHost.size());
2415 if (nrQubits == 0) nrQubits = 1;
2421 throw std::runtime_error(
"Circuit does not fit on the host!");
2423 return reverseQubitsMap;
2441 GetNumberOfThreads();
2446 std::shared_ptr<Simulators::ISimulator>
2449 std::shared_ptr<Circuits::Circuit<Time>>
2452 std::shared_ptr<IController<Time>>
2457 std::vector<std::shared_ptr<IHost<Time>>>
2460 std::unique_ptr<Estimators::SimulatorsEstimatorInterface<Time>>
2466 bool recreateIfNeeded =
2468 std::unordered_map<Types::qubit_t, Types::qubit_t>
2472 const std::vector<std::string> *pauliStrings =
2476 bool optimizeInitialQubitsMap =
true;
2478 bool mpsOptimizeSwaps =
true;
2479 size_t mpsOptimizationBondDimensionThreshold =
2481 size_t mpsOptimizationQubitsNumberThreshold =
2484 int lookaheadDepth =
2485 std::numeric_limits<int>::max();
2487 int lookaheadDepthWithHeuristic = std::numeric_limits<int>::max();
2490 double growthFactorSwap = 1.;
2491 double growthFactorGate = 0.65;
int GetSimulationType(void *sim)
Circuit class for holding the sequence of operations.
static std::shared_ptr< Circuits::Circuit< Time > > LayersToCircuit(const std::vector< std::shared_ptr< Circuits::Circuit< Time > > > &layers)
Converts the layers back to a circuit.
The state class that stores the classical state of a quantum circuit execution.
const std::vector< bool > & GetAllBits() const
Get the classical bits.
void Clear()
Clear the classical state.
void SetResultsInOrder(const std::vector< bool > &results)
Set the classical bits.
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.
An interface for runtime estimators.
static void ExecuteUpToMeasurements(const std::shared_ptr< Circuits::Circuit< Time > > &dcirc, size_t nrQubits, size_t nrCbits, size_t nrResultCbits, const std::shared_ptr< Simulators::ISimulator > &sim, std::vector< bool > &executed)
The controller host interface.
std::shared_ptr< INetwork< Time > > getptr()
typename Circuits::Circuit< Time >::ExecuteResults ExecuteResults
std::unordered_set< SimulatorPair, boost::hash< SimulatorPair > > SimulatorsSet
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.
std::string singularValueThreshold
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.
typename BaseClass::ExecuteResults ExecuteResults
The execute results type.
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.
int GetLookaheadDepthWithHeuristic() const override
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.
void OptimizeMPSInitialQubitsMap(std::shared_ptr< Simulators::ISimulator > &sim, std::shared_ptr< Circuits::Circuit< Time > > &dcirc, size_t nrQubits) const
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 SetLookaheadDepthWithHeuristic(int depth) override
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.
void SetMPSOptimizeSwaps(bool optimize=true) override
void SetInitialQubitsMapOptimization(bool optimize=true) override
size_t GetMPSOptimizationBondDimensionThreshold() const override
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.
std::vector< double > ExecuteOnHostExpectations(const std::shared_ptr< Circuits::Circuit< Time > > &circuit, size_t hostId, const std::vector< std::string > &paulis) override
Execute the circuit on the specified host and return the expectation values for the specified Pauli s...
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.
std::complex< double > ExecuteOnHostProjectOnZero(const std::shared_ptr< Circuits::Circuit< Time > > &circuit, size_t hostId) override
Execute circuit on host and return the projection onto the zero state.
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.
BaseClass::SimulatorsSet simulatorsForOptimizations
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.
double getGrowthFactorSwap() const override
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.
void SetLookaheadDepth(int depth) override
bool GetInitialQubitsMapOptimization() 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 > ChooseBestSimulator(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< 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.
std::vector< std::complex< double > > ExecuteOnHostAmplitudes(const std::shared_ptr< Circuits::Circuit< Time > > &circuit, size_t hostId) override
Execute circuit on host and return full statevector amplitudes.
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.
void setGrowthFactorSwap(double factor) override
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.
bool GetMPSOptimizeSwaps() const override
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.
void SetMPSOptimizationQubitsNumberThreshold(size_t threshold) override
int GetLookaheadDepth() const override
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.
void setGrowthFactorGate(double factor) override
NetworkType GetType() const override
Get the type of the network.
void SetMPSOptimizationBondDimensionThreshold(size_t threshold) override
bool AreClassicalBitsOnSameHost(size_t bitId1, size_t bitId2) const override
Check if the specified classical bits are on the same host.
double getGrowthFactorGate() const override
size_t GetMPSOptimizationQubitsNumberThreshold() const override
The simple host implementation.
void setGrowthFactorSwap(double factor)
std::vector< long long int > ComputeOptimalQubitsMap(const std::vector< std::shared_ptr< Circuits::Circuit<> > > &layers, int nrShuffles=25, int nrSwaps=10)
void setGrowthFactorGate(double factor)
void SetMaxBondDimension(IndexType val)
static bool IsGpuLibraryAvailable()
static std::shared_ptr< ISimulator > CreateSimulator(SimulatorType t=SimulatorType::kQCSim, SimulationType method=SimulationType::kMatrixProductState)
Create a quantum computing simulator.
ThreadsPool class for holding and controlling a pool of threads.
@ kGate
the usual quantum gate, result stays in simulator's state
NetworkType
The type of the network.
@ kSimpleDisconnectedNetwork
Simple network, no communication among hosts, sequential simulation.
SchedulerType
The type of the network scheduler for scheduling execution of multiple circuits.
@ kNoEntanglementQubitsParallel
SimulationType
The type of simulation.
@ kStatevector
statevector simulation type
@ kMatrixProductState
matrix product state simulation type
@ kStabilizer
Clifford gates simulation type.
@ kPauliPropagator
Pauli propagator simulation type.
@ kTensorNetwork
Tensor network simulation type.
@ kPathIntegral
Path integral simulation type.
SimulatorType
The type of simulator.
@ kCompositeQCSim
composite qcsim simulator type
@ kQCSim
qcsim simulator type
@ kQiskitAer
qiskit aer simulator type
@ kQuestSim
quest simulator type
@ kCompositeQiskitAer
composite qiskit aer simulator type
@ kGpuSim
gpu simulator type
double time_type
The type of time.
A way to pack together a circuit and the number of shots for its execution.