Maestro 0.3.11
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{
26
33{
34 public:
41 StochasticContractor() : gen(std::random_device{}())
42 {
43 }
44
51 double Contract(const TensorNetwork &network, Types::qubit_t qubit) override
52 {
53 // algorithm very similar with the 'Algorithm 2' from arXiv:1709.03636v2
54 // [quant-ph] 22 Dec 2018 qTorch: The quantum tensor contraction handler
55 // there are some changes, though, in picking up the contraction
56
57 long long int CostThreshold = -1;
58 size_t rejections = 0;
59
60 std::vector<Eigen::Index> keys;
61 std::unordered_map<Eigen::Index, Eigen::Index> keysKeys;
62
63 auto tensors = InitializeTensors(network, qubit, keys, keysKeys);
64
65 using TensorPair = std::pair<Eigen::Index, Eigen::Index>;
66 std::unordered_set<TensorPair, boost::hash<TensorPair>> visitedPairs;
67
68 // while there is more than one tensor...
69 while (tensors.size() > 1)
70 {
71 // choose a random tensor
72 std::uniform_int_distribution<Eigen::Index> tensor1Dist(0LL, static_cast<Eigen::Index>(keys.size()) - 1);
73 auto pos1 = tensor1Dist(gen);
74 Eigen::Index tensor1Id = keys[pos1];
75 const auto tensor1 = tensors[tensor1Id];
76
77 // then a random tensor it is connected to
78 // this favors the ones that have more connection with the chosen one
79
80 std::uniform_int_distribution<Eigen::Index> tensor2Dist(0LL, static_cast<Eigen::Index>(tensor1->connections.size()) - 1);
81 auto pos2 = tensor2Dist(gen);
82 Eigen::Index tensor2Id = tensor1->connections[pos2];
83
84 auto t1 = tensor1Id;
85 auto t2 = tensor2Id;
86 if (t1 > t2)
87 std::swap(t1, t2);
88 if (visitedPairs.find(std::make_pair(t1, t2)) != visitedPairs.end())
89 {
90 ++rejections;
91 if (rejections >= MaxRejections)
92 {
93 ++CostThreshold;
94 rejections = 0;
95 visitedPairs.clear();
96 }
97 continue;
98 }
99 else
100 visitedPairs.insert(std::make_pair(t1, t2));
101
102 const auto tensor2 = tensors[tensor2Id];
103
104 const auto keysKeysIt = keysKeys.find(tensor2Id);
105 if (keysKeysIt != keysKeys.end())
106 pos2 = keysKeysIt->second;
107
108 const Eigen::Index resultRank = GetResultRank(tensor1, tensor2);
109 // const Eigen::Index Cost = resultRank - std::max(tensor1->GetRank(),
110 // tensor2->GetRank());
111 const Eigen::Index Cost = resultRank - (tensor1->GetRank() + tensor2->GetRank()) / 2;
112 if (Cost <= CostThreshold)
113 {
114 rejections = 0;
115 CostThreshold = -1;
116
117 ContractNodes(qubit, tensors, tensor1Id, tensor2Id, resultRank);
118
119 visitedPairs.clear();
120
121 // also remove them from 'keys' vector
122 // actually only one needs to be removed, the other one will be replaced
123 // by the result tensor
124 if (pos1 == static_cast<Eigen::Index>(keys.size()) - 1)
125 pos1 = pos2;
126
127 keys[pos2] = keys.back();
128 keysKeys[keys[pos2]] = pos2;
129 keysKeys.erase(tensor2Id);
130 keys.resize(keys.size() - 1);
131
132 if (resultRank == 0)
133 {
134 if (tensors.size() == 1 || tensors[tensor1Id]->contractsTheNeededQubit)
135 return std::real(tensors[tensor1Id]->tensor->atOffset(0));
136
137 // erasing this tensor happens because (not the case anymore, it's
138 // avoided) the tensor network might be a disjoint one and a
139 // subnetwork is contracted that does not contain the needed qubit
140 keys[pos1] = keys.back();
141 keysKeys[keys[pos1]] = pos1;
142 keysKeys.erase(tensor1Id);
143 keys.resize(keys.size() - 1);
144
145 tensors.erase(tensor1Id);
146 }
147 }
148 else
149 {
150 ++rejections;
151 if (rejections >= MaxRejections)
152 {
153 ++CostThreshold;
154 rejections = 0;
155 visitedPairs.clear();
156 }
157 }
158 }
159
160 return std::real(tensors.begin()->second->tensor->atOffset(0));
161 }
162
163 size_t GetMaxRejections() const
164 {
165 return MaxRejections;
166 }
167
168 void SetMaxRejections(size_t maxRejections)
169 {
170 MaxRejections = maxRejections;
171 }
172
178 std::shared_ptr<ITensorContractor> Clone() const override
179 {
180 auto cloned = std::make_shared<StochasticContractor>();
181
182 cloned->maxTensorRank = maxTensorRank;
183 cloned->enableMultithreading = enableMultithreading;
184 cloned->MaxRejections = MaxRejections;
185
186 return cloned;
187 }
188
189 protected:
190 std::mt19937 gen;
191 size_t MaxRejections = 15;
192};
193
194} // namespace TensorNetworks
195
196#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:23