Maestro 0.3.11
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
QCSimTensorChainSimulator.h
Go to the documentation of this file.
1#pragma once
2#if defined(INCLUDED_BY_FACTORY)
6#include "QCSimTensorUtils.h"
7#include "RoutingMap.h"
8
10{
11class QCSimTensorChainSimulator : public TensorChainRouting<QCSimGateSimulator>
12{
13 using RoutingBase = TensorChainRouting<QCSimGateSimulator>;
14
15 public:
16 bool IsRoutingLookaheadEnabled() const override
17 {
18 return RoutingBase::IsRoutingLookaheadEnabled() || (UsesBoundedRouting() && CurrentRoutingMap().size() == nrQubits);
19 }
20
21 void SetLookaheadDepth(int depth) override
22 {
23 automaticRoutingDepth = false;
24 InvalidateBoundedRouting();
25 RoutingBase::SetLookaheadDepth(depth);
26 }
27
28 void SetAutomaticLookaheadDepth(int depth) override
29 {
30 automaticRoutingDepth = true;
31 InvalidateBoundedRouting();
32 RoutingBase::SetLookaheadDepth(depth);
33 }
34
35 void SetUpcomingGates(const std::vector<std::shared_ptr<Circuits::IOperation<double>>> &gates) override
36 {
37 InvalidateBoundedRouting(true);
38 RoutingBase::SetUpcomingGates(gates);
39 }
40
41 void setGrowthFactorSwap(double factor) override
42 {
43 RoutingBase::setGrowthFactorSwap(factor);
44 RefreshRoutingCallback();
45 }
46
47 void setGrowthFactorGate(double factor) override
48 {
49 RoutingBase::setGrowthFactorGate(factor);
50 RefreshRoutingCallback();
51 }
52
53 std::string GetConfiguration(const char *key) const override
54 {
55 if (key && std::string(key) == RoutingConfig::kStrategy && !configuration.IsSet(key))
56 return "legacy";
57 return RoutingBase::GetConfiguration(key);
58 }
59
60 protected:
61 explicit QCSimTensorChainSimulator(bool isOperatorChain) : TensorChainRouting(isOperatorChain, true)
62 {
63 meetingPositionCallback = [this](const auto &bonds) -> QC::TensorNetworks::MPSSimulatorInterface::IndexType {
64 try
65 {
66 if (!decompositionDepth && upcomingGateIndex >= 0)
67 {
68 if (!boundedRoutingPrepared && UsesBoundedRouting() && static_cast<size_t>(upcomingGateIndex) < upcomingGates.size())
69 {
70 const auto &operation = upcomingGates[static_cast<size_t>(upcomingGateIndex)];
71 // Native routing invokes this callback only for nonadjacent
72 // operands. Unsupported boundaries need no operation table.
73 if (operation && operation->GetType() == Circuits::OperationType::kGate && operation->AffectedQubits().size() == 2)
74 PrepareBoundedRouting();
75 }
76 if (boundedRouting)
77 return boundedRouting->Select(CurrentRoutingMap(), bonds.data(), bonds.size(), static_cast<size_t>(upcomingGateIndex));
78 }
79 return PlanMeetingPosition(bonds.data(), bonds.size());
80 }
81 catch (...)
82 {
83 InvalidateDummyHistory();
84 return -1;
85 }
86 };
87 bondDimensionCallback = [this](auto maximum) { curMaxBondDim = std::max(curMaxBondDim, static_cast<size_t>(maximum)); };
88 }
89
90 bool UsesBoundedRouting() const
91 {
92 // Apply the measured policy only to automatic CPU routing. Explicit
93 // depth and cost-model overrides continue to select the legacy policy.
94 return automaticRoutingDepth && useOptimalMeetingPosition && lookaheadDepth == 0 && nrQubits > 1 &&
95 RoutingConfig::GetStrategy(configuration) == RoutingConfig::Strategy::Combined && !virtualBondsEnabled && growthFactorGate == 0.7 &&
96 growthFactorSwap == 1. && (operatorChain ? nrQubits <= 8 : nrQubits > 10);
97 }
98
99 void InvalidateBoundedRouting(bool operationsChanged = false)
100 {
101 boundedRouting.reset();
102 boundedRoutingPrepared = false;
103 if (operationsChanged)
104 {
105 boundedRoutingOperations.reset();
106 boundedRoutingOperationsQubits = 0;
107 }
108 }
109
110 // Setters and cloning update eligibility without parsing gates or allocating
111 // forecast scratch. Actual nonadjacent execution performs preparation once.
112 void RefreshBoundedRouting()
113 {
114 if (boundedRoutingOperations && boundedRoutingOperationsQubits != nrQubits)
115 InvalidateBoundedRouting(true);
116 else if (!UsesBoundedRouting() || upcomingGates.empty() ||
117 (boundedRoutingPrepared && (boundedRoutingQubits != nrQubits || boundedRoutingCap != physicalBondCap)))
118 InvalidateBoundedRouting();
119 }
120
121 void PrepareBoundedRouting()
122 {
123 if (!UsesBoundedRouting() || upcomingGates.empty())
124 {
125 InvalidateBoundedRouting();
126 return;
127 }
128 if (boundedRoutingPrepared && boundedRoutingQubits == nrQubits && boundedRoutingCap == physicalBondCap)
129 return;
130 boundedRouting.reset();
131 boundedRoutingPrepared = true;
132 boundedRoutingQubits = nrQubits;
133 boundedRoutingCap = physicalBondCap;
134 try
135 {
136 if (!boundedRoutingOperations || boundedRoutingOperationsQubits != nrQubits)
137 {
138 boundedRoutingOperations = BoundedRoutingPlanner::PrepareOperations(nrQubits, upcomingGates);
139 boundedRoutingOperationsQubits = nrQubits;
140 }
141 boundedRouting =
142 std::make_unique<BoundedRoutingPlanner>(nrQubits, operatorChain, physicalBondCap, boundedRoutingOperations,
143 operatorChain ? BoundedRoutingPlanner::Policy::Work4 : BoundedRoutingPlanner::Policy::Work24);
144 }
145 catch (...)
146 {
147 // Routing metadata is advisory. A failed preparation must leave
148 // execution on the native routing fallback, without retrying per gate.
149 }
150 }
151
152 bool automaticRoutingDepth = false;
153 std::unique_ptr<BoundedRoutingPlanner> boundedRouting;
154 BoundedRoutingPlanner::SharedOperations boundedRoutingOperations;
155 size_t boundedRoutingOperationsQubits = 0;
156 bool boundedRoutingPrepared = false;
157 size_t boundedRoutingQubits = 0;
158 MPSDummySimulator::IndexType boundedRoutingCap = 0;
159
160 QC::TensorNetworks::MPSSimulator::MeetingPositionCallback meetingPositionCallback = nullptr;
161 std::function<void(Eigen::Index)> bondDimensionCallback = nullptr;
162};
163} // namespace Simulators::Private
164#endif
char * GetConfiguration(void *sim, const char *key)
@ kGate
the usual quantum gate, result stays in simulator's state
Definition Operations.h:30