34 template<
double (*scoreFct)(
double,
double,
double,
double,
double)>
38 double numNodes = 0, numEdges = 0;
39 for (
const auto &node : _network.
nodes) {
42 numEdges +=
static_cast<double>(node.degree());
46 if (_bestCost < 2 * 2 * numNodes * numEdges) {
return; }
48 double bestScore, ourCost=0;
49 double ourFinalCost=0;
50 std::vector<std::pair<size_t,size_t>> ourContractions;
51 size_t bestId1, bestId2;
53 bestScore = std::numeric_limits<double>::max();
54 for (
size_t i = 0; i < _network.
nodes.size(); ++i) {
55 if (_network.
nodes[i].erased) {
continue; }
57 for (
size_t j = i+1; j < _network.
nodes.size(); ++j) {
58 if (_network.
nodes[j].erased) {
continue; }
63 for (
size_t d = 0; d < ni.
degree(); ++d) {
65 r *=
static_cast<double>(ni.
neighbors[d].dimension);
67 m *=
static_cast<double>(ni.
neighbors[d].dimension);
70 for (
size_t d = 0; d < nj.
degree(); ++d) {
72 n *=
static_cast<double>(nj.
neighbors[d].dimension);
75 double tmpscore = scoreFct(m,n,r,0.0,0.0);
76 if (tmpscore < bestScore) {
84 if (bestScore < std::numeric_limits<double>::max()) {
85 ourFinalCost += ourCost;
86 if (ourFinalCost > _bestCost) {
89 ourContractions.emplace_back(bestId1,bestId2);
92 }
while (bestScore < std::numeric_limits<double>::max());
93 if (ourFinalCost < _bestCost) {
94 _bestCost = ourFinalCost;
95 _contractions = std::move(ourContractions);
109 double score_size(
double _m,
double _n,
double _r,
double ,
double ) {
110 return _n*_m-(_n+_m)*_r;
112 double score_mn(
double _m,
double _n,
double ,
double ,
double ) {
115 double score_speed(
double _m,
double _n,
double _r,
double ,
double ) {
116 return (_n*_m-(_n+_m)*_r)/(_n*_m*_r);
118 double score_r(
double ,
double ,
double _r,
double ,
double ) {
122 if (_n*_m<(_n+_m)*_r) {
123 return -1e10 + _n*_m*_r;
125 return _n*_m-(_n+_m)*_r;
129 if (_n*_m<(_n+_m)*_r) {
130 return -std::max(_n,_m)*_r;
132 return _n*_m-(_n+_m)*_r;
142 double sa=1, sb=1, sc=1;
143 double sab=1, sbc=1, sac=1;
144 for (
size_t d = 0; d < na.
degree(); ++d) {
146 sab *=
static_cast<double>(na.
neighbors[d].dimension);
147 }
else if (na.
neighbors[d].links(_id3)) {
148 sac *=
static_cast<double>(na.
neighbors[d].dimension);
150 sa *=
static_cast<double>(na.
neighbors[d].dimension);
153 for (
size_t d = 0; d < nb.
degree(); ++d) {
155 sbc *=
static_cast<double>(nb.
neighbors[d].dimension);
156 }
else if (!nb.
neighbors[d].links(_id1)) {
157 sb *=
static_cast<double>(nb.
neighbors[d].dimension);
160 for (
size_t d = 0; d < nc.
degree(); ++d) {
163 sc *=
static_cast<double>(nc.
neighbors[d].dimension);
167 double costAB = sa*sb*sac*sbc*(sab+sc);
168 double costAC = sa*sc*sab*sbc*(sac+sb);
169 double costBC = sb*sc*sab*sac*(sbc+sa);
170 if (costAB < costAC && costAB < costBC) {
171 return std::tuple<size_t, size_t, size_t, double>(_id1, _id2, _id3, sa*sb*sac*sbc*sab);
173 if (costAC < costBC) {
174 return std::tuple<size_t, size_t, size_t, double>(_id1, _id3, _id2, sa*sc*sab*sbc*sac);
176 return std::tuple<size_t, size_t, size_t, double>(_id2, _id3, _id1, sb*sc*sab*sac*sbc);
183 size_t numNodes=0, numEdges=0;
184 for (
const auto &node : _network.
nodes) {
187 numEdges += node.degree();
191 if (_bestCost <
double(2 * 3 * numNodes * numEdges)) {
return; }
193 double ourFinalCost=0;
194 std::vector<std::pair<size_t,size_t>> ourContractions;
195 while (numNodes >= 3) {
198 size_t currDegree=~0ul;
199 for (
size_t i=0; i<_network.
nodes.size(); ++i) {
200 if (!_network.
nodes[i].erased) {
201 if (_network.
nodes[i].degree() < currDegree) {
203 currDegree = _network.
nodes[i].degree();
213 if (_network.
nodes[l.other].degree() < currDegree) {
215 currDegree = _network.
nodes[l.other].degree();
222 while (id3 == id1 || id3 == id2 || _network.
nodes[id3].erased) {
225 size_t numConnections = 0;
227 if (l.links(id1) || l.links(id2)) {
232 for (
size_t i=id3+1; i<_network.
nodes.size(); ++i) {
233 if (i == id1 || i == id2) {
continue; }
234 size_t newConnections=0;
236 if (l.links(id1) || l.links(id2)) {
240 if (newConnections > numConnections) {
241 numConnections = newConnections;
247 std::tuple<size_t, size_t, size_t, double> contraction =
best_of_three(_network, id1, id2, id3);
248 ourFinalCost += std::get<3>(contraction);
249 if (ourFinalCost > _bestCost) {
257 ourContractions.emplace_back(std::get<0>(contraction), std::get<1>(contraction));
258 _network.
contract(std::get<0>(contraction), std::get<1>(contraction));
260 LOG(cont, std::get<0>(contraction) <<
" " << std::get<1>(contraction));
264 ourContractions.emplace_back(id1, id2);
265 LOG(cont, id1 <<
" " << id2);
270 LOG(hahaha, ourFinalCost <<
" vs " << _bestCost);
271 if (ourFinalCost < _bestCost) {
272 _bestCost = ourFinalCost;
273 _contractions = std::move(ourContractions);
283 for (
const auto &node : _network.
nodes) {
285 numEdges +=
static_cast<double>(node.degree());
289 double cost_of_heuristic = 3*numEdges;
291 if (_bestCost < 2 * cost_of_heuristic) {
return; }
294 std::vector<std::pair<size_t, size_t>> openPairs;
295 openPairs.push_back(_contractions.front());
297 double ourFinalCost=0;
298 std::vector<std::pair<size_t,size_t>> ourContractions;
299 std::vector<size_t> idMap;
300 for (
size_t i =0; i<_network.
nodes.size(); ++i) {
301 idMap.emplace_back(i);
304 for (
size_t i=1; i<_contractions.size(); ++i) {
305 std::pair<size_t, size_t> next = _contractions[i];
306 while (next.first != idMap[next.first]) { next.first = idMap[next.first]; }
307 while (next.second != idMap[next.second]) { next.second = idMap[next.second]; }
309 std::vector<std::pair<size_t, size_t>> newOpenPairs;
310 for (
const std::pair<size_t, size_t> &p : openPairs) {
311 size_t id1 = p.first;
312 while (id1 != idMap[id1]) { id1 = idMap[id1]; }
313 size_t id2 = p.second;
314 while (id2 != idMap[id2]) { id2 = idMap[id2]; }
315 if (next.first != id1 && next.first != id2) {
316 if (next.second == id1 || next.second == id2) {
318 size_t a = std::get<0>(contr);
319 size_t b = std::get<1>(contr);
320 size_t c = std::get<2>(contr);
322 ourFinalCost += std::get<3>(contr);
323 ourContractions.emplace_back(a,b);
328 newOpenPairs.emplace_back(id1,id2);
331 if (next.second == id1 || next.second == id2) {
335 size_t a = std::get<0>(contr);
336 size_t b = std::get<1>(contr);
337 size_t c = std::get<2>(contr);
339 ourFinalCost += std::get<3>(contr);
340 ourContractions.emplace_back(a,b);
347 newOpenPairs.emplace_back(next);
348 openPairs = std::move(newOpenPairs);
353 ourFinalCost += _network.
contraction_cost(openPairs.front().first, openPairs.front().second);
354 ourContractions.emplace_back(openPairs.front());
357 if (ourFinalCost < _bestCost) {
359 if (_bestCost - ourFinalCost > cost_of_heuristic * 2) {
362 _bestCost = ourFinalCost;
363 _contractions = std::move(ourContractions);
373 &greedy_heuristic<&score_size>,
374 &greedy_heuristic<&score_mn>,
375 &greedy_heuristic<&score_speed>,
377 &greedy_heuristic<&score_big_tensor>,
378 &greedy_heuristic<&score_littlestep>
Header file for CHECK and REQUIRE macros.
void contract(const size_t _nodeId1, const size_t _nodeId2)
Contracts the nodes with indices _nodeId1 and _nodeId2.
double score_littlestep(double _m, double _n, double _r, double _sparsity1, double _sparsity2)
const std::vector< ContractionHeuristic > contractionHeuristics
Very general class used to represent arbitary tensor networks.
void greedy_best_of_three_heuristic(double &_bestCost, std::vector< std::pair< size_t, size_t >> &_contractions, TensorNetwork _network)
The TensorNode class is used by the class TensorNetwork to store the componentent tensors defining th...
double contraction_cost(double _m, double _n, double _r, double _sparsity1, double _sparsity2)
The main namespace of xerus.
Class representing a link from a TensorNode to another node or an external index. ...
double score_mn(double _m, double _n, double _r, double _sparsity1, double _sparsity2)
double contraction_cost(const size_t _nodeId1, const size_t _nodeId2) const
Approximates the cost of contraction two given nodes.
void exchange_heuristic(double &_bestCost, std::vector< std::pair< size_t, size_t >> &_contractions, TensorNetwork _network)
std::tuple< size_t, size_t, size_t, double > best_of_three(const TensorNetwork &_network, size_t _id1, size_t _id2, size_t _id3)
Header file for comfort functions and macros that should not be exported in the library.
size_t degree() const noexcept
Header file for the class managing the contraction heuristics.
void greedy_heuristic(double &_bestCost, std::vector< std::pair< size_t, size_t >> &_contractions, TensorNetwork _network)
double score_big_tensor(double _m, double _n, double _r, double _sparsity1, double _sparsity2)
std::vector< Link > neighbors
Vector of links defining the connection of this node to the network.
Header file for the TensorNetwork class.
double score_r(double _m, double _n, double _r, double _sparsity1, double _sparsity2)
double score_size(double _m, double _n, double _r, double _sparsity1, double _sparsity2)
std::vector< TensorNode > nodes
The nodes constituting the network. The order determines the ids of the nodes.
double score_speed(double _m, double _n, double _r, double _sparsity1, double _sparsity2)