17#ifndef _IMMEDIATE_COMPOSITE_H_
18#define _IMMEDIATE_COMPOSITE_H_
20#ifdef INCLUDED_BY_FACTORY
46class ImmediateCompositeSimulator :
public ISimulator
56 ImmediateCompositeSimulator(SimulatorType type =
65 SeedAuxiliaryRng(samplingSeed);
76 type != SimulatorType::kQiskitAer &&
78 type != SimulatorType::kQCSim)
95 void Initialize()
override
98 qubitsMap.resize(nrQubits);
99 const uint64_t initializationSeed = nextInitialization++ == 0 ? samplingSeed : DeriveSeed(samplingSeed, 0x494E4954ULL + nextInitialization);
102 for (
size_t q = 0; q < nrQubits; ++q)
105 auto sim = std::make_unique<IndividualSimulator>(type);
106 sim->AllocateQubits(1);
110 sim->Configure(
"method",
"statevector");
113 sim->SetMultithreading(enableMultithreading);
114 if (config.IsSet(
"precision"))
115 sim->Configure(
"precision", config.GetConfiguration(
"precision").c_str());
117 for (
const auto &[key, value] : config.GetConfigMap())
118 if (key !=
"seed" && key !=
"method")
119 sim->Configure(key.c_str(), value.c_str());
120 sim->SetSeed(DeriveSeed(initializationSeed, q));
121 sim->GetQubitsMap()[q] = 0;
122 simulators[q] = std::move(sim);
133 void Reset()
override
150 void InitializeState(
size_t num_qubits, std::vector<std::complex<double>> &litudes)
override
152 throw std::runtime_error(
"CompositeSimulator::InitializeState not supported");
189 void InitializeState(
size_t num_qubits, AER::Vector<std::complex<double>> &litudes)
override
191 throw std::runtime_error(
"CompositeSimulator::InitializeState not supported");
207 void InitializeState(
size_t num_qubits, Eigen::VectorXcd &litudes)
override
209 throw std::runtime_error(
"CompositeSimulator::InitializeState not supported");
222 void Configure(
const char *key,
const char *value)
override
226 if (std::string(
"method") == key)
229 if (std::string(key) ==
"precision" || std::string(key) ==
"use_double_precision")
231 Configuration::ParsePrecision(key, value);
234 if (!simulators.empty())
236 config.SetConfiguration(key, value);
240 config.SetConfiguration(key, value);
242 if (std::string(
"seed") == key)
244 const uint64_t seed = std::stoull(value);
246 nextCloneStream = nextRestoreStream = nextInitialization = nextSplitStream = 0;
247 SeedAuxiliaryRng(seed);
248 for (
auto &[
id, simulator] : simulators)
249 simulator->SetSeed(DeriveSeed(seed,
id));
253 for (
auto &[
id, simulator] : simulators)
254 simulator->Configure(key, value);
267 if (std::string(key) ==
"sampling_seed")
268 return std::to_string(samplingSeed);
269 if (std::string(key) ==
"sampling_policy" && type == SimulatorType::kQCSim && !config.IsSet(key))
270 return "reproducible_v1";
271 if (std::string(key) ==
"precision" || std::string(key) ==
"use_double_precision")
273 if (!simulators.empty())
274 return simulators.begin()->second->GetConfiguration(key);
275 const bool useDouble = type == SimulatorType::kQCSim || !config.IsSet(
"precision") || config.GetConfiguration(
"precision") ==
"double";
276 return std::string(key) ==
"precision" ? (useDouble ?
"double" :
"single") : (useDouble ?
"1" :
"0");
278 if (simulators.empty())
281 return config.GetConfiguration(key);
294 if (!simulators.empty())
297 const size_t oldNrQubits = nrQubits;
298 nrQubits += num_qubits;
320 void Clear()
override
334 for (
auto &[
id, simulator] : simulators)
335 simulator->SaveStateToInternalDestructive();
346 for (
auto &[
id, simulator] : simulators)
347 simulator->RestoreInternalDestructiveSavedState();
358 std::complex<double> AmplitudeRaw(
Types::qubit_t outcome)
override
360 std::complex<double> res = 1.0;
362 for (
auto &[
id, simulator] : simulators)
363 res *= simulator->AmplitudeRaw(simulator->ConvertOutcomeFromGlobal(outcome));
380 if (qubits.size() >
sizeof(
size_t) * 8)
381 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
382 "number of bits in the size_t type, the outcome will be undefined"
391 const bool outcome =
GetSimulator(qubit)->Measure({qubit}) != 0;
396 Split(qubit, outcome);
400 NotifyObservers(qubits);
413 std::vector<bool> res(qubits.size(),
false);
416 for (
size_t q = 0; q < qubits.size(); ++q)
419 const bool outcome =
GetSimulator(qubit)->Measure({qubit}) != 0;
423 Split(qubit, outcome);
427 NotifyObservers(qubits);
448 NotifyObservers(qubits);
475 std::complex<double> res = 1.0;
477 for (
auto &[
id, simulator] : simulators)
478 res *= simulator->Amplitude(outcome);
496 std::complex<double> ProjectOnZero()
override
498 std::complex<double> res = 1.0;
500 for (
auto &[
id, simulator] : simulators)
501 res *= simulator->ProjectOnZero();
515 const size_t nrBasisStates = 1ULL << nrQubits;
516 std::vector<double> result;
518 for (
size_t i = 0; i < nrBasisStates; ++i)
535 std::vector<double> result;
537 for (
size_t i = 0; i < qubits.size(); ++i)
561 if (type == SimulatorType::kQCSim && config.GetConfiguration(
"sampling_policy") !=
"legacy")
562 return SamplePrepared<false>(qubits, shots);
563 if (qubits.empty() || !shots)
566 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
567 "number of bits in the Types::qubit_t type, the outcome will be "
571 std::unordered_map<Types::qubit_t, Types::qubit_t> result;
580 for (
size_t shot = 0; shot < shots; ++shot)
583 for (
auto &[
id, simulator] : simulators)
584 measRaw |= simulator->SampleFromAlias();
588 for (
auto q : qubits)
590 const size_t qubitMask = 1ULL << q;
591 if ((measRaw & qubitMask) != 0)
602 for (
size_t shot = 0; shot < shots; ++shot)
608 for (
auto q : qubits)
610 const size_t qubitMask = 1ULL << q;
611 if ((measRaw & qubitMask) != 0)
622 NotifyObservers(qubits);
642 if (type == SimulatorType::kQCSim && config.GetConfiguration(
"sampling_policy") !=
"legacy")
643 return SamplePrepared<true>(qubits, shots);
644 if (qubits.empty() || !shots)
650 std::vector<bool> meas(qubits.size());
655 for (
size_t shot = 0; shot < shots; ++shot)
658 for (
auto &[
id, simulator] : simulators)
659 measRaw |= simulator->SampleFromAlias();
661 for (
size_t i = 0; i < qubits.size(); ++i)
662 meas[i] = ((measRaw >> qubits[i]) & 1) == 1;
671 for (
size_t shot = 0; shot < shots; ++shot)
673 const auto measRaw = MeasureNoCollapseMany();
675 for (
size_t i = 0; i < qubits.size(); ++i)
676 meas[i] = measRaw[qubits[i]];
685 NotifyObservers(qubits);
701 double ExpectationValue(
const std::string &pauliString)
override
703 std::unordered_map<size_t, std::string> pauliStrings;
705 for (
size_t q = 0; q < pauliString.size(); ++q)
707 const char op = toupper(pauliString[q]);
711 const size_t simId = qubitsMap[q];
712 const size_t localQubit = simulators[simId]->GetQubitsMap().at(q);
714 if (pauliStrings[simId].size() <= localQubit)
715 pauliStrings[simId].resize(localQubit + 1,
'I');
717 pauliStrings[simId][localQubit] = op;
721 for (
auto &[
id, localPauliString] : pauliStrings)
722 result *= simulators[id]->ExpectationValue(localPauliString);
734 SimulatorType GetType()
const override
737 return SimulatorType::kCompositeQCSim;
739 if (type != SimulatorType::kQiskitAer)
740 return SimulatorType::kCompositeQCSim;
742 return SimulatorType::kCompositeQiskitAer;
756 return SimulationType::kStatevector;
766 void Flush()
override
768 for (
auto &[
id, simulator] : simulators)
779 GetSimulator(qubit)->ApplyGenericOneQubitGate(qubit, gate);
780 NotifyObservers({qubit});
791 JoinIfNeeded(qubit0, qubit1);
792 GetSimulator(qubit0)->ApplyGenericTwoQubitGate(qubit0, qubit1, gate);
793 NotifyObservers({qubit0, qubit1});
798 JoinIfNeeded(q0, q1);
799 JoinIfNeeded(q0, q2);
800 GetSimulator(q0)->ApplyGenericThreeQubitGate(q0, q1, q2, gate);
801 NotifyObservers({q0, q1, q2});
816 NotifyObservers({qubit});
828 NotifyObservers({qubit});
840 NotifyObservers({qubit});
852 NotifyObservers({qubit});
864 NotifyObservers({qubit});
876 NotifyObservers({qubit});
888 NotifyObservers({qubit});
900 NotifyObservers({qubit});
912 NotifyObservers({qubit});
924 NotifyObservers({qubit});
936 NotifyObservers({qubit});
948 NotifyObservers({qubit});
961 NotifyObservers({qubit});
974 NotifyObservers({qubit});
987 NotifyObservers({qubit});
1000 void ApplyU(
Types::qubit_t qubit,
double theta,
double phi,
double lambda,
double gamma)
override
1002 GetSimulator(qubit)->ApplyU(qubit, theta, phi, lambda, gamma);
1003 NotifyObservers({qubit});
1018 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1019 GetSimulator(ctrl_qubit)->ApplyCX(ctrl_qubit, tgt_qubit);
1020 NotifyObservers({tgt_qubit, ctrl_qubit});
1032 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1033 GetSimulator(ctrl_qubit)->ApplyCY(ctrl_qubit, tgt_qubit);
1034 NotifyObservers({tgt_qubit, ctrl_qubit});
1046 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1047 GetSimulator(ctrl_qubit)->ApplyCZ(ctrl_qubit, tgt_qubit);
1048 NotifyObservers({tgt_qubit, ctrl_qubit});
1061 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1062 GetSimulator(ctrl_qubit)->ApplyCP(ctrl_qubit, tgt_qubit, lambda);
1063 NotifyObservers({tgt_qubit, ctrl_qubit});
1076 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1077 GetSimulator(ctrl_qubit)->ApplyCRx(ctrl_qubit, tgt_qubit, theta);
1078 NotifyObservers({tgt_qubit, ctrl_qubit});
1091 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1092 GetSimulator(ctrl_qubit)->ApplyCRy(ctrl_qubit, tgt_qubit, theta);
1093 NotifyObservers({tgt_qubit, ctrl_qubit});
1106 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1107 GetSimulator(ctrl_qubit)->ApplyCRz(ctrl_qubit, tgt_qubit, theta);
1108 NotifyObservers({tgt_qubit, ctrl_qubit});
1120 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1121 GetSimulator(ctrl_qubit)->ApplyCH(ctrl_qubit, tgt_qubit);
1122 NotifyObservers({tgt_qubit, ctrl_qubit});
1134 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1135 GetSimulator(ctrl_qubit)->ApplyCSx(ctrl_qubit, tgt_qubit);
1136 NotifyObservers({tgt_qubit, ctrl_qubit});
1148 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1149 GetSimulator(ctrl_qubit)->ApplyCSxDAG(ctrl_qubit, tgt_qubit);
1150 NotifyObservers({tgt_qubit, ctrl_qubit});
1162 JoinIfNeeded(qubit0, qubit1);
1164 NotifyObservers({qubit1, qubit0});
1179 JoinIfNeeded(qubit0, qubit1);
1180 JoinIfNeeded(qubit0, qubit2);
1181 GetSimulator(qubit0)->ApplyCCX(qubit0, qubit1, qubit2);
1182 NotifyObservers({qubit2, qubit1, qubit0});
1197 JoinIfNeeded(ctrl_qubit, qubit0);
1198 JoinIfNeeded(ctrl_qubit, qubit1);
1199 GetSimulator(ctrl_qubit)->ApplyCSwap(ctrl_qubit, qubit0, qubit1);
1200 NotifyObservers({qubit1, qubit0, ctrl_qubit});
1216 JoinIfNeeded(ctrl_qubit, tgt_qubit);
1217 GetSimulator(ctrl_qubit)->ApplyCU(ctrl_qubit, tgt_qubit, theta, phi, lambda, gamma);
1218 NotifyObservers({tgt_qubit, ctrl_qubit});
1221 void ApplyNop()
override
1236 enableMultithreading = multithreading;
1237 for (
auto &[
id, simulator] : simulators)
1238 simulator->SetMultithreading(multithreading);
1250 return enableMultithreading;
1284 savedState = CloneStateForExecution(DeriveSeed(samplingSeed, 0x53415645ULL),
false);
1304 const ImmediateCompositeSimulator *savedStatePtr =
static_cast<ImmediateCompositeSimulator *
>(savedState.get());
1306 type = savedStatePtr->type;
1307 qubitsMap = savedStatePtr->qubitsMap;
1310 nrQubits = savedStatePtr->nrQubits;
1311 nextId = savedStatePtr->nextId;
1312 enableMultithreading = savedStatePtr->enableMultithreading;
1316 const uint64_t restoreSeed = DeriveSeed(samplingSeed, 0x52455354ULL + nextRestoreStream++);
1317 for (
auto &[
id, simulator] : savedStatePtr->simulators)
1319 auto isim = simulator->CloneForExecution(DeriveSeed(restoreSeed,
id));
1320 simulators[id] = std::unique_ptr<IndividualSimulator>(
static_cast<IndividualSimulator *
>(isim.release()));
1346 std::cerr <<
"Warning: The number of qubits to measure is larger than the "
1347 "number of bits in the Types::qubit_t type, the outcome will be "
1351 for (
auto &[
id, simulator] : simulators)
1374 std::vector<bool> MeasureNoCollapseMany()
override
1376 std::vector<bool> res(nrQubits,
false);
1377 for (
auto &[
id, simulator] : simulators)
1379 const std::vector<bool> meas = simulator->MeasureNoCollapseMany();
1380 for (
size_t i = 0; i < meas.size(); ++i)
1397 std::unique_ptr<ISimulator> Clone()
override
1399 if (nextCloneStream == std::numeric_limits<uint64_t>::max())
1400 throw std::overflow_error(
"Composite clone stream exhausted");
1401 return CloneForExecution(DeriveSeed(samplingSeed, nextCloneStream++));
1404 std::unique_ptr<ISimulator> CloneForExecution(uint64_t seed)
override
1406 return CloneStateForExecution(seed,
true);
1410 std::unique_ptr<ISimulator> CloneStateForExecution(uint64_t seed,
bool includeSnapshot)
1412 auto clone = std::make_unique<ImmediateCompositeSimulator>(type);
1415 clone->qubitsMap = qubitsMap;
1418 clone->nrQubits = nrQubits;
1419 clone->nextId = nextId;
1420 clone->enableMultithreading = enableMultithreading;
1423 clone->config = config;
1425 for (
auto &[
id, simulator] : simulators)
1427 auto isim = simulator->CloneForExecution(DeriveSeed(seed,
id));
1428 clone->simulators[id] = std::unique_ptr<IndividualSimulator>(
static_cast<IndividualSimulator *
>(isim.release()));
1431 if (includeSnapshot && savedState)
1432 clone->savedState =
static_cast<ImmediateCompositeSimulator *
>(savedState.get())->CloneStateForExecution(DeriveSeed(seed, 0x53415645ULL),
false);
1434 clone->SetSeed(seed);
1444 const std::unordered_map<std::string, std::string> &GetConfigMap()
const override
1446 return config.GetConfigMap();
1453 using Plan = QCSimStatevectorSimulator::SamplingPlan;
1455 if (qubits.empty() || !shots)
1458 if (simulators.size() == 1)
1460 auto &component = *simulators.begin()->second;
1462 result = component.SampleCountsMany(qubits, shots);
1464 result = component.SampleCounts(qubits, shots);
1465 NotifyObservers(qubits);
1471 std::unordered_map<size_t, size_t> uniqueBits;
1472 std::vector<size_t> outputBits;
1473 for (
const auto qubit : qubits)
1474 outputBits.push_back(uniqueBits.emplace(qubit, uniqueBits.size()).first->second);
1475 constexpr size_t wordBits = std::numeric_limits<size_t>::digits;
1476 const size_t words = (uniqueBits.size() + wordBits - 1) / wordBits;
1481 IndividualSimulator *simulator;
1482 std::vector<std::pair<size_t, size_t>> bits;
1483 std::unique_ptr<Plan> plan;
1484 std::vector<size_t> projection;
1485 size_t minimumBytes = 0;
1488 std::vector<Component> components;
1489 components.reserve(simulators.size());
1490 for (
auto &[
id, simulator] : simulators)
1492 Component component{id, simulator.get()};
1493 for (
auto [qubit, local] : simulator->GetQubitsMap())
1494 if (
const auto found = uniqueBits.find(qubit); found != uniqueBits.end())
1495 component.bits.emplace_back(local, found->second);
1496 components.push_back(std::move(component));
1500 std::sort(components.begin(), components.end(), [](
const auto &a,
const auto &b) { return a.id < b.id; });
1501 auto project = [&](
const Component &component,
size_t row,
size_t *joint) {
1502 if (!component.projection.empty())
1503 joint[0] |= component.projection[row];
1505 for (
const auto [local, output] : component.bits)
1506 joint[output / wordBits] |= ((row >> local) &
size_t{1}) << (output % wordBits);
1508 std::vector<bool> key;
1510 key.resize(qubits.size());
1511 auto insert = [&](
const size_t *joint,
size_t count) {
1514 for (
size_t bit = 0; bit < outputBits.size(); ++bit)
1515 key[bit] = ((joint[outputBits[bit] / wordBits] >> (outputBits[bit] % wordBits)) & 1) != 0;
1516 result[key] += count;
1521 for (
size_t bit = 0; bit < outputBits.size(); ++bit)
1522 packed |=
Types::qubit_t((joint[outputBits[bit] / wordBits] >> (outputBits[bit] % wordBits)) & 1) << bit;
1523 result[packed] += count;
1528 std::vector<size_t> joint(words, 0);
1529 for (
auto &component : components)
1530 if (component.bits.empty())
1531 component.simulator->DiscardLocalMeasurementDraw();
1533 project(component, component.simulator->SampleLocalOnce(), joint.data());
1534 insert(joint.data(), 1);
1535 NotifyObservers(qubits);
1539 const Options options = components.front().simulator->SamplingOptions();
1540 const size_t sharedReserve = options.
memoryBytes / 4;
1541 size_t remaining = options.
memoryBytes - sharedReserve, reserved = 0;
1542 const size_t selected = std::count_if(components.begin(), components.end(), [](
const auto &c) { return !c.bits.empty(); });
1543 const size_t componentBudget = remaining / std::max<size_t>(1, selected);
1544 for (
auto &component : components)
1545 if (!component.bits.empty())
1547 component.minimumBytes = Plan::MinimumMemoryBytes(component.simulator->SamplingRows(), shots, componentBudget);
1548 if (component.minimumBytes > remaining - reserved)
1549 throw std::length_error(
"Composite probability indexes exceed the sampling scratch budget");
1550 reserved += component.minimumBytes;
1552 for (
auto &component : components)
1553 if (!component.bits.empty())
1555 reserved -= component.minimumBytes;
1556 auto localOptions = options;
1558 component.plan = std::make_unique<Plan>(component.simulator->PrepareSampling(shots, localOptions));
1559 remaining -= localOptions.memoryBytes - component.plan->ScratchAvailable();
1563 for (
auto &component : components)
1564 if (words == 1 && component.bits.size() > 1 && component.plan && component.plan->Size() <= 65536 &&
1565 shots >= std::max<size_t>(256, component.plan->Size()) && component.plan->Size() <= remaining /
sizeof(
size_t))
1567 std::vector<size_t> table(component.plan->Size(), 0);
1568 for (
size_t row = 0; row < table.size(); ++row)
1569 project(component, row, &table[row]);
1570 remaining -= table.size() *
sizeof(size_t);
1571 component.projection = std::move(table);
1573 remaining += sharedReserve;
1574 const size_t categories = uniqueBits.size() <= 20 ?
size_t{1} << uniqueBits.size() : 0;
1575 const bool histogram = categories && shots >= std::max<size_t>(1024, categories / 4) && categories <= remaining / (2 *
sizeof(size_t));
1576 std::vector<size_t> bins(histogram ? categories : 0, 0);
1577 remaining -= bins.size() *
sizeof(size_t);
1579 if (words > (std::numeric_limits<size_t>::max() - 32) /
sizeof(
size_t))
1580 throw std::length_error(
"Composite sampling output is too wide");
1581 const size_t bytesPerShot = 32 + words *
sizeof(size_t);
1582 const size_t batch = std::min({shots, options.
batchSize, remaining / bytesPerShot});
1584 throw std::length_error(
"Composite sampling batch exceeds the scratch budget");
1585 std::vector<size_t> joint(batch * words), sampled;
1586 std::vector<double> uniforms;
1589 for (
auto &component : components)
1590 if (component.bits.empty())
1591 component.simulator->SamplingRng().discard(shots);
1592 for (
size_t begin = 0; begin < shots;)
1594 const size_t count = std::min(batch, shots - begin);
1595 std::fill(joint.begin(), joint.begin() + count * words, 0);
1596 for (
auto &component : components)
1598 if (!component.plan)
1600 const auto &plan = *component.plan;
1601 auto &rng = component.simulator->SamplingRng();
1603 if (threads == 1 && (plan.Method() ==
Family::Alias || plan.Size() <= 65536 || count < 128))
1605 for (
size_t shot = 0; shot < count; ++shot)
1610 uniforms.resize(count);
1611 for (
double &value : uniforms)
1613 plan.Draw(uniforms, sampled, threads);
1615#pragma omp parallel for if (threads > 1) num_threads(threads) schedule(static)
1617 for (int64_t shot = 0; shot < static_cast<int64_t>(count); ++shot)
1618 project(component, sampled[shot], &joint[
size_t(shot) * words]);
1621 for (
size_t shot = 0; shot < count; ++shot)
1623 ++bins[joint[shot]];
1625 insert(&joint[shot * words], 1);
1628 for (
size_t row = 0; row < bins.size(); ++row)
1630 insert(&row, bins[row]);
1631 NotifyObservers(qubits);
1635 void InitializeAlias()
1637 for (
auto &[
id, simulator] : simulators)
1638 simulator->InitializeAlias();
1643 for (
auto &[
id, simulator] : simulators)
1644 simulator->ClearAlias();
1655 inline std::unique_ptr<IndividualSimulator> &
GetSimulator(
size_t qubit)
1657 assert(qubitsMap.size() > qubit);
1658 assert(simulators.find(qubitsMap[qubit]) != simulators.end());
1661 return simulators[qubitsMap[qubit]];
1678 inline bool JoinNeeded(
size_t qubit1,
size_t qubit2)
1683 return qubitsMap[qubit1] != qubitsMap[qubit2];
1694 inline void JoinIfNeeded(
size_t qubit1,
size_t qubit2)
1696 if (JoinNeeded(qubit1, qubit2))
1698 const size_t simId = qubitsMap[qubit1];
1699 const size_t eraseSimId = qubitsMap[qubit2];
1703 sim1->Join(simId, sim2, qubitsMap, enableMultithreading);
1705 simulators.erase(eraseSimId);
1719 inline void Split(
size_t qubit,
bool qubitOutcome =
false)
1722 if (sim->GetNumberOfQubits() == 1)
1725 if (nextSplitStream == std::numeric_limits<uint64_t>::max())
1726 throw std::overflow_error(
"Composite split stream exhausted");
1729 const uint64_t splitSeed = DeriveSeed(DeriveSeed(samplingSeed, 0x53504C4954ULL), nextSplitStream++);
1730 qubitsMap[qubit] = nextId;
1731 simulators[nextId] = sim->Split(qubit, qubitOutcome, enableMultithreading, splitSeed);
1737 std::vector<size_t> qubitsMap;
1739 std::unordered_map<size_t, std::unique_ptr<IndividualSimulator>> simulators;
1740 size_t nrQubits = 0;
1742 bool enableMultithreading =
true;
1744 std::unique_ptr<ISimulator> savedState;
1746 Configuration config;
1748 uint64_t nextCloneStream = 0, nextRestoreStream = 0, nextInitialization = 0, nextSplitStream = 0;
int ApplyK(void *sim, int qubit)
double Probability(void *sim, unsigned long long int outcome)
char * GetConfiguration(void *sim, const char *key)
int RestoreState(void *sim)
int ApplyRx(void *sim, int qubit, double theta)
int ApplyReset(void *sim, const unsigned long int *qubits, unsigned long int nrQubits)
int ApplyX(void *sim, int qubit)
int ApplyU(void *sim, int qubit, double theta, double phi, double lambda, double gamma)
int ApplyCRy(void *sim, int controlQubit, int targetQubit, double theta)
int ApplyTDG(void *sim, int qubit)
int ApplyS(void *sim, int qubit)
int ApplyCX(void *sim, int controlQubit, int targetQubit)
unsigned long int AllocateQubits(void *sim, unsigned long int nrQubits)
int ApplyCRz(void *sim, int controlQubit, int targetQubit, double theta)
unsigned long int GetNumberOfQubits(void *sim)
double * AllProbabilities(void *sim)
unsigned long long int MeasureNoCollapse(void *sim)
int ApplyCP(void *sim, int controlQubit, int targetQubit, double theta)
int GetMultithreading(void *sim)
int ApplySDG(void *sim, int qubit)
unsigned long long int Measure(void *sim, const unsigned long int *qubits, unsigned long int nrQubits)
int ApplyCSwap(void *sim, int controlQubit, int qubit1, int qubit2)
int ApplyCCX(void *sim, int controlQubit1, int controlQubit2, int targetQubit)
int ApplyY(void *sim, int qubit)
double * Amplitude(void *sim, unsigned long long int outcome)
int ApplyZ(void *sim, int qubit)
int ApplyH(void *sim, int qubit)
int ApplyGenericThreeQubitGate(void *sim, unsigned long q0, unsigned long q1, unsigned long q2, const double *buffer)
int ApplyCY(void *sim, int controlQubit, int targetQubit)
double * Probabilities(void *sim, const unsigned long long int *qubits, unsigned long int nrQubits)
int SetMultithreading(void *sim, int multithreading)
int ApplyCU(void *sim, int controlQubit, int targetQubit, double theta, double phi, double lambda, double gamma)
int ApplySwap(void *sim, int qubit1, int qubit2)
void * GetSimulator(unsigned long int simHandle)
int ApplyRy(void *sim, int qubit, double theta)
int ApplyP(void *sim, int qubit, double theta)
int SaveStateToInternalDestructive(void *sim)
int ApplyCH(void *sim, int controlQubit, int targetQubit)
int GetSimulationType(void *sim)
unsigned long long int * SampleCounts(void *sim, const unsigned long long int *qubits, unsigned long int nrQubits, unsigned long int shots)
int ApplyCZ(void *sim, int controlQubit, int targetQubit)
int ApplyRz(void *sim, int qubit, double theta)
int RestoreInternalDestructiveSavedState(void *sim)
int ApplyT(void *sim, int qubit)
int ApplyCRx(void *sim, int controlQubit, int targetQubit, double theta)
int ApplyGenericOneQubitGate(void *sim, unsigned long q0, const double *buffer)
int ApplyGenericTwoQubitGate(void *sim, unsigned long q0, unsigned long q1, const double *buffer)
Bounded online routing based on current physical bond dimensions.
@ kQCSim
qcsim simulator type
@ kQiskitAer
qiskit aer simulator type
std::vector< qubit_t > qubits_vector
The type of a vector of qubits.
uint_fast64_t qubit_t
The type of a qubit.
double Uniform(std::mt19937_64 &engine)
bool ValidateSetting(std::string_view name, std::string_view setting)
int Threads(bool permitted, size_t work)
void ValidateQubits(const Qubits &qubits, size_t width, bool many)
std::unordered_map< std::conditional_t< Many, std::vector< bool >, Types::qubit_t >, Types::qubit_t > Counts