15#ifndef _SIMPLE_NETWORK_H_
16#define _SIMPLE_NETWORK_H_
20#include "QubitRegister.h"
63 configuration.SetConfiguration(
"trajectory_policy",
"shot_v1");
102 void CreateNetwork(
const std::vector<Types::qubit_t> &qubits,
const std::vector<size_t> &cbits)
104 size_t qubitsOffset = 0;
105 size_t cbitsOffset = 0;
107 for (
size_t i = 0; i < qubits.size(); ++i)
109 const size_t numQubits = qubits[i];
110 const size_t numBits = (i < cbits.size() ? cbits[i] : 0);
111 hosts.emplace_back(std::make_shared<
SimpleHost<Time>>(i, qubitsOffset, numQubits, cbitsOffset, numBits));
112 qubitsOffset += numQubits;
113 cbitsOffset += numBits;
116 for (
size_t i = 0; i <
hosts.size(); ++i)
118 std::static_pointer_cast<SimpleHost<Time>>(
hosts[i])->SetEntangledQubitId(qubitsOffset);
119 std::static_pointer_cast<SimpleHost<Time>>(
hosts[i])->SetEntangledQubitMeasurementBit(cbitsOffset);
143 size_t numQubits = 2;
148 numQubits =
simulator->GetNumberOfQubits();
175 const auto &first = *res.begin();
180 simulator->GetNumberOfQubits() != numQubits))))
202 size_t numQubits = 2;
207 numQubits =
simulator->GetNumberOfQubits();
219 const auto &first = *res.begin();
224 simulator->GetNumberOfQubits() != numQubits))))
249 size_t numQubits = 2;
254 numQubits =
simulator->GetNumberOfQubits();
259 const auto cleanCircuit = circuit ? circuit->RemoveEndMeasurements() : circuit;
261 pauliStrings = &paulis;
263 pauliStrings =
nullptr;
270 const auto &first = *res.begin();
274 std::vector<double> expectations(paulis.size());
278 const size_t numOps =
simulator->GetNumberOfQubits();
284 const auto &qubitsMap = optimiser->GetQubitsMap();
285 std::vector<std::string> translatedPaulis;
286 translatedPaulis.reserve(paulis.size());
288 for (
size_t i = 0; i < paulis.size(); ++i)
290 std::string translated(numOps,
'I');
292 for (
size_t j = 0; j < paulis[i].size(); ++j)
294 const auto pos = qubitsMap.find(j);
295 if (pos != qubitsMap.end())
296 translated[pos->second] = paulis[i][j];
298 translated[j] = paulis[i][j];
301 translatedPaulis.push_back(std::move(translated));
303 expectations =
simulator->ExpectationValues(translatedPaulis);
307 expectations =
simulator->ExpectationValues(paulis);
334 const std::vector<std::string> &paulis)
override
340 size_t numQubits = 2;
345 numQubits =
simulator->GetNumberOfQubits();
352 const std::vector<std::string> **ps;
354 ScopedRestore(
bool &f,
const std::vector<std::string> **p) : flag(f), saved(f), ps(p)
366 const auto cleanCircuit = circuit ? circuit->RemoveEndMeasurements() : circuit;
368 pauliStrings = &paulis;
374 const auto &first = *res.begin();
382 const size_t offsetBase = qubitsMapOnHost.size();
384 std::vector<double> expectations(paulis.size(), 1.);
388 const size_t numOps =
simulator->GetNumberOfQubits();
391 std::vector<std::string> translatedPaulis;
392 translatedPaulis.reserve(paulis.size());
393 for (
size_t i = 0; i < paulis.size(); ++i)
395 std::string translated(std::max(numOps, paulis[i].size()),
'I');
397 size_t offset = offsetBase;
399 for (
size_t j = 0; j < paulis[i].size(); ++j)
401 auto pos = qubitsMapOnHost.find(j);
402 if (pos != qubitsMapOnHost.end())
403 translated[pos->second] = paulis[i][j];
406 translated[offset] = paulis[i][j];
413 translatedPaulis.push_back(std::move(translated));
415 expectations =
simulator->ExpectationValues(translatedPaulis);
419 throw std::runtime_error(
"ExecuteOnHostExpectations: no simulator available after execution.");
447 size_t numQubits = 2;
452 numQubits =
simulator->GetNumberOfQubits();
456 struct ScopedRestoreFlag
460 ScopedRestoreFlag(
bool &f) : flag(f), saved(f)
475 const auto &first = *res.begin();
480 throw std::runtime_error(
"ExecuteOnHostAmplitudes: no simulator available after execution.");
482 const size_t n =
simulator->GetNumberOfQubits();
483 auto amplitudes =
simulator->GetStateVector();
484 const size_t dim = amplitudes.size();
488 if (!qubitsMapOnHost.empty())
492 std::vector<std::pair<Types::qubit_t, Types::qubit_t>> byOriginal(qubitsMapOnHost.begin(), qubitsMapOnHost.end());
493 std::sort(byOriginal.begin(), byOriginal.end());
495 std::vector<size_t> simToOrig(n);
496 for (
size_t pos = 0; pos < byOriginal.size(); ++pos)
497 simToOrig[byOriginal[pos].second] = pos;
499 std::vector<std::complex<double>> remapped(dim);
501 for (
size_t sim_state = 0; sim_state < dim; ++sim_state)
503 size_t orig_state = 0;
504 for (
size_t qbit = 0; qbit < n; ++qbit)
506 if (sim_state & (1ULL << qbit))
507 orig_state |= (1ULL << simToOrig[qbit]);
509 if (orig_state < dim)
510 remapped[orig_state] = amplitudes[sim_state];
512 amplitudes.swap(remapped);
541 size_t numQubits = 2;
546 numQubits =
simulator->GetNumberOfQubits();
550 struct ScopedRestoreFlag
554 ScopedRestoreFlag(
bool &f) : flag(f), saved(f)
569 const auto &first = *res.begin();
574 throw std::runtime_error(
"ExecuteOnHostProjectOnZero: no simulator available after "
577 const std::complex<double> result =
simulator->ProjectOnZero();
609 for (
auto q :
distCirc->AffectedQubits())
613 std::cout <<
"This is a distributed circuit, using entanglement or cutting" << std::endl;
623 if (
distCirc->HasOpsAfterMeasurements() && (
628 distCirc->MoveMeasurementsAndResets();
630 auto method =
simulator->GetSimulationType();
632 const auto saveSimType = simType;
633 const auto saveMethod = method;
669 std::vector<bool> executed;
688 !
distCirc->HasOpsAfterMeasurements()) ||
692 nrThreads = std::min(nrThreads, std::max<size_t>(shots, 1ULL));
694 std::mutex resultsMutex;
698 if (reproducibleSampling && dcirc->HasOpsAfterMeasurements() &&
699 (shots > 1 || (shots == 1 &&
configuration.GetConfiguration(
"trajectory_policy") ==
"shot_v1")))
701 ExecuteLogicalShotBlocks(dcirc, res, shots, nrThreads, nrQubits, nrCbits, nrCbitsResults, simType, method, optSim, executed, resultsMutex);
703 else if (nrThreads > 1)
707 optSim->SetMultithreading(
false);
719 const size_t cntPerThread = std::max<size_t>(shots / nrThreads, 1ULL);
721 threadsPool.Resize(nrThreads);
722 threadsPool.SetFinishLimit(shots);
724 uint64_t jobStream = 0;
727 const size_t curCnt = std::min(cntPerThread, shots);
731 auto job = std::make_shared<ExecuteJob<Time>>(dcirc, res, curCnt, nrQubits, nrCbits, nrCbitsResults, simType, method, resultsMutex);
739 job->curMaxBondDim = &curMaxBondDim;
742 job->randomStream = jobStream++;
746 job->config.SetConfiguration(
"seed", std::to_string(childSeed));
751 job->optSim = optSim->Clone();
752 job->executedGates = executed;
753 if (job->config.IsSet(
"seed"))
754 job->optSim->SetSeed(std::stoull(job->config.GetConfiguration(
"seed")));
757 threadsPool.AddRunJob(std::move(job));
762 threadsPool.WaitForFinish();
766 const size_t curCnt = shots;
768 auto job = std::make_shared<ExecuteJob<Time>>(dcirc, res, curCnt, nrQubits, nrCbits, nrCbitsResults, simType, method, resultsMutex);
776 job->curMaxBondDim = &curMaxBondDim;
782 optSim->SetMultithreading(
true);
783 job->optSim = optSim;
784 job->executedGates = executed;
788 if (
simulator && method == saveMethod && simType == saveSimType)
792 job->optSim = optSim;
793 if (optSim->GetNumberOfQubits() == nrQubits)
798 optSim->SetGatesCounter(0);
800 job->config.ApplyConfigurationToSimulator(optSim);
805 job->executedGates.resize(dcirc->size(),
812 lastGpuDevice = job->optSim ? job->optSim->GetGpuDevice() : -1;
849 auto mappingCircuit = circuit;
852 mappingCircuit = std::static_pointer_cast<Circuits::Circuit<Time>>(circuit->Clone());
853 mappingCircuit->Optimize();
855 const auto reverseQubitsMap =
MapCircuitOnHost(mappingCircuit, hostId, nrQubits, nrCbits,
true);
870 if (
distCirc->HasOpsAfterMeasurements() && (
875 distCirc->MoveMeasurementsAndResets();
877 auto method =
simulator->GetSimulationType();
878 const auto saveSimType = simType;
879 const auto saveMethod = method;
908 std::vector<bool> executed;
927 !
distCirc->HasOpsAfterMeasurements()) ||
931 nrThreads = std::min(nrThreads, std::max<size_t>(shots, 1ULL));
936 std::mutex resultsMutex;
940 if (reproducibleSampling && dcirc->HasOpsAfterMeasurements() &&
941 (shots > 1 || (shots == 1 &&
configuration.GetConfiguration(
"trajectory_policy") ==
"shot_v1")))
943 ExecuteLogicalShotBlocks(dcirc, res, shots, nrThreads, nrQubits, nrCbits, nrCbits, simType, method, optSim, executed, resultsMutex);
945 else if (nrThreads > 1)
949 optSim->SetMultithreading(
false);
954 const size_t cntPerThread = std::max<size_t>(shots / nrThreads, 1ULL);
956 threadsPool.Resize(nrThreads);
957 threadsPool.SetFinishLimit(shots);
959 uint64_t jobStream = 0;
962 const size_t curCnt = std::min(cntPerThread, shots);
965 auto job = std::make_shared<ExecuteJob<Time>>(dcirc, res, curCnt, nrQubits, nrCbits, nrCbits, simType, method, resultsMutex);
973 job->curMaxBondDim = &curMaxBondDim;
976 job->randomStream = jobStream++;
980 job->config.SetConfiguration(
"seed", std::to_string(childSeed));
985 job->optSim = optSim->Clone();
986 job->executedGates = executed;
987 if (job->config.IsSet(
"seed"))
988 job->optSim->SetSeed(std::stoull(job->config.GetConfiguration(
"seed")));
991 threadsPool.AddRunJob(std::move(job));
996 threadsPool.WaitForFinish();
1000 const size_t curCnt = shots;
1002 auto job = std::make_shared<ExecuteJob<Time>>(dcirc, res, curCnt, nrQubits, nrCbits, nrCbits, simType, method, resultsMutex);
1010 job->curMaxBondDim = &curMaxBondDim;
1016 optSim->SetMultithreading(
true);
1017 job->optSim = optSim;
1018 job->executedGates = executed;
1020 else if (
simulator && method == saveMethod && simType == saveSimType)
1023 job->optSim = optSim;
1024 if (optSim->GetNumberOfQubits() == nrQubits)
1029 optSim->SetGatesCounter(0);
1030 job->config.ApplyConfigurationToSimulator(optSim);
1034 job->executedGates.resize(dcirc->size(),
false);
1037 job->DoWorkNoLock();
1038 lastGpuDevice = job->optSim ? job->optSim->GetGpuDevice() : -1;
1046 if (!reverseQubitsMap.empty())
1065 size_t distgates = 0;
1067 for (
const auto &op : circuit->GetOperations())
1136 simulator->AllocateQubits(allocationQubits);
1148 simulator->setGrowthFactorGate(growthFactorGate);
1149 simulator->setGrowthFactorSwap(growthFactorSwap);
1150 simulator->SetLookaheadDepth(lookaheadDepth);
1151 simulator->SetLookaheadDepthWithHeuristic(lookaheadDepthWithHeuristic);
1169 if (std::string(
"trajectory_policy") == key)
1171 const std::string policy(value);
1172 if (policy !=
"block_v1" && policy !=
"shot_v1")
1173 throw std::invalid_argument(
"trajectory_policy must be block_v1 or shot_v1");
1175 if (std::string(
"trajectory_max_memory_mb") == key)
1178 const std::string_view text(value);
1179 const auto parsed = std::from_chars(text.data(), text.data() + text.size(), mb);
1180 if (parsed.ec != std::errc{} || parsed.ptr != text.data() + text.size() || !mb || mb > (std::numeric_limits<size_t>::max() >> 20))
1181 throw std::invalid_argument(
"trajectory_max_memory_mb must be a positive representable MiB count");
1184 if (std::string(
"gate_fusion") == key)
1186 const std::string setting(value);
1187 if (setting !=
"true" && setting !=
"false" && setting !=
"0" && setting !=
"1" && setting !=
"auto")
1188 throw std::invalid_argument(
"gate_fusion must be true, false, 1, 0 or auto");
1195 if (std::string(
"distributed_host_qubit_indexing") == key)
1197 const std::string mode(value);
1198 if (mode !=
"auto" && mode !=
"local" && mode !=
"global")
1199 throw std::invalid_argument(
"distributed_host_qubit_indexing must be auto, local or global");
1204 if (std::string(
"distributed_devices") == key || std::string(
"gpu_device") == key)
1207 if (std::string(
"max_simulators") == key)
1210 if (std::string(
"gpu_device") == key)
1284 std::shared_ptr<Schedulers::IScheduler<Time>>
GetScheduler()
const override
1301 const std::shared_ptr<IHost<Time>>
GetHost(
size_t hostId)
const override
1303 if (hostId >=
hosts.size())
1306 return hosts[hostId];
1331 return hosts.size();
1346 for (
const auto &host :
hosts)
1347 res += host->GetNumQubits();
1363 if (hostId >=
hosts.size())
1366 return hosts[hostId]->GetNumQubits();
1381 for (
const auto &host :
hosts)
1382 res += host->GetNumNetworkEntangledQubits();
1401 if (hostId >=
hosts.size())
1404 return hosts[hostId]->GetNumNetworkEntangledQubits();
1419 for (
const auto &host :
hosts)
1420 res += host->GetNumClassicalBits();
1438 if (hostId >=
hosts.size())
1441 return hosts[hostId]->GetNumClassicalBits();
1483 bool SendPacket(
size_t fromHostId,
size_t toHostId,
const std::vector<uint8_t> &packet)
override
1512 const auto qubits = op->AffectedQubits();
1517 size_t firstQubit = qubits[0];
1519 for (
size_t q = 1; q < qubits.size(); ++q)
1540 const auto qubits = op->AffectedQubits();
1547 size_t firstQubit = qubits[0];
1550 firstQubit = qubits[q];
1554 for (; q < qubits.size(); ++q)
1574 const auto qubits = op->AffectedQubits();
1579 for (
size_t q = 0; q < qubits.size(); ++q)
1599 const auto qubits = op->AffectedQubits();
1600 if (qubits.size() != 2)
1618 if (!op->IsConditional())
1621 const auto qubits = op->AffectedQubits();
1623 const std::shared_ptr<Circuits::IConditionalOperation<Time>> condOp = std::static_pointer_cast<Circuits::IConditionalOperation<Time>>(op);
1624 const auto &classicalBits = condOp->GetCondition()->GetBitsIndices();
1626 if (qubits.empty() && classicalBits.empty())
1627 throw std::runtime_error(
"No classical bits specified!");
1635 for (
const auto bit : classicalBits)
1654 if (!op->IsConditional())
1655 throw std::runtime_error(
"Operation is not conditional!");
1657 std::shared_ptr<Circuits::IConditionalOperation<Time>> condOp = std::static_pointer_cast<Circuits::IConditionalOperation<Time>>(op);
1658 const auto classicalBits = condOp->AffectedBits();
1660 if (classicalBits.empty())
1661 throw std::runtime_error(
"No classical bits specified!");
1676 for (
const auto &host :
hosts)
1678 const bool present1 = host->IsQubitOnHost(qubitId1);
1679 const bool present2 = host->IsQubitOnHost(qubitId2);
1681 if (present1 && present2)
1683 else if (present1 || present2)
1701 for (
const auto &host :
hosts)
1703 const bool present1 = host->IsClassicalBitOnHost(bitId1);
1704 const bool present2 = host->IsClassicalBitOnHost(bitId2);
1706 if (present1 && present2)
1708 else if (present1 || present2)
1727 for (
const auto &host :
hosts)
1729 const bool present1 = host->IsQubitOnHost(qubitId);
1730 const bool present2 = host->IsClassicalBitOnHost(bitId);
1732 if (present1 && present2)
1734 else if (present1 || present2)
1752 for (
const auto &host :
hosts)
1753 if (host->IsQubitOnHost(qubitId))
1754 return host->GetId();
1756 return std::numeric_limits<size_t>::max();
1773 for (
const auto &host :
hosts)
1774 if (host->IsEntangledQubitOnHost(qubitId))
1775 return host->GetId();
1777 return std::numeric_limits<size_t>::max();
1808 for (
const auto &host :
hosts)
1809 if (host->IsClassicalBitOnHost(classicalBitId))
1810 return host->GetId();
1812 return std::numeric_limits<size_t>::max();
1825 if (hostId >=
hosts.size())
1826 return std::vector<size_t>();
1828 return hosts[hostId]->GetQubitsIds();
1843 if (hostId >=
hosts.size())
1844 return std::vector<size_t>();
1846 return hosts[hostId]->GetNetworkEntangledQubitsIds();
1860 if (hostId >=
hosts.size())
1861 return std::vector<size_t>();
1863 return hosts[hostId]->GetClassicalBitsIds();
1878 if (hostId >=
hosts.size())
1879 return std::vector<size_t>();
1881 return hosts[hostId]->GetEntangledQubitMeasurementBitIds();
1951 throw std::runtime_error(
"Entanglement between hosts is not supported in the simple network");
1967 throw std::runtime_error(
"Entanglement between hosts is not supported in the simple network");
1981 throw std::runtime_error(
"Entanglement between hosts is not supported in the simple network");
2024 const auto &options =
simulator->GetConfigMap();
2025 const auto found = options.find(
"gate_fusion");
2026 if (found != options.end())
2027 return found->second !=
"false" && found->second !=
"0";
2031 const auto value =
configuration.GetConfiguration(
"gate_fusion");
2032 return value !=
"false" && value !=
"0";
2082 else if (val > (
size_t)QC::QubitRegisterCalculator<>::GetNumberOfThreads())
2083 val = (size_t)QC::QubitRegisterCalculator<>::GetNumberOfThreads();
2216 std::shared_ptr<INetwork<Time>>
Clone()
const override
2220 std::vector<Types::qubit_t> qubits(numHosts);
2221 std::vector<size_t> cbits(numHosts);
2223 for (
size_t h = 0; h < numHosts; ++h)
2229 const auto cloned = std::make_shared<SimpleDisconnectedNetwork<Time, Controller>>(qubits, cbits);
2240 cloned->GetController()->SetOptimizeCircuit(
GetController()->GetOptimizeCircuit());
2241 cloned->GetController()->SetOptimizeRotationGates(
GetController()->GetOptimizeRotationGates());
2264 bool dontRunCircuitStart =
false)
override
2279 std::vector<std::pair<Simulators::SimulatorType, Simulators::SimulationType>> simulatorTypes;
2295#ifndef NO_QISKIT_AER
2312 const long long int maxBondDim =
configuration.GetConfigurationAsInt(
"matrix_product_state_max_bond_dimension");
2315 (nrQubits <= 4 || maxBondDim > 0))
2324#ifndef NO_QISKIT_AER
2336 (nrQubits <= 4 || maxBondDim > 0))
2342 : Simulators::SimulatorsFactory::ResolveGpuDevice();
2343 Simulators::SimulatorsFactory::ScopedGpuDevice gpuDeviceScope(gpuDevice);
2345 [](
const auto &candidate) { return candidate.first == Simulators::SimulatorType::kGpuSim; });
2347 throw std::runtime_error(
"Unable to initialize requested GPU device " + std::to_string(gpuDevice));
2374 simulatorTypes.push_back(candidate);
2377 if (simulatorTypes.empty())
2379 else if (simulatorTypes.size() == 1)
2381 const auto candidateType = simulatorTypes[0].first;
2382 const auto candidateMethod = simulatorTypes[0].second;
2387 simType = candidateType;
2388 method = candidateMethod;
2393 sim->AllocateQubits(nrQubits);
2396 sim->setGrowthFactorGate(growthFactorGate);
2397 sim->setGrowthFactorSwap(growthFactorSwap);
2398 sim->SetLookaheadDepth(lookaheadDepth);
2399 sim->SetLookaheadDepthWithHeuristic(lookaheadDepthWithHeuristic);
2405 sim->AllocateQubits(nrQubits);
2409 if (!dontRunCircuitStart)
2412 sim->Configure(
"reproducible_trajectory", dcirc->HasOpsAfterMeasurements() ?
"true" :
"false");
2413 sim->SetMultithreading(
true);
2428 const double singularValueThreshold =
configuration.GetConfigurationAsDouble(
"matrix_product_state_truncation_threshold");
2430 const std::string truncationMode =
configuration.GetConfiguration(
"matrix_product_state_truncation_mode");
2432 const std::string mpsSample =
configuration.GetConfiguration(
"mps_sample_measure_algorithm");
2434 std::shared_ptr<Simulators::ISimulator> sim =
2435 simulatorsEstimator->ChooseBestSimulator(simulatorTypes, dcirc, counts, nrQubits, nrCbits, nrResultCbits, simType, method, executed, maxBondDim,
2436 singularValueThreshold, truncationMode, mpsSample,
GetMaxSimulators(), pauliStrings, multithreading);
2440 sim->AllocateQubits(nrQubits);
2443 sim->setGrowthFactorGate(growthFactorGate);
2444 sim->setGrowthFactorSwap(growthFactorSwap);
2445 sim->SetLookaheadDepth(lookaheadDepth);
2446 sim->SetLookaheadDepthWithHeuristic(lookaheadDepthWithHeuristic);
2450 if (!dontRunCircuitStart)
2453 sim->Configure(
"reproducible_trajectory", dcirc->HasOpsAfterMeasurements() ?
"true" :
"false");
2454 sim->SetMultithreading(
true);
2465 optimizeInitialQubitsMap = optimize;
2470 return optimizeInitialQubitsMap;
2475 mpsOptimizeSwaps = optimize;
2480 simulator->SetLookaheadDepthWithHeuristic(0);
2486 return mpsOptimizeSwaps;
2491 mpsOptimizationBondDimensionThreshold = threshold;
2493 if (
simulator && std::stoull(
simulator->GetConfiguration(
"matrix_product_state_max_bond_dimension")) < threshold)
2496 simulator->SetLookaheadDepthWithHeuristic(0);
2502 return mpsOptimizationBondDimensionThreshold;
2507 mpsOptimizationQubitsNumberThreshold = threshold;
2512 simulator->SetLookaheadDepthWithHeuristic(0);
2518 return mpsOptimizationQubitsNumberThreshold;
2524 depth = std::numeric_limits<int>::max();
2526 lookaheadDepth = depth;
2528 if (
simulator && lookaheadDepth != std::numeric_limits<int>::max())
2531 if (lookaheadDepthWithHeuristic != std::numeric_limits<int>::max())
2532 simulator->SetLookaheadDepthWithHeuristic(std::min(depth, lookaheadDepthWithHeuristic));
2538 return lookaheadDepth;
2544 depth = std::numeric_limits<int>::max();
2546 if (depth > lookaheadDepth)
2547 depth = lookaheadDepth;
2549 lookaheadDepthWithHeuristic = depth;
2551 if (
simulator && lookaheadDepthWithHeuristic != std::numeric_limits<int>::max())
2552 simulator->SetLookaheadDepthWithHeuristic(depth);
2557 return lookaheadDepthWithHeuristic;
2562 return growthFactorSwap;
2567 return growthFactorGate;
2572 growthFactorSwap = factor;
2580 growthFactorGate = factor;
2594 return curMaxBondDim;
2602 const auto requested =
configuration.GetConfiguration(
"distributed_devices");
2605 configuration.SetConfiguration(
"distributed_devices", requested);
2626 const std::shared_ptr<Simulators::ISimulator> &prepared,
const std::vector<bool> &executed, std::mutex &resultsMutex)
2630 const bool independentShots =
configuration.GetConfiguration(
"trajectory_policy") ==
"shot_v1";
2631 workers = std::max<size_t>(1, workers);
2634 int threadBudget = omp_in_parallel() ? 1 : std::max(1, omp_get_max_threads());
2635 workers = std::min(workers,
static_cast<size_t>(threadBudget));
2640 if (qubits <= (std::numeric_limits<size_t>::digits - 5) / bitsPerQubit)
2642 const size_t elements =
size_t{1} << (bitsPerQubit * qubits);
2643 const size_t bytes = elements *
sizeof(std::complex<double>);
2645 configuration.IsSet(
"trajectory_max_memory_mb") ? std::stoull(
configuration.GetConfiguration(
"trajectory_max_memory_mb")) : 1024;
2646 const size_t slots = (mb << 20) / bytes;
2649 const size_t memoryWorkers = prepared ? (slots > 2 ? slots - 2 : 1) : slots / 2;
2650 workers = std::min(workers, std::max<size_t>(1, memoryWorkers));
2660 if (elements >= (
size_t{1} << 20))
2662 threadBudget = std::min(threadBudget, std::max(1, QC::QubitRegisterCalculator<>::GetParallelTeamSize(elements)));
2663 workers = std::min(workers,
static_cast<size_t>(std::max(1, threadBudget / 4)));
2676 const size_t blockSize = independentShots ? std::min<size_t>(256, std::max<size_t>(1, shots / workers + (shots % workers != 0))) : 256;
2679 const auto cloneMutex = std::make_shared<std::mutex>();
2684 simulator->GetSimulationType() == method &&
simulator->GetNumberOfQubits() == qubits;
2686 prepared->SetMultithreading(
false);
2689 workers = std::max<size_t>(1, std::min(workers, shots / blockSize + (shots % blockSize != 0)));
2692 threadsPool.Resize(workers);
2693 threadsPool.SetFinishLimit(shots);
2698 int internalThreads = 1;
2701 internalThreads =
static_cast<int>(std::max<size_t>(1,
static_cast<size_t>(threadBudget) / workers));
2703#if defined(_OPENMP) && defined(_MSC_VER) && !defined(__clang__) && !defined(_OPENMP_LLVM_RUNTIME)
2706 struct RestoreThreadLimit
2708 const int previous = omp_get_max_threads();
2710 ~RestoreThreadLimit()
2712 omp_set_num_threads(previous);
2714 } restoreThreadLimit;
2716 omp_set_num_threads(internalThreads);
2718 std::shared_ptr<ExecuteJob<Time>> last;
2719 for (
size_t begin = 0, block = 0; begin < shots; ++block)
2721 const size_t count = std::min(blockSize, shots - begin);
2722 auto job = std::make_shared<ExecuteJob<Time>>(circuit, results, count, qubits, cbits, resultBits, type, method, resultsMutex);
2728#if defined(_OPENMP) && defined(_MSC_VER) && !defined(__clang__) && !defined(_OPENMP_LLVM_RUNTIME)
2729 job->internalThreads = 0;
2731 job->internalThreads = internalThreads;
2733 job->allowInternalMultithreading = internalThreads > 1;
2739 job->curMaxBondDim = &curMaxBondDim;
2742 job->randomStream = block;
2743 job->independentShotStreams = independentShots;
2745 job->firstShot = begin;
2746 job->cloneSource = prepared;
2747 job->cloneMutex = cloneMutex;
2748 job->executedGates = executed;
2749 if (continueExecution)
2752 job->config.ApplyConfigurationToSimulator(job->optSim);
2753 job->executedGates.assign(circuit->size(),
false);
2757 threadsPool.AddRunJob(std::move(job));
2763 threadsPool.WaitForFinish();
2773 const std::vector<bool> &executed)
const
2776 return std::numeric_limits<size_t>::max();
2778 if (qubits > (std::numeric_limits<size_t>::digits - 5) / bitsPerQubit)
2779 return std::numeric_limits<size_t>::max();
2780 const double elements =
static_cast<double>(
size_t{1} << (bitsPerQubit * qubits));
2781 const size_t done =
static_cast<size_t>(std::count(executed.begin(), executed.end(),
true));
2782 const double ops =
static_cast<double>(circuit->size() > done ? circuit->size() - done : 1);
2783 const double micros =
static_cast<double>(shots) * (6. + 0.4e-3 * ops * elements);
2791 result.SetConfiguration(
"reproducible_trajectory",
distCirc &&
distCirc->HasOpsAfterMeasurements() ?
"true" :
"false");
2796 auto devices = found->second;
2802 for (
char c : devices)
2806 for (
size_t n = count; n > 1; n >>= 1)
2808 while (count > 1 && bits >= qubits)
2814 for (
size_t i = 0; i < count; ++i)
2816 end = devices.find(
',', end);
2817 if (end == std::string::npos)
2822 devices = devices.substr(0, end);
2824 result.SetConfiguration(
"distributed_devices", devices);
2832 (optimizeInitialQubitsMap || mpsOptimizeSwaps) && sim->SupportsMPSSwapOptimization() && !dcirc->HasCompositeOperations())
2837 if (mpsOptimizationQubitsNumberThreshold <= routedQubits)
2839 const auto maxBondDimValue =
2841 configuration.IsSet(
"matrix_product_operator_max_bond_dimension")
2842 ?
"matrix_product_operator_max_bond_dimension"
2843 :
"matrix_product_state_max_bond_dimension");
2845 if (maxBondDimValue <= 0 ||
static_cast<int>(mpsOptimizationBondDimensionThreshold) <= maxBondDimValue)
2848 dcirc->ConvertForCutting();
2849 auto layers = dcirc->ToMultipleQubitsLayersNoClone();
2853 dcirc->SetOperations(ordered->GetOperations());
2854 sim->SetUpcomingGates(dcirc->GetOperations());
2855 if (sim->IsGateFusionEnabled())
2858 for (
const auto &op : sim->GetUpcomingRoutingOperations())
2869 if (maxBondDimValue > 0)
2879 if (optimizeInitialQubitsMap)
2882 sim->SetInitialQubitsMap(optimalMap);
2885 if (mpsOptimizeSwaps)
2887 int lookaheadDepthLocal = lookaheadDepth;
2889 if (lookaheadDepthLocal == std::numeric_limits<int>::max())
2891 double avgTwoQubitGatesPerLayer = 0.0;
2892 for (
const auto &layer : layers)
2894 int twoQubitGates = 0;
2895 for (
const auto &op : layer->GetOperations())
2897 if (op->AffectedQubits().size() >= 2)
2902 avgTwoQubitGatesPerLayer += twoQubitGates;
2904 if (!layers.empty())
2905 avgTwoQubitGatesPerLayer /= layers.size();
2907 int lookaheadVal =
static_cast<int>(4. * avgTwoQubitGatesPerLayer);
2908 if (lookaheadVal > 15)
2911 lookaheadDepthLocal = layers.size() < 8 || routedQubits <= 10 ? 0
2912 : layers.size() < 15 ?
static_cast<int>(lookaheadVal)
2913 : layers.size() < 25 ?
static_cast<int>(1.5 * lookaheadVal)
2917 int lookaheadHeuristicDepthLocal = lookaheadDepthWithHeuristic;
2919 if (lookaheadHeuristicDepthLocal == std::numeric_limits<int>::max())
2920 lookaheadHeuristicDepthLocal = layers.size() < 8 || routedQubits <= 10 ? 0 : lookaheadDepthLocal - 1;
2922 if (lookaheadHeuristicDepthLocal < 0)
2923 lookaheadHeuristicDepthLocal = 0;
2925 sim->setGrowthFactorGate(growthFactorGate);
2926 sim->setGrowthFactorSwap(growthFactorSwap);
2927 sim->SetUseOptimalMeetingPosition(
true);
2928 if (lookaheadDepth == std::numeric_limits<int>::max())
2929 sim->SetAutomaticLookaheadDepth(lookaheadDepthLocal);
2931 sim->SetLookaheadDepth(lookaheadDepthLocal);
2932 sim->SetLookaheadDepthWithHeuristic(lookaheadHeuristicDepthLocal);
2936 sim->SetUpcomingGates(dcirc->GetOperations());
2957 const auto &qubitsMap = optimiser->GetReverseQubitsMap();
2979 theClassicalState.
Remap(qubitsMap);
2998 const auto &qubitsMap = optimiser->GetReverseQubitsMap();
3020 size_t numClassicalBits = 0;
3021 for (
const auto &[q, b] : bitsMap)
3022 if (b >= numClassicalBits)
3023 numClassicalBits = b + 1;
3027 for (
const auto &r : res)
3031 translatedState.
Remap(bitsMap,
false, numClassicalBits);
3032 translatedRes[translatedState.
GetAllBits()] = r.second;
3035 res.swap(translatedRes);
3050 size_t &nrQubits,
size_t &nrCbits,
bool useSeparateSimForHosts =
false)
3052 qubitsMapOnHost.clear();
3058 const auto host = std::static_pointer_cast<SimpleHost<Time>>(
GetHost(hostId));
3059 const size_t hostNrQubits = host->GetNumQubits();
3061 std::unordered_map<Types::qubit_t, Types::qubit_t> reverseQubitsMap;
3063 if (!useSeparateSimForHosts)
3069 size_t mnq = std::numeric_limits<size_t>::max();
3071 size_t mnb = std::numeric_limits<size_t>::max();
3073 for (
const auto &op : circuit->GetOperations())
3075 const auto qbits = op->AffectedQubits();
3076 for (
auto q : qbits)
3084 for (
auto b : circuit->GetBits())
3097 nrQubits = mxq - mnq + 1;
3098 nrCbits = mxb - mnb + 1;
3099 if (nrCbits < nrQubits)
3102 const size_t startQubit = host->GetStartQubitId();
3104 if (mnq < startQubit || mxq >= startQubit + hostNrQubits)
3106 if (nrQubits > hostNrQubits + 1)
3108 throw std::runtime_error(
"Circuit does not fit on the host!");
3110 for (
size_t i = 0; i < nrCbits; ++i)
3112 const size_t mapFrom = mnq + i;
3113 const size_t mapTo = startQubit + i;
3115 qubitsMapOnHost[mapFrom] = mapTo;
3116 reverseQubitsMap[mapTo] = mapFrom;
3119 distCirc = std::static_pointer_cast<Circuits::Circuit<Time>>(circuit->Remap(qubitsMapOnHost, qubitsMapOnHost));
3122 return reverseQubitsMap;
3125 distCirc = circuit->RemapToContinuous(qubitsMapOnHost, reverseQubitsMap, nrQubits, nrCbits);
3133 throw std::runtime_error(
"Circuit does not fit on a host with no qubits!");
3134 const size_t start = host->GetStartQubitId();
3135 bool fitsLocal =
true, fitsGlobal =
true;
3136 for (
const auto &entry : qubitsMapOnHost)
3138 const auto q = entry.first;
3139 fitsLocal = fitsLocal && q < hostNrQubits;
3140 fitsGlobal = fitsGlobal && q >= start && q - start < hostNrQubits;
3145 if (!(global ? fitsGlobal : fitsLocal))
3146 throw std::runtime_error(
"Circuit does not fit on the host!");
3147 const size_t offset = global ? start : 0;
3149 for (
const auto &pauli : *pauliStrings)
3150 if (pauli.size() > hostNrQubits)
3151 throw std::invalid_argument(
"Host Pauli strings use local indices and must fit the host");
3152 std::unordered_map<Types::qubit_t, Types::qubit_t> restoreQubits;
3153 for (
const auto &[original, compact] : qubitsMapOnHost)
3155 if (original < offset || original - offset >= hostNrQubits)
3156 throw std::runtime_error(
"Circuit does not fit on the host!");
3157 restoreQubits[compact] = original - offset;
3159 distCirc = std::static_pointer_cast<Circuits::Circuit<Time>>(
distCirc->Remap(restoreQubits));
3160 qubitsMapOnHost.clear();
3161 for (
size_t q = 0; q < hostNrQubits; ++q)
3162 qubitsMapOnHost[q] = q;
3163 nrQubits = hostNrQubits;
3165 else if (pauliStrings)
3170 for (
const auto &pauli : *pauliStrings)
3171 width = std::max(width, pauli.size());
3172 for (
size_t q = 0; q < width; ++q)
3173 if (!qubitsMapOnHost.count(q))
3174 qubitsMapOnHost[q] = nrQubits++;
3177 assert(nrQubits == qubitsMapOnHost.size());
3182 if (nrQubits > hostNrQubits + 1)
3184 throw std::runtime_error(
"Circuit does not fit on the host!");
3186 return reverseQubitsMap;
3216 std::vector<std::shared_ptr<IHost<Time>>>
hosts;
3232 std::unordered_map<Types::qubit_t, Types::qubit_t> qubitsMapOnHost;
3235 const std::vector<std::string> *pauliStrings =
nullptr;
3238 bool optimizeInitialQubitsMap =
true;
3240 bool mpsOptimizeSwaps =
true;
3241 size_t mpsOptimizationBondDimensionThreshold = 32;
3242 size_t mpsOptimizationQubitsNumberThreshold = 12;
3244 int lookaheadDepth = std::numeric_limits<int>::max();
3246 int lookaheadDepthWithHeuristic = std::numeric_limits<int>::max();
3249 double growthFactorSwap = 1.;
3250 double growthFactorGate = 0.7;
3251 size_t curMaxBondDim = 0;
int GetSimulationType(void *sim)
Circuit class for holding the sequence of operations.
void AddOperation(const OperationPtr &op)
Adds an operation to the circuit.
std::vector< std::shared_ptr< Circuits::Circuit< Time > > > ToMultipleQubitsLayersNoClone() const
Converts the circuit to layers oriented on multiple qubit gates.
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.
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, size_t *curMaxBondDim=nullptr)
The controller host interface.
std::shared_ptr< INetwork< Time > > getptr()
typename Circuits::Circuit< Time >::ExecuteResults ExecuteResults
std::unordered_set< SimulatorPair, boost::hash< SimulatorPair > > SimulatorsSet
bool resetBeforeExecution
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< Simulators::SimulatorType, std::string > resolvedDistributedDevices
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.
Configuration< Time > ExecutionConfiguration(Simulators::SimulatorType type, size_t qubits) const
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.
bool GetGateFusion() const override
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
unsigned GetLastGateFusionMaxQubits() 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.
bool WasGateFusionEnabled() const override
std::shared_ptr< INetwork< Time > > Clone() const override
Clone the network.
bool UsesReproducibleSampling(Simulators::SimulatorType type, Simulators::SimulationType method) const
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.
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.
double GetTrajectoryMinWorkerMicros() const
std::vector< std::shared_ptr< IHost< Time > > > hosts
The hosts in the network.
BaseClass::SimulatorsSet simulatorsForOptimizations
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) override
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.
std::string distributedHostQubitIndexing
Circuits::OperationState classicalState
The classical state of the network.
int GetLastGpuDevice() const override
Get the last used simulator type.
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.
void SetTrajectoryMinWorkerMicros(double micros)
Set the estimated work per trajectory worker.
bool recreateIfNeeded
The flag to recreate the simulator if needed.
Configuration< Time > configuration
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.
size_t GetCurrentMaxBondDimension() const override
Returns the maximum bond dimension reached.
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.
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 TrajectoryWorkersForWork(const std::shared_ptr< Circuits::Circuit< Time > > &circuit, size_t shots, size_t qubits, Simulators::SimulationType method, const std::vector< bool > &executed) const
double trajectoryMinWorkerMicros
Estimated serial work per trajectory worker, see SetTrajectoryMinWorkerMicros.
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
void CaptureSimulatorConfiguration()
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...
void ExecuteLogicalShotBlocks(const std::shared_ptr< Circuits::Circuit< Time > > &circuit, ExecuteResults &results, size_t shots, size_t workers, size_t qubits, size_t cbits, size_t resultBits, Simulators::SimulatorType type, Simulators::SimulationType method, const std::shared_ptr< Simulators::ISimulator > &prepared, const std::vector< bool > &executed, std::mutex &resultsMutex)
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 RecreateSimulatorKeepingResults(Simulators::SimulatorType simType, Simulators::SimulationType method)
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.
std::atomic< bool > lastFusionEnabled
void RemoveAllOptimizationSimulatorsAndAdd(Simulators::SimulatorType type, Simulators::SimulationType kind) override
Removes all simulators from the simulators optimization set and adds the one specified.
std::atomic< unsigned > lastFusionWidth
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.
static std::string GpuSvdSettingGroup(const std::string &key)
static int ParseGpuDevice(const std::string &value)
Set a configuration value.
Interface class for a quantum computing simulator.
static uint64_t DeriveSeed(uint64_t seed, uint64_t stream)
void SetSwapGatesRelabelQubits(bool enabled)
static IndexType EffectiveMapMaxBondDimension(size_t nrQubits, bool operatorChain, IndexType cap)
void setGrowthFactorSwap(double factor)
void SetRoutingCostModel(IndexType cap, double weight)
std::vector< long long int > ComputeOptimalQubitsMap(const std::vector< std::shared_ptr< Circuits::Circuit<> > > &layers, int nrShuffles=0, int nrSwaps=0)
void setGrowthFactorGate(double factor)
void SetMaxBondDimension(IndexType val)
static MAESTRO_FACTORY_EXPORT std::shared_ptr< ISimulator > CreateSimulator(SimulatorType t=SimulatorType::kQCSim, SimulationType method=SimulationType::kMatrixProductState)
Create a quantum computing simulator.
static bool IsGpuLibraryAvailable(int=-1)
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
bool VirtualBondsEnabled(const Config &config)
double TruncationWeight(const Config &config)
uint64_t GenerateRandomSeed(SimulatorType type, const std::unordered_map< std::string, std::string > &options={})
SimulationType
The type of simulation.
@ kStatevector
statevector simulation type
@ kMatrixProductState
matrix product state simulation type
@ kDensityMatrix
Density matrix simulation type.
@ kStabilizer
Clifford gates simulation type.
@ kMatrixProductOperator
Matrix product operator 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
@ kDistGpuSim
state distributed across local GPUs
@ kGpuSim
gpu simulator type
bool IsDistributedGpuSimulator(SimulatorType type)
bool IsGpuSimulator(SimulatorType type)
A way to pack together a circuit and the number of shots for its execution.