32 using TensorPair = std::pair<Eigen::Index, Eigen::Index>;
34 std::unordered_set<TensorPair, boost::hash<TensorPair>>;
44 std::vector<Eigen::Index> keys;
45 std::unordered_map<Eigen::Index, Eigen::Index> keysKeys;
52 while (tensors.size() > 1) {
54 auto it = tensors.begin();
55 Eigen::Index tensor1Id = it->first;
57 Eigen::Index tensor2Id = it->first;
61 Eigen::Index maxCost = std::numeric_limits<Eigen::Index>::max();
62 size_t bestDepth = numberOfLevels;
63 Lookahead(qubit, tensor1Id, tensor2Id, bestDepth, 0, 0, dummyTensors, 1,
66 const auto &tensor = tensors[tensor1Id];
67 const auto resultRank =
GetResultRank(tensor, tensors[tensor2Id]);
70 ContractNodes(qubit, dummyTensors, tensor1Id, tensor2Id, resultRank);
74 ContractNodes(qubit, tensors, tensor1Id, tensor2Id, resultRank);
76 if (resultRank == 0) {
77 if (tensors.size() == 1 || tensor->contractsTheNeededQubit)
78 return std::real(tensor->tensor->atOffset(0));
82 tensors.erase(tensor1Id);
83 dummyTensors.erase(tensor1Id);
87 return std::real(tensors.begin()->second->tensor->atOffset(0));
103 std::shared_ptr<ITensorContractor>
Clone()
const override {
104 auto cloned = std::make_shared<LookaheadContractor>();
108 cloned->numberOfLevels = numberOfLevels;
109 cloned->useMaxRankCost = useMaxRankCost;
115 void Lookahead(Types::qubit_t qubit, Eigen::Index &tensor1Id,
116 Eigen::Index &tensor2Id,
size_t &bestDepth, Eigen::Index curt1,
118 size_t curLevel, Eigen::Index &maxCost,
119 Eigen::Index CostOnPath) {
120 if (dummyTensors.size() > 1 && curLevel < numberOfLevels) {
121 std::unordered_set<TensorPair, boost::hash<TensorPair>> visitedPairs;
123 for (
auto tensorIt = dummyTensors.begin(); tensorIt != dummyTensors.end();
125 auto tensor = tensorIt->second;
126 const auto curTensorId = tensor->GetId();
128 assert(tensor->tensor->IsDummy());
131 for (Eigen::Index ti = 0;
132 ti < static_cast<Eigen::Index>(tensor->connections.size()); ++ti) {
133 const auto nextTensorId = tensor->connections[ti];
136 auto t1 = curTensorId;
137 auto t2 = nextTensorId;
138 if (t1 > t2) std::swap(t1, t2);
139 if (visitedPairs.find(std::make_pair(t1, t2)) != visitedPairs.end())
142 visitedPairs.insert(std::make_pair(t1, t2));
144 const Eigen::Index newRank =
149 const Eigen::Index newCostOnPath =
150 useMaxRankCost ? std::max(newRank, CostOnPath)
151 : CostOnPath + newRank;
152 if (newCostOnPath < maxCost) {
163 auto saveTensor2 = dummyTensors[nextTensorId];
165 ContractNodes(qubit, dummyTensors, curTensorId, nextTensorId,
168 Lookahead(qubit, tensor1Id, tensor2Id, bestDepth,
169 curLevel == 1 ? curTensorId : curt1,
170 curLevel == 1 ? nextTensorId : curt2, dummyTensors,
171 curLevel + 1, maxCost, newCostOnPath);
175 dummyTensors[curTensorId] = tensor;
176 dummyTensors[nextTensorId] = saveTensor2;
181 for (Eigen::Index i = 0;
182 i < static_cast<Eigen::Index>(tensor->connections.size());
185 tensor->connections[i] != nextTensorId) {
186 const auto connectedTensorId = tensor->connections[i];
187 const auto otherTensorIndex = tensor->connectionsIndices[i];
190 dummyTensors[connectedTensorId]
191 ->connectionsIndices[otherTensorIndex] = i;
195 for (Eigen::Index i = 0; i < static_cast<Eigen::Index>(
196 saveTensor2->connections.size());
199 saveTensor2->connections[i] != curTensorId) {
200 const auto connectedTensorId = saveTensor2->connections[i];
201 const auto otherTensorIndex =
202 saveTensor2->connectionsIndices[i];
203 dummyTensors[connectedTensorId]
204 ->connections[otherTensorIndex] = nextTensorId;
205 dummyTensors[connectedTensorId]
206 ->connectionsIndices[otherTensorIndex] = i;
213 tensorIt = dummyTensors.find(curTensorId);
220 if ((curLevel == numberOfLevels && CostOnPath < maxCost) ||
221 (dummyTensors.size() <= 1 &&
222 (CostOnPath < maxCost ||
223 (maxCost == CostOnPath && curLevel < bestDepth)))) {
224 maxCost = CostOnPath;
225 bestDepth = curLevel;
234 for (
const auto &[tensorId, tensor] : tensors)
235 clonedTensors[tensorId] = tensor->CloneWithADummyTensor();
237 return clonedTensors;
240 size_t numberOfLevels = 3;
241 bool useMaxRankCost =
true;