LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
arborescence.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2022 CEA LIST <gael.de-chalendar@cea.fr>
2//
3// SPDX-License-Identifier: MIT
4
5#ifndef ARBORESCENCE_H
6#define ARBORESCENCE_H
7
8#include <vector>
9#include <set>
10#include <map>
11#include <list>
12#include <iostream>
13#include <iterator> // needed for std::ostram_iterator
14#include <sstream>
15#include <boost/pending/disjoint_sets.hpp>
16
17namespace deeplima
18{
19
20// template <typename T>
21// std::ostream& operator<< (std::ostream& out, const std::vector<T>& v) {
22// out << '[';
23// if ( !v.empty() ) {
24// std::copy (v.begin(), v.end(), std::ostream_iterator<T>(out, ", "));
25// }
26// out << "]";
27// return out;
28// }
29
30namespace impl
31{
32
33template <class M,
34 typename vertex_idx_t,
35 typename weight_t>
37{
38 struct edge_t
39 {
40 vertex_idx_t source;
41 vertex_idx_t target;
42 weight_t weight;
43 edge_t* parent = nullptr;
44 std::vector<edge_t*> children;
45 bool removed = false;
46
47 edge_t(const vertex_idx_t s, const vertex_idx_t t, const weight_t w)
48 : source(s), target(t), weight(w)
49 {}
50 };
51
52 static void remove_from_f(edge_t* e, std::vector<edge_t*>& f_roots)
53 {
54 // std::cerr << "remove_from_f" << std::endl;
55 while (e != nullptr)
56 {
57 e->removed = true;
58 for (edge_t* child : e->children)
59 {
60 f_roots.push_back(child);
61 child->parent = nullptr;
62 }
63
64 std::vector<edge_t*>().swap(e->children);
65
66 e = e->parent;
67 }
68 }
69
70public:
71
72 static void fill_heads_with_max(const std::function <float(size_t, size_t)>& adj_matrix,
73 size_t len,
74 std::vector<size_t>& heads)
75 {
76 // std::cerr << "fill_heads_with_max" << std::endl;
77 for (vertex_idx_t i = 1; i < len; i++)
78 {
79 vertex_idx_t max_id = 0;
80 float max_value = adj_matrix(i, max_id);
81 for (vertex_idx_t j = 1; j < len; j++)
82 {
83 if (i == j)
84 continue;
85
86 if (adj_matrix(i, j) > max_value)
87 {
88 max_id = j;
89 max_value = adj_matrix(i, j);
90 }
91 }
92 heads[i] = max_id;
93 }
94 }
95
99 static size_t count_roots(typename std::vector<vertex_idx_t>::const_iterator pos,
100 typename std::vector<vertex_idx_t>::const_iterator end)
101 {
102 // std::cerr << "count_roots pos=" << *pos << "; end=" << *end << std::endl;
103 size_t c = 0;
104 pos++;
105 for (; pos != end; pos++)
106 {
107 if (*pos == 0)
108 c++;
109 }
110 // std::cerr << "count_roots: " << c << std::endl;
111 return c;
112 }
113
114 static bool is_connected(typename std::vector<vertex_idx_t>::const_iterator pos,
115 typename std::vector<vertex_idx_t>::const_iterator end)
116 {
117 // std::cerr << "is_connected" << std::endl;
118 std::vector< std::vector<size_t> > head2child;
119 size_t len = end - pos;
120 head2child.resize(len);
121 pos++;
122 for (size_t i = 1; i < len; i++)
123 {
124 head2child[*pos].push_back(i);
125 pos++;
126 }
127
128 std::vector<size_t> visited(len, 0);
129 std::vector<size_t> stack;
130 stack.reserve(len);
131 stack.push_back(0);
132 while (stack.size() > 0)
133 {
134 size_t from = stack.back();
135 stack.pop_back();
136
137 for (size_t to : head2child[from])
138 {
139 if (visited[to] == 0)
140 {
141 stack.push_back(to);
142 visited[to] += 1;
143 }
144 }
145 }
146
147 for (size_t i = 1; i < visited.size(); i++)
148 if (visited[i] == 0)
149 return false;
150
151 return true;
152 }
153
154 static void find_disconnected_groups(const std::vector< std::vector<size_t> >& head2child,
155 size_t len,
156 std::vector<size_t>& accessibility_map)
157 {
158 // std::cerr << "find_disconnected_groups" << std::endl;
159 std::fill(accessibility_map.begin(), accessibility_map.end(), 0);
160
161 std::vector<size_t> stack;
162 stack.reserve(len);
163 stack.push_back(0);
164 while (stack.size() > 0)
165 {
166 size_t from = stack.back();
167 stack.pop_back();
168
169 for (size_t to : head2child[from])
170 {
171 if (accessibility_map[to] == 0)
172 {
173 stack.push_back(to);
174 accessibility_map[to] += 1;
175 }
176 }
177 }
178 }
179
180 static void find_loops(const std::vector<vertex_idx_t>& heads,
181 std::vector< std::vector<size_t> >& loops,
182 const std::vector<size_t>& connected,
183 size_t len,
184 size_t offset)
185 {
186 // std::cerr << "find_loops" << std::endl;
187 std::vector<size_t> visited = connected;
188 loops.clear();
189
190 for (size_t i = 1; i < len; i++)
191 {
192 if (visited[i] > 0)
193 {
194 visited[i] = 1;
195 continue;
196 }
197
198 std::vector<size_t> loop_counter(len, 0);
199 std::list<size_t> loop_items;
200 size_t j = i;
201 while (loop_counter[j] == 0 && visited[j] == 0)
202 {
203 loop_counter[j] += 1;
204 loop_items.push_back(j);
205 j = heads[offset+j];
206 }
207
208 if (visited[j] > 0)
209 continue;
210
211 while (loop_items.front() != j)
212 loop_items.pop_front();
213
214 std::vector<size_t> new_loop;
215 for (size_t x : loop_items)
216 {
217 visited[x] = 1;
218 new_loop.push_back(x);
219 }
220
221 loops.push_back(new_loop);
222 }
223 }
224
225 static void make_connected(const M& adj_matrix,
226 std::vector<vertex_idx_t>& heads,
227 size_t offset)
228 {
229 // std::cerr << "make_connected" << std::endl;
230 std::vector< std::vector<size_t> > head2child;
231 size_t len = adj_matrix.rows();
232 assert(adj_matrix.rows() == adj_matrix.cols());
233 head2child.resize(len);
234 for (size_t i = 1; i < len; i++)
235 {
236 head2child[heads[offset+i]].push_back(i);
237 }
238
239 std::vector<size_t> connected(len, 0);
240 find_disconnected_groups(head2child, len, connected);
241
242 while (std::find(std::next(connected.begin()), connected.end(), 0) != connected.end())
243 {
244 std::vector< std::vector<size_t> > loops;
245 find_loops(heads, loops, connected, len, offset);
246
247 std::pair<size_t, size_t> best_new_arc = std::make_pair(0, 0); // child -> parent
248 float best_score = 0;
249 for (size_t l = 0; l < loops.size(); l++)
250 {
251 for (size_t i = 0; i < loops[l].size(); i++)
252 {
253 size_t from = loops[l][i];
254 for (size_t j = 1; j < len; j++)
255 {
256 if (connected[j] == 0)
257 continue; // we have no intentions to create new loops
258 if (j == heads[offset+from])
259 continue; // this value of j changes nothing
260 if (adj_matrix(from, j) > best_score || best_new_arc.first == 0)
261 {
262 best_score = adj_matrix(from, j);
263 best_new_arc = std::make_pair(from, j);
264 }
265 }
266 }
267 }
268
269 if (best_new_arc.first == 0 || best_new_arc.second == 0)
270 throw std::runtime_error("make_connected best_new_arc first or second should be 0");
271
272 heads[offset+best_new_arc.first] = best_new_arc.second;
273
274 head2child.clear();
275 head2child.resize(len);
276 for (size_t i = 1; i < len; i++)
277 {
278 head2child[heads[offset+i]].push_back(i);
279 }
280
281 std::fill(connected.begin(), connected.end(), 0);
282 find_disconnected_groups(head2child, len, connected);
283 }
284 }
285
286 static void choose_one_root(const M& adj_matrix,
287 std::vector<vertex_idx_t>& heads,
288 size_t offset)
289 {
290 // std::cerr << "choose_one_root" << std::endl;
291 assert(adj_matrix.rows() == adj_matrix.cols());
292 size_t len = adj_matrix.rows();
293
294 std::vector<std::pair<size_t, float>> roots;
295 roots.reserve(16);
296 for (size_t i = 1; i < len; i++)
297 {
298 if (heads[offset + i] == 0)
299 {
300 roots.push_back(std::make_pair(i, adj_matrix(i, 0)));
301 }
302 }
303
304 if (roots.size() == 0)
305 // This function is intended to choose from a several (> 0) of roots
306 throw std::runtime_error("choose_one_root should have at least one root");
307
308 if (roots.size() == 1)
309 return;
310
311 size_t best_root = 0;
312 float best_root_score = 0;
313 for (size_t i = 0; i < roots.size(); i++)
314 {
315 if (best_root == 0 || roots[i].second > best_root_score)
316 {
317 best_root = roots[i].first;
318 best_root_score = roots[i].second;
319 }
320 }
321
322 for (auto& r : roots)
323 {
324 if (r.first != best_root)
325 heads[offset + r.first] = best_root;
326 }
327 }
328
329 static void choose_root(const M& adj_matrix,
330 std::vector<vertex_idx_t>& heads,
331 size_t offset)
332 {
333 // std::cerr << "choose_root" << std::endl;
334 assert(adj_matrix.rows() == adj_matrix.cols());
335 size_t len = adj_matrix.rows();
336
337 if (len < 3)
338 {
339 heads[offset + 1] = 0;
340 return;
341 }
342
343 size_t best_root = 1;
344 float best_root_score = adj_matrix(best_root, 0);
345 for (size_t i = 2; i < len; i++)
346 {
347 if (adj_matrix(i, 0) > best_root_score)
348 {
349 best_root = i;
350 best_root_score = adj_matrix(i, 0);
351 }
352 }
353
354 heads[offset + best_root] = 0;
355 }
356
357 // adj_matrix[i][j]: i <- j (j is head)
358 static void arborescence_impl(const M& adj_matrix,
359 std::vector<vertex_idx_t>& heads,
360 size_t offset)
361 {
362 // std::cerr << "arborescence_impl" << std::endl;
363 assert(adj_matrix.rows() == adj_matrix.cols());
364 size_t len = adj_matrix.rows();
365
366 std::vector<edge_t> all_edges;
367 all_edges.reserve(len * len); // TODO: move memory allocation out of this function
368 std::vector<std::vector<edge_t*>> in_edges;
369 in_edges.resize(len);
370
371 for (vertex_idx_t i = 1; i < len; i++)
372 for (vertex_idx_t j = 1; j < len; j++)
373 {
374 if (i == j)
375 continue;
376 all_edges.push_back(edge_t(j, i, adj_matrix(i, j)));
377 in_edges[i].push_back(&all_edges.back());
378 }
379
380 for (edge_t& e : all_edges)
381 in_edges[e.target].push_back(&e);
382
383 std::vector<std::vector<edge_t*>> cycle(len);
384 std::vector<edge_t*> lambda(len);
385 std::vector<vertex_idx_t> roots;
386 std::vector<vertex_idx_t> final_roots; // = { 0 };
387 boost::disjoint_sets_with_storage<> S(2 * len);
388 boost::disjoint_sets_with_storage<> W(2 * len);
389 std::vector<vertex_idx_t> min(len);
390 std::vector<edge_t*> enter(len);
391 std::vector<edge_t*> F;
392 std::vector<weight_t> edge_weight_change(len);
393
394 for (vertex_idx_t v = 0; v < len; ++v)
395 {
396 S.make_set(v);
397 W.make_set(v);
398 min[v] = v;
399 if (v != 0)
400 roots.push_back(v);
401 }
402
403 while (!roots.empty())
404 {
405 vertex_idx_t curr = roots.back();
406 roots.pop_back();
407
408 if (in_edges[curr].empty())
409 {
410 final_roots.push_back(min[curr]);
411 continue;
412 }
413
414 edge_t *optimal_in_edge = in_edges[curr].front();
415 for (edge_t* e : in_edges[curr])
416 if (e->weight > optimal_in_edge->weight)
417 optimal_in_edge = e;
418
419 F.push_back(optimal_in_edge);
420 for (edge_t* e : cycle[curr])
421 {
422 e->parent = optimal_in_edge;
423 optimal_in_edge->children.push_back(e);
424 }
425
426 if (cycle[curr].empty())
427 lambda[curr] = optimal_in_edge;
428
429 // adding optimal_in_edge don't create a cycle
430 if (W.find_set(optimal_in_edge->source) != W.find_set(optimal_in_edge->target))
431 {
432 enter[curr] = optimal_in_edge;
433 W.union_set(optimal_in_edge->source, optimal_in_edge->target);
434 }
435 else // adding optimal_in_edge creates a cycle
436 {
437 std::vector<edge_t*> cycle_edges = { optimal_in_edge };
438 std::vector<vertex_idx_t> cycle_repr = { S.find_set(optimal_in_edge->target) };
439 edge_t* least_costly_edge = optimal_in_edge;
440 enter[curr] = nullptr;
441
442 for (vertex_idx_t v = S.find_set(optimal_in_edge->source);
443 enter[v] != nullptr;
444 v = S.find_set(enter[v]->source))
445 {
446 cycle_edges.push_back(enter[v]);
447 cycle_repr.push_back(v);
448
449 if (enter[v]->weight < least_costly_edge->weight)
450 least_costly_edge = enter[v];
451 }
452
453 for (edge_t* e : cycle_edges)
454 edge_weight_change[S.find_set(e->target)] = least_costly_edge->weight - e->weight;
455
456 vertex_idx_t cycle_root = min[S.find_set(least_costly_edge->target)];
457
458 // Union all components of the cycle into one component
459 vertex_idx_t new_repr = cycle_repr.front();
460 for (vertex_idx_t v : cycle_repr)
461 {
462 S.link(v, new_repr);
463 new_repr = S.find_set(new_repr);
464 }
465 min[new_repr] = cycle_root;
466 roots.push_back(new_repr);
467 cycle[new_repr].swap(cycle_edges);
468
469 for (vertex_idx_t v : cycle_repr)
470 {
471 for (edge_t* e : in_edges[v])
472 {
473 e->weight += edge_weight_change[v];
474 }
475 }
476
477 std::vector<edge_t*> new_in_edges;
478 for (size_t i = 1; i < cycle_repr.size(); ++i)
479 {
480 typename std::vector<edge_t*>::iterator i1 = in_edges[cycle_repr[i]].begin();
481 typename std::vector<edge_t*>::iterator e1 = in_edges[cycle_repr[i]].end();
482 typename std::vector<edge_t*>::iterator i2 = in_edges[cycle_repr[i-1]].begin();
483 typename std::vector<edge_t*>::iterator e2 = in_edges[cycle_repr[i-1]].end();
484
485 while (i1 != e1 || i2 != e2)
486 {
487 while (i1 != e1 && S.find_set((*i1)->source) == new_repr)
488 ++i1;
489
490 while (i2 != e2 && S.find_set((*i2)->source) == new_repr)
491 ++i2;
492
493 if (i1 == e1 && i2 == e2)
494 break;
495
496 if (i1 == e1)
497 {
498 new_in_edges.push_back(*i2);
499 ++i2;
500 }
501 else if (i2 == e2)
502 {
503 new_in_edges.push_back(*i1);
504 ++i1;
505 }
506 else if ( (*i1)->source < (*i2)->source )
507 {
508 new_in_edges.push_back(*i1);
509 ++i1;
510 }
511 else if ( (*i1)->source > (*i2)->source )
512 {
513 new_in_edges.push_back(*i2);
514 ++i2;
515 }
516 else
517 {
518 if ( (*i1)->weight > (*i2)->weight )
519 new_in_edges.push_back(*i1);
520 else
521 new_in_edges.push_back(*i2);
522
523 ++i1;
524 ++i2;
525 }
526 }
527
528 in_edges[cycle_repr[i]].swap(new_in_edges);
529 new_in_edges.clear();
530 }
531
532 in_edges[new_repr].swap(in_edges[cycle_repr.back()]);
533 edge_weight_change[new_repr] = weight_t(0);
534 }
535 }
536
537 std::vector<edge_t*> F_roots;
538 for (edge_t* e : F)
539 {
540 if (e->parent == nullptr)
541 F_roots.push_back(e);
542 }
543
544 for (vertex_idx_t v : final_roots)
545 {
546 if (lambda[v] != nullptr)
547 remove_from_f(lambda[v], F_roots);
548 }
549
550 while (!F_roots.empty())
551 {
552 edge_t* e = F_roots.back();
553 F_roots.pop_back();
554
555 if (e->removed)
556 continue;
557
558 heads[offset + e->target] = e->source;
559 remove_from_f(lambda[e->target], F_roots);
560 }
561
562 return;
563 }
564};
565
566template <typename vertex_idx_t,
567 typename weight_t>
569{
570 struct edge_t
571 {
572 vertex_idx_t source;
573 vertex_idx_t target;
574 weight_t weight;
575 edge_t* parent = nullptr;
576 std::vector<edge_t*> children;
577 bool removed = false;
578
579 edge_t(const vertex_idx_t s, const vertex_idx_t t, const weight_t w)
580 : source(s), target(t), weight(w)
581 {}
582 };
583
584 static void remove_from_f(edge_t* e, std::vector<edge_t*>& f_roots)
585 {
586 // std::cerr << "remove_from_f" << std::endl;
587 while (e != nullptr)
588 {
589 e->removed = true;
590 for (edge_t* child : e->children)
591 {
592 f_roots.push_back(child);
593 child->parent = nullptr;
594 }
595
596 std::vector<edge_t*>().swap(e->children);
597
598 e = e->parent;
599 }
600 }
601
602public:
603
607 static size_t count_roots(typename std::vector<vertex_idx_t>::const_iterator pos,
608 typename std::vector<vertex_idx_t>::const_iterator end)
609 {
610 // std::cerr << "count_roots pos=" << *pos << "; end=" << *end << std::endl;
611 size_t c = 0;
612 pos++;
613 for (; pos != end; pos++)
614 {
615 if (*pos == 0)
616 c++;
617 }
618 // std::cerr << "count_roots: " << c << std::endl;
619 return c;
620 }
621
622 static bool is_connected(typename std::vector<vertex_idx_t>::const_iterator pos,
623 typename std::vector<vertex_idx_t>::const_iterator end)
624 {
625 // std::cerr << "is_connected" << std::endl;
626 std::vector< std::vector<size_t> > head2child;
627 size_t len = end - pos;
628 head2child.resize(len);
629 pos++;
630 for (size_t i = 1; i < len; i++)
631 {
632 head2child[*pos].push_back(i);
633 pos++;
634 }
635
636 std::vector<size_t> visited(len, 0);
637 std::vector<size_t> stack;
638 stack.reserve(len);
639 stack.push_back(0);
640 while (stack.size() > 0)
641 {
642 size_t from = stack.back();
643 stack.pop_back();
644
645 for (size_t to : head2child[from])
646 {
647 if (visited[to] == 0)
648 {
649 stack.push_back(to);
650 visited[to] += 1;
651 }
652 }
653 }
654
655 for (size_t i = 1; i < visited.size(); i++)
656 if (visited[i] == 0)
657 return false;
658
659 return true;
660 }
661
662 static void find_disconnected_groups(const std::vector< std::vector<size_t> >& head2child,
663 size_t len,
664 std::vector<size_t>& accessibility_map)
665 {
666 // std::cerr << "find_disconnected_groups" << std::endl;
667 std::fill(accessibility_map.begin(), accessibility_map.end(), 0);
668
669 std::vector<size_t> stack;
670 stack.reserve(len);
671 stack.push_back(0);
672 while (stack.size() > 0)
673 {
674 size_t from = stack.back();
675 stack.pop_back();
676
677 for (size_t to : head2child[from])
678 {
679 if (accessibility_map[to] == 0)
680 {
681 stack.push_back(to);
682 accessibility_map[to] += 1;
683 }
684 }
685 }
686 }
687
688 static void find_loops(const std::vector<vertex_idx_t>& heads,
689 std::vector< std::vector<size_t> >& loops,
690 const std::vector<size_t>& connected,
691 size_t len,
692 size_t offset)
693 {
694 // std::cerr << "find_loops" << std::endl;
695 std::vector<size_t> visited = connected;
696 loops.clear();
697
698 for (size_t i = 1; i < len; i++)
699 {
700 if (visited[i] > 0)
701 {
702 visited[i] = 1;
703 continue;
704 }
705
706 std::vector<size_t> loop_counter(len, 0);
707 std::list<size_t> loop_items;
708 size_t j = i;
709 while (loop_counter[j] == 0 && visited[j] == 0)
710 {
711 loop_counter[j] += 1;
712 loop_items.push_back(j);
713 j = heads[offset+j];
714 }
715
716 if (visited[j] > 0)
717 continue;
718
719 while (loop_items.front() != j)
720 loop_items.pop_front();
721
722 std::vector<size_t> new_loop;
723 for (size_t x : loop_items)
724 {
725 visited[x] = 1;
726 new_loop.push_back(x);
727 }
728
729 loops.push_back(new_loop);
730 }
731 }
732
733 // static void make_connected(std::vector<vertex_idx_t>& heads,
734 // size_t offset)
735 // {
736 // // std::cerr << "make_connected" << std::endl;
737 // std::vector< std::vector<size_t> > head2child;
738 // size_t len = adj_matrix.rows();
739 // assert(adj_matrix.rows() == adj_matrix.cols());
740 // head2child.resize(len);
741 // for (size_t i = 1; i < len; i++)
742 // {
743 // head2child[heads[offset+i]].push_back(i);
744 // }
745 //
746 // std::vector<size_t> connected(len, 0);
747 // find_disconnected_groups(head2child, len, connected);
748 //
749 // while (std::find(std::next(connected.begin()), connected.end(), 0) != connected.end())
750 // {
751 // std::vector< std::vector<size_t> > loops;
752 // find_loops(heads, loops, connected, len, offset);
753 //
754 // std::pair<size_t, size_t> best_new_arc = std::make_pair(0, 0); // child -> parent
755 // float best_score = 0;
756 // for (size_t l = 0; l < loops.size(); l++)
757 // {
758 // for (size_t i = 0; i < loops[l].size(); i++)
759 // {
760 // size_t from = loops[l][i];
761 // for (size_t j = 1; j < len; j++)
762 // {
763 // if (connected[j] == 0)
764 // continue; // we have no intentions to create new loops
765 // if (j == heads[offset+from])
766 // continue; // this value of j changes nothing
767 // if (adj_matrix(from, j) > best_score || best_new_arc.first == 0)
768 // {
769 // best_score = adj_matrix(from, j);
770 // best_new_arc = std::make_pair(from, j);
771 // }
772 // }
773 // }
774 // }
775 //
776 // if (best_new_arc.first == 0 || best_new_arc.second == 0)
777 // throw std::runtime_error("make_connected best_new_arc first or second should be 0");
778 //
779 // heads[offset+best_new_arc.first] = best_new_arc.second;
780 //
781 // head2child.clear();
782 // head2child.resize(len);
783 // for (size_t i = 1; i < len; i++)
784 // {
785 // head2child[heads[offset+i]].push_back(i);
786 // }
787 //
788 // std::fill(connected.begin(), connected.end(), 0);
789 // find_disconnected_groups(head2child, len, connected);
790 // }
791 // }
792
793 static void choose_one_root(std::vector<vertex_idx_t>& heads,
794 size_t offset)
795 {
796 // std::cerr << "choose_one_root" << std::endl;
797 // assert(adj_matrix.rows() == adj_matrix.cols());
798 // size_t len = adj_matrix.rows();
799 //
800 // std::vector<std::pair<size_t, float>> roots;
801 // roots.reserve(16);
802 // for (size_t i = 1; i < len; i++)
803 // {
804 // if (heads[offset + i] == 0)
805 // {
806 // roots.push_back(std::make_pair(i, adj_matrix(i, 0)));
807 // }
808 // }
809 //
810 // if (roots.size() == 0)
811 // // This function is intended to choose from a several (> 0) of roots
812 // throw std::runtime_error("choose_one_root should have at least one root");
813 //
814 // if (roots.size() == 1)
815 // return;
816 //
817 // size_t best_root = 0;
818 // float best_root_score = 0;
819 // for (size_t i = 0; i < roots.size(); i++)
820 // {
821 // if (best_root == 0 || roots[i].second > best_root_score)
822 // {
823 // best_root = roots[i].first;
824 // best_root_score = roots[i].second;
825 // }
826 // }
827 //
828 // for (auto& r : roots)
829 // {
830 // if (r.first != best_root)
831 // heads[offset + r.first] = best_root;
832 // }
833 }
834
835 static void choose_root(std::vector<vertex_idx_t>& heads,
836 size_t offset)
837 {
838 // // std::cerr << "choose_root" << std::endl;
839 // assert(adj_matrix.rows() == adj_matrix.cols());
840 // size_t len = adj_matrix.rows();
841 //
842 // if (len < 3)
843 // {
844 // heads[offset + 1] = 0;
845 // return;
846 // }
847 //
848 // size_t best_root = 1;
849 // float best_root_score = adj_matrix(best_root, 0);
850 // for (size_t i = 2; i < len; i++)
851 // {
852 // if (adj_matrix(i, 0) > best_root_score)
853 // {
854 // best_root = i;
855 // best_root_score = adj_matrix(i, 0);
856 // }
857 // }
858 //
859 // heads[offset + best_root] = 0;
860 }
861
862 // // adj_matrix[i][j]: i <- j (j is head)
863 // static void arborescence_impl(std::vector<vertex_idx_t>& heads,
864 // size_t offset)
865 // {
866 // // std::cerr << "arborescence_impl" << std::endl;
867 // assert(adj_matrix.rows() == adj_matrix.cols());
868 // size_t len = adj_matrix.rows();
869 //
870 // std::vector<edge_t> all_edges;
871 // all_edges.reserve(len * len); // TODO: move memory allocation out of this function
872 // std::vector<std::vector<edge_t*>> in_edges;
873 // in_edges.resize(len);
874 //
875 // for (vertex_idx_t i = 1; i < len; i++)
876 // for (vertex_idx_t j = 1; j < len; j++)
877 // {
878 // if (i == j)
879 // continue;
880 // all_edges.push_back(edge_t(j, i, adj_matrix(i, j)));
881 // in_edges[i].push_back(&all_edges.back());
882 // }
883 //
884 // for (edge_t& e : all_edges)
885 // in_edges[e.target].push_back(&e);
886 //
887 // std::vector<std::vector<edge_t*>> cycle(len);
888 // std::vector<edge_t*> lambda(len);
889 // std::vector<vertex_idx_t> roots;
890 // std::vector<vertex_idx_t> final_roots; // = { 0 };
891 // boost::disjoint_sets_with_storage<> S(2 * len);
892 // boost::disjoint_sets_with_storage<> W(2 * len);
893 // std::vector<vertex_idx_t> min(len);
894 // std::vector<edge_t*> enter(len);
895 // std::vector<edge_t*> F;
896 // std::vector<weight_t> edge_weight_change(len);
897 //
898 // for (vertex_idx_t v = 0; v < len; ++v)
899 // {
900 // S.make_set(v);
901 // W.make_set(v);
902 // min[v] = v;
903 // if (v != 0)
904 // roots.push_back(v);
905 // }
906 //
907 // while (!roots.empty())
908 // {
909 // vertex_idx_t curr = roots.back();
910 // roots.pop_back();
911 //
912 // if (in_edges[curr].empty())
913 // {
914 // final_roots.push_back(min[curr]);
915 // continue;
916 // }
917 //
918 // edge_t *optimal_in_edge = in_edges[curr].front();
919 // for (edge_t* e : in_edges[curr])
920 // if (e->weight > optimal_in_edge->weight)
921 // optimal_in_edge = e;
922 //
923 // F.push_back(optimal_in_edge);
924 // for (edge_t* e : cycle[curr])
925 // {
926 // e->parent = optimal_in_edge;
927 // optimal_in_edge->children.push_back(e);
928 // }
929 //
930 // if (cycle[curr].empty())
931 // lambda[curr] = optimal_in_edge;
932 //
933 // // adding optimal_in_edge don't create a cycle
934 // if (W.find_set(optimal_in_edge->source) != W.find_set(optimal_in_edge->target))
935 // {
936 // enter[curr] = optimal_in_edge;
937 // W.union_set(optimal_in_edge->source, optimal_in_edge->target);
938 // }
939 // else // adding optimal_in_edge creates a cycle
940 // {
941 // std::vector<edge_t*> cycle_edges = { optimal_in_edge };
942 // std::vector<vertex_idx_t> cycle_repr = { S.find_set(optimal_in_edge->target) };
943 // edge_t* least_costly_edge = optimal_in_edge;
944 // enter[curr] = nullptr;
945 //
946 // for (vertex_idx_t v = S.find_set(optimal_in_edge->source);
947 // enter[v] != nullptr;
948 // v = S.find_set(enter[v]->source))
949 // {
950 // cycle_edges.push_back(enter[v]);
951 // cycle_repr.push_back(v);
952 //
953 // if (enter[v]->weight < least_costly_edge->weight)
954 // least_costly_edge = enter[v];
955 // }
956 //
957 // for (edge_t* e : cycle_edges)
958 // edge_weight_change[S.find_set(e->target)] = least_costly_edge->weight - e->weight;
959 //
960 // vertex_idx_t cycle_root = min[S.find_set(least_costly_edge->target)];
961 //
962 // // Union all components of the cycle into one component
963 // vertex_idx_t new_repr = cycle_repr.front();
964 // for (vertex_idx_t v : cycle_repr)
965 // {
966 // S.link(v, new_repr);
967 // new_repr = S.find_set(new_repr);
968 // }
969 // min[new_repr] = cycle_root;
970 // roots.push_back(new_repr);
971 // cycle[new_repr].swap(cycle_edges);
972 //
973 // for (vertex_idx_t v : cycle_repr)
974 // {
975 // for (edge_t* e : in_edges[v])
976 // {
977 // e->weight += edge_weight_change[v];
978 // }
979 // }
980 //
981 // std::vector<edge_t*> new_in_edges;
982 // for (size_t i = 1; i < cycle_repr.size(); ++i)
983 // {
984 // typename std::vector<edge_t*>::iterator i1 = in_edges[cycle_repr[i]].begin();
985 // typename std::vector<edge_t*>::iterator e1 = in_edges[cycle_repr[i]].end();
986 // typename std::vector<edge_t*>::iterator i2 = in_edges[cycle_repr[i-1]].begin();
987 // typename std::vector<edge_t*>::iterator e2 = in_edges[cycle_repr[i-1]].end();
988 //
989 // while (i1 != e1 || i2 != e2)
990 // {
991 // while (i1 != e1 && S.find_set((*i1)->source) == new_repr)
992 // ++i1;
993 //
994 // while (i2 != e2 && S.find_set((*i2)->source) == new_repr)
995 // ++i2;
996 //
997 // if (i1 == e1 && i2 == e2)
998 // break;
999 //
1000 // if (i1 == e1)
1001 // {
1002 // new_in_edges.push_back(*i2);
1003 // ++i2;
1004 // }
1005 // else if (i2 == e2)
1006 // {
1007 // new_in_edges.push_back(*i1);
1008 // ++i1;
1009 // }
1010 // else if ( (*i1)->source < (*i2)->source )
1011 // {
1012 // new_in_edges.push_back(*i1);
1013 // ++i1;
1014 // }
1015 // else if ( (*i1)->source > (*i2)->source )
1016 // {
1017 // new_in_edges.push_back(*i2);
1018 // ++i2;
1019 // }
1020 // else
1021 // {
1022 // if ( (*i1)->weight > (*i2)->weight )
1023 // new_in_edges.push_back(*i1);
1024 // else
1025 // new_in_edges.push_back(*i2);
1026 //
1027 // ++i1;
1028 // ++i2;
1029 // }
1030 // }
1031 //
1032 // in_edges[cycle_repr[i]].swap(new_in_edges);
1033 // new_in_edges.clear();
1034 // }
1035 //
1036 // in_edges[new_repr].swap(in_edges[cycle_repr.back()]);
1037 // edge_weight_change[new_repr] = weight_t(0);
1038 // }
1039 // }
1040 //
1041 // std::vector<edge_t*> F_roots;
1042 // for (edge_t* e : F)
1043 // {
1044 // if (e->parent == nullptr)
1045 // F_roots.push_back(e);
1046 // }
1047 //
1048 // for (vertex_idx_t v : final_roots)
1049 // {
1050 // if (lambda[v] != nullptr)
1051 // remove_from_f(lambda[v], F_roots);
1052 // }
1053 //
1054 // while (!F_roots.empty())
1055 // {
1056 // edge_t* e = F_roots.back();
1057 // F_roots.pop_back();
1058 //
1059 // if (e->removed)
1060 // continue;
1061 //
1062 // heads[offset + e->target] = e->source;
1063 // remove_from_f(lambda[e->target], F_roots);
1064 // }
1065 //
1066 // return;
1067 // }
1068};
1069
1070} // namespace impl
1071
1072template <class M,
1073 typename vertex_idx_t,
1074 typename weight_t>
1075void arborescence(const M& adj_matrix,
1076 std::vector<vertex_idx_t>& heads,
1077 size_t offset)
1078{
1080 //Tree::fill_heads_with_max(adj_matrix, len, heads.begin);
1081 assert(adj_matrix.rows() == adj_matrix.cols());
1082 size_t len = adj_matrix.rows();
1083 // std::cerr << "arborescence heads=" << heads << ", offset=" << offset << ", len=" << len << std::endl;
1084
1085 const typename std::vector<vertex_idx_t>::const_iterator begin = heads.cbegin() + offset;
1086 const typename std::vector<vertex_idx_t>::const_iterator end = begin + len;
1087
1088 size_t n_roots = Tree::count_roots(begin, end);
1089
1090 if (n_roots == 0)
1091 Tree::choose_root(adj_matrix, heads, offset);
1092
1093 if (n_roots > 1)
1094 Tree::choose_one_root(adj_matrix, heads, offset);
1095
1096 n_roots = Tree::count_roots(begin, end);
1097
1098 if (n_roots != 1)
1099 throw std::runtime_error("choose_one_root should have selected one root.");
1100 // there is a bug in choose_one_root
1101
1102 // now n_roots == 1
1103 // if (Tree::is_connected(begin, end))
1104 // // TODO detect and clear cycles
1105 // return;
1106
1107 Tree::make_connected(adj_matrix, heads, offset);
1108
1109 n_roots = Tree::count_roots(begin, end);
1110
1111 if (n_roots == 1)
1112 if (Tree::is_connected(begin, end))
1113 return;
1114
1115 // we still have problems. Retrying with full tree reconstruction.
1116 std::fill(heads.begin() + offset, heads.begin() + offset + len, 0);
1117
1118 Tree::arborescence_impl(adj_matrix, heads, offset);
1119
1120 // final check for the number of roots
1121 n_roots = Tree::count_roots(begin, end);
1122
1123 if (n_roots != 1)
1124 throw std::runtime_error("choose_one_root should have selected one root.");
1125
1126}
1127
1128template <typename vertex_idx_t,
1129 typename weight_t>
1130void arborescence(std::vector<uint32_t>& heads, size_t len)
1131{
1132 // typedef impl::ArborescenceHeads<vertex_idx_t, weight_t> Tree;
1133 // std::cerr << "arborescence len=" << len << ", heads=" << heads << std::endl;
1134
1135 // hyp: there can be several root (head == 0), then select the first one and point the others to it
1136 auto h = std::numeric_limits<vertex_idx_t>::max();
1137 for (size_t i = 1; i < len; i++)
1138 {
1139 if (heads[i] == 0)
1140 {
1141 h = i;
1142 // std::cerr << "arborescence setting head to " << h << std::endl;
1143 break;
1144 }
1145 }
1146 // if there is no root, select the first node
1147 if (h == std::numeric_limits<vertex_idx_t>::max())
1148 {
1149 h = 1;
1150 heads[h] = 0;
1151 // std::cerr << "arborescence no head. selecting first node" << h << "->" << heads[h] << std::endl;
1152 }
1153 for (size_t i = h+1; i < len; i++)
1154 {
1155 if (heads[i] == 0)
1156 {
1157 heads[i] = h;
1158 // std::cerr << "arborescence duplicate head on "<<i<<". pointing it to the first one: " << i << "->" << heads[i] << std::endl;
1159 }
1160 else if (heads[i] >= len)
1161 {
1162 // std::cerr << "arborescence head on " << i << " (" << heads[i] << ") is out of sentence of size " << len
1163 // << ". pointing it to the first one: " << i << "->" << h << std::endl;
1164 heads[i] = h;
1165 }
1166 }
1167 // std::cerr << "AFTER scence len=" << len << ", heads=" << heads << std::endl;
1168}
1169
1170} // namespace deeplima
1171
1172#endif
static size_t count_roots(typename std::vector< vertex_idx_t >::const_iterator pos, typename std::vector< vertex_idx_t >::const_iterator end)
A node is a root if its head id is 0.
static void find_disconnected_groups(const std::vector< std::vector< size_t > > &head2child, size_t len, std::vector< size_t > &accessibility_map)
static bool is_connected(typename std::vector< vertex_idx_t >::const_iterator pos, typename std::vector< vertex_idx_t >::const_iterator end)
static void choose_root(std::vector< vertex_idx_t > &heads, size_t offset)
static void find_loops(const std::vector< vertex_idx_t > &heads, std::vector< std::vector< size_t > > &loops, const std::vector< size_t > &connected, size_t len, size_t offset)
static void choose_one_root(std::vector< vertex_idx_t > &heads, size_t offset)
static void find_loops(const std::vector< vertex_idx_t > &heads, std::vector< std::vector< size_t > > &loops, const std::vector< size_t > &connected, size_t len, size_t offset)
static void fill_heads_with_max(const std::function< float(size_t, size_t)> &adj_matrix, size_t len, std::vector< size_t > &heads)
static void arborescence_impl(const M &adj_matrix, std::vector< vertex_idx_t > &heads, size_t offset)
static void make_connected(const M &adj_matrix, std::vector< vertex_idx_t > &heads, size_t offset)
static void choose_one_root(const M &adj_matrix, std::vector< vertex_idx_t > &heads, size_t offset)
static size_t count_roots(typename std::vector< vertex_idx_t >::const_iterator pos, typename std::vector< vertex_idx_t >::const_iterator end)
A node is a root if its head id is 0.
static bool is_connected(typename std::vector< vertex_idx_t >::const_iterator pos, typename std::vector< vertex_idx_t >::const_iterator end)
static void choose_root(const M &adj_matrix, std::vector< vertex_idx_t > &heads, size_t offset)
static void find_disconnected_groups(const std::vector< std::vector< size_t > > &head2child, size_t len, std::vector< size_t > &accessibility_map)
void arborescence(const M &adj_matrix, std::vector< vertex_idx_t > &heads, size_t offset)