Maestro 0.1.0
Unified interface for quantum circuit simulation
Loading...
Searching...
No Matches
StochasticContractor.h
Go to the documentation of this file.
1
13
14#pragma once
15
16#ifndef __STOCHASTIC_CONTRACTOR_H_
17#define __STOCHASTIC_CONTRACTOR_H_ 1
18
19#include "BaseContractor.h"
20
21#include <boost/container_hash/hash.hpp>
22#include <random>
23
24namespace TensorNetworks {
25
32public:
39 StochasticContractor() : gen(std::random_device{}()) {}
40
47 double Contract(const TensorNetwork &network, Types::qubit_t qubit) override {
48 // algorithm very similar with the 'Algorithm 2' from arXiv:1709.03636v2
49 // [quant-ph] 22 Dec 2018 qTorch: The quantum tensor contraction handler
50 // there are some changes, though, in picking up the contraction
51
52 long long int CostThreshold = -1;
53 size_t rejections = 0;
54
55 std::vector<Eigen::Index> keys;
56 std::unordered_map<Eigen::Index, Eigen::Index> keysKeys;
57
58 auto tensors = InitializeTensors(network, qubit, keys, keysKeys);
59
60 using TensorPair = std::pair<Eigen::Index, Eigen::Index>;
61 std::unordered_set<TensorPair, boost::hash<TensorPair>> visitedPairs;
62
63 // while there is more than one tensor...
64 while (tensors.size() > 1) {
65 // choose a random tensor
66 std::uniform_int_distribution<Eigen::Index> tensor1Dist(
67 0LL, static_cast<Eigen::Index>(keys.size()) - 1);
68 auto pos1 = tensor1Dist(gen);
69 Eigen::Index tensor1Id = keys[pos1];
70 const auto tensor1 = tensors[tensor1Id];
71
72 // then a random tensor it is connected to
73 // this favors the ones that have more connection with the chosen one
74
75 std::uniform_int_distribution<Eigen::Index> tensor2Dist(
76 0LL, static_cast<Eigen::Index>(tensor1->connections.size()) - 1);
77 auto pos2 = tensor2Dist(gen);
78 Eigen::Index tensor2Id = tensor1->connections[pos2];
79
80 auto t1 = tensor1Id;
81 auto t2 = tensor2Id;
82 if (t1 > t2)
83 std::swap(t1, t2);
84 if (visitedPairs.find(std::make_pair(t1, t2)) != visitedPairs.end()) {
85 ++rejections;
86 if (rejections >= MaxRejections) {
87 ++CostThreshold;
88 rejections = 0;
89 visitedPairs.clear();
90 }
91 continue;
92 } else
93 visitedPairs.insert(std::make_pair(t1, t2));
94
95 const auto tensor2 = tensors[tensor2Id];
96
97 const auto keysKeysIt = keysKeys.find(tensor2Id);
98 if (keysKeysIt != keysKeys.end())
99 pos2 = keysKeysIt->second;
100
101 const Eigen::Index resultRank = GetResultRank(tensor1, tensor2);
102 // const Eigen::Index Cost = resultRank - std::max(tensor1->GetRank(),
103 // tensor2->GetRank());
104 const Eigen::Index Cost =
105 resultRank - (tensor1->GetRank() + tensor2->GetRank()) / 2;
106 if (Cost <= CostThreshold) {
107 rejections = 0;
108 CostThreshold = -1;
109
110 ContractNodes(qubit, tensors, tensor1Id, tensor2Id, resultRank);
111
112 visitedPairs.clear();
113
114 // also remove them from 'keys' vector
115 // actually only one needs to be removed, the other one will be replaced
116 // by the result tensor
117 if (pos1 == static_cast<Eigen::Index>(keys.size()) - 1)
118 pos1 = pos2;
119
120 keys[pos2] = keys.back();
121 keysKeys[keys[pos2]] = pos2;
122 keysKeys.erase(tensor2Id);
123 keys.resize(keys.size() - 1);
124
125 if (resultRank == 0) {
126 if (tensors.size() == 1 ||
127 tensors[tensor1Id]->contractsTheNeededQubit)
128 return std::real(tensors[tensor1Id]->tensor->atOffset(0));
129
130 // erasing this tensor happens because (not the case anymore, it's
131 // avoided) the tensor network might be a disjoint one and a
132 // subnetwork is contracted that does not contain the needed qubit
133 keys[pos1] = keys.back();
134 keysKeys[keys[pos1]] = pos1;
135 keysKeys.erase(tensor1Id);
136 keys.resize(keys.size() - 1);
137
138 tensors.erase(tensor1Id);
139 }
140 } else {
141 ++rejections;
142 if (rejections >= MaxRejections) {
143 ++CostThreshold;
144 rejections = 0;
145 visitedPairs.clear();
146 }
147 }
148 }
149
150 return std::real(tensors.begin()->second->tensor->atOffset(0));
151 }
152
153 size_t GetMaxRejections() const { return MaxRejections; }
154
155 void SetMaxRejections(size_t maxRejections) { MaxRejections = maxRejections; }
156
162 std::shared_ptr<ITensorContractor> Clone() const override {
163 auto cloned = std::make_shared<StochasticContractor>();
164
165 cloned->maxTensorRank = maxTensorRank;
166 cloned->enableMultithreading = enableMultithreading;
167 cloned->MaxRejections = MaxRejections;
168
169 return cloned;
170 }
171
172protected:
173 std::mt19937 gen;
174 size_t MaxRejections = 15;
175};
176
177} // namespace TensorNetworks
178
179#endif // __STOCHASTIC_CONTRACTOR_H_
The Base Class Tensor Contractor.
bool enableMultithreading
A flag to indicate if multithreading should be enabled.
TensorsMap InitializeTensors(const TensorNetwork &network, Types::qubit_t qubit, std::vector< Eigen::Index > &keys, std::unordered_map< Eigen::Index, Eigen::Index > &keysKeys, bool fillKeys=true, bool contract=true) override
Eigen::Index ContractNodes(Types::qubit_t qubit, PassedTensorsMap &tensors, Eigen::Index tensor1Id, Eigen::Index tensor2Id, Eigen::Index resultRank)
size_t maxTensorRank
The maximum rank of the tensors in the network.
static size_t GetResultRank(const std::shared_ptr< TensorNode > &tensor1, const std::shared_ptr< TensorNode > &tensor2)
std::shared_ptr< ITensorContractor > Clone() const override
Clone the tensor contractor.
void SetMaxRejections(size_t maxRejections)
double Contract(const TensorNetwork &network, Types::qubit_t qubit) override
Contract the tensor network.
uint_fast64_t qubit_t
The type of a qubit.
Definition Types.h:20