Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
Dominators.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
105# ifndef DOMINATORS_H
106# define DOMINATORS_H
107
108# include <ah-graph-concepts.H>
109
110# include <utility>
111# include <tpl_graph.H>
112# include <tpl_graph_utils.H>
113# include <tpl_array.H>
114# include <htlist.H>
115# include <tpl_dynListStack.H>
116# include <ah-errors.H>
117# include <tpl_dynSetTree.H>
118
119namespace Aleph
120{
148 template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
150 {
151 SA sa;
152
153 using Node = typename GT::Node;
154 using Arc = typename GT::Arc;
155
156 GT *gptr = nullptr;
157 Node *root_ptr = nullptr;
158 bool is_computed = false;
160
161 // Internal arrays indexed by DFS number
162 Array<Node *> vertex; // DFS number -> node pointer
163 Array<long> par; // DFS parent (as DFS number)
164 Array<long> semi; // semi-dominator (as DFS number)
165 Array<long> idom_arr; // immediate dominator (as DFS number)
166 Array<long> anc; // Union-Find ancestor
167 Array<long> label_arr; // Union-Find label (best semi on path)
168 Array<DynList<long>> pred; // predecessors[i] = DFS numbers of predecessors of node i
169
178 void compress(long v)
179 {
180 if (anc[v] == -1 or anc[anc[v]] == -1)
181 return;
182
183 // First pass: find the path to the root
184 Array<long> path;
185 long root = v;
186 while (anc[root] != -1 and anc[anc[root]] != -1)
187 {
188 path.append(root);
189 root = anc[root];
190 }
191
192 // Second pass: compress path and update labels
193 // Iterate from root-child down to v
194 while (not path.is_empty())
195 {
196 const long u = path.remove_last();
197 if (semi[label_arr[anc[u]]] < semi[label_arr[u]])
198 label_arr[u] = label_arr[anc[u]];
199 anc[u] = anc[anc[u]];
200 }
201 }
202
208 {
209 struct Frame
210 {
211 Node *u;
213 };
214
216
217 // Initialize root
218 const long root_num = num_reachable++;
221 par[root_num] = -1;
224 anc[root_num] = -1;
225
227
228 while (not stack.is_empty())
229 {
230 if (Frame & top = stack.top(); top.it.has_curr())
231 {
232 Node *v = gptr->get_tgt_node(top.it.get_curr());
233 top.it.next_ne();
234
235 if (NODE_COUNTER(v) == -1)
236 {
237 const long v_num = num_reachable++;
238 NODE_COUNTER(v) = v_num;
239 vertex[v_num] = v;
240 par[v_num] = NODE_COUNTER(top.u);
241 semi[v_num] = v_num;
243 anc[v_num] = -1;
244
245 stack.push(Frame{v, Out_Iterator<GT, SA>(v, sa)});
246 }
247 }
248 else
249 static_cast<void>(stack.pop());
250 }
251 }
252
261 [[nodiscard]] long eval(const long v)
262 {
263 if (anc[v] == -1)
264 return v;
265 compress(v);
266 return label_arr[v];
267 }
268
278 void do_compute(GT & g, Node *root)
279 {
280 gptr = &g;
281 root_ptr = root;
282 is_computed = false;
283 num_reachable = 0;
284
285 const size_t N = g.get_num_nodes();
286 if (N == 0)
287 {
288 is_computed = true;
289 return;
290 }
291
292 // Allocate internal arrays
293 vertex = Array<Node *>(N, nullptr);
294 par = Array<long>(N, -1L);
295 semi = Array<long>(N, -1L);
296 idom_arr = Array<long>(N, -1L);
297 anc = Array<long>(N, -1L);
298 label_arr = Array<long>(N, -1L);
300
301 // Mark all nodes as unvisited
302 gptr->for_each_node([](Node *p) { NODE_COUNTER(p) = -1; });
303
304 // Phase 1: DFS from root
305 dfs(root); // dfs updates num_reachable
306
307 if (num_reachable <= 1)
308 {
309 if (num_reachable == 1)
310 idom_arr[0] = -1; // root has no dominator
311 is_computed = true;
312 return;
313 }
314
315 // Build predecessor lists by iterating over all arcs.
316 // In_Iterator does not work on List_Digraph because arcs are
317 // only stored in the source node's adjacency list.
318 pred = Array<DynList<long>>(static_cast<size_t>(num_reachable), DynList<long>());
319 for (typename GT::Arc_Iterator ait(g); ait.has_curr(); ait.next_ne())
320 {
321 auto arc = ait.get_curr();
322 if (not sa(arc))
323 continue;
324 long s = NODE_COUNTER(gptr->get_src_node(arc));
325 long t = NODE_COUNTER(gptr->get_tgt_node(arc));
327 pred[t].append(s);
328 }
329
330 // Allocate buckets (one per reachable node)
331 Array<DynList<long>> bucket(static_cast<size_t>(num_reachable), DynList<long>());
332
333 // Phase 2: Semi-dominators (process in reverse DFS order)
334 for (long w = num_reachable - 1; w >= 1; --w)
335 {
336 // For each predecessor of w
337 for (auto pit = pred[w].get_it(); pit.has_curr(); pit.next_ne())
338 {
339 const long v_num = pit.get_curr();
340 const long u = eval(v_num);
341 if (semi[u] < semi[w])
342 semi[w] = semi[u];
343 }
344
345 bucket[semi[w]].append(w);
346 anc[w] = par[w]; // LINK(parent[w], w)
347
348 // Process bucket of parent[w]
349 while (not bucket[par[w]].is_empty())
350 {
351 const long v = bucket[par[w]].remove_first();
352 long u = eval(v);
353 idom_arr[v] = (semi[u] == semi[v]) ? par[w] : u;
354 }
355 }
356
357 // Phase 3: Resolve deferred idom assignments
358 for (long w = 1; w < num_reachable; ++w)
359 {
360 if (idom_arr[w] != semi[w])
362 }
363
364 idom_arr[0] = -1; // root has no dominator
365 is_computed = true;
366 }
367
377 {
378 ah_domain_error_if(root == nullptr)
379 << "Lengauer_Tarjan_Dominators: root cannot be null";
380
381 if (is_computed and gptr == &g and root_ptr == root)
382 return;
383
384 do_compute(g, root);
385 }
386
387 public:
393 : sa(std::move(__sa))
394 { /* empty */
395 }
396
399
401
404
406
419 {
421
423 for (long i = 0; i < num_reachable; ++i)
424 {
425 Node *idom_node = (idom_arr[i] >= 0) ? vertex[idom_arr[i]] : nullptr;
426 result.append(std::make_pair(vertex[i], idom_node));
427 }
428 return result;
429 }
430
443 void build_tree(GT & g, Node *root, GT & tree)
444 {
446
447 clear_graph(tree);
448
449 if (num_reachable == 0)
450 return;
451
452 // Create tree nodes and establish mapping
454 for (long i = 0; i < num_reachable; ++i)
455 {
456 auto tn = tree.insert_node(vertex[i]->get_info());
458 tree_nodes[i] = tn;
459 }
460
461 // Create arcs: idom(v) -> v
462 for (long i = 1; i < num_reachable; ++i)
463 if (idom_arr[i] >= 0)
465 }
466
476 [[nodiscard]] Node * get_idom(GT & g, Node *root, Node *node)
477 {
478 ah_domain_error_if(node == nullptr)
479 << "Lengauer_Tarjan_Dominators::get_idom: node cannot be null";
481
482 long v = NODE_COUNTER(node);
483 if (v < 0 or v >= num_reachable or vertex[v] != node)
484 return nullptr; // unreachable node
485
486 return (idom_arr[v] >= 0) ? vertex[idom_arr[v]] : nullptr;
487 }
488
500 [[nodiscard]] bool dominates(GT & g, Node *root, Node *d, Node *v)
501 {
503
504 if (d == v)
505 return true; // reflexive
506
507 long d_num = NODE_COUNTER(d);
508 long v_num = NODE_COUNTER(v);
509
511 return false;
513 return false;
514
515 // Walk up the idom chain from v
516 long curr = idom_arr[v_num];
517 while (curr != -1)
518 {
519 if (curr == d_num)
520 return true;
521 curr = idom_arr[curr];
522 }
523 return false;
524 }
525
544 {
546
548
549 // Initialize empty frontiers for all reachable nodes
550 for (long i = 0; i < num_reachable; ++i)
552
553 if (num_reachable <= 1)
554 return df;
555
556 // For each node with 2+ predecessors, walk up from each pred
557 for (long b = 0; b < num_reachable; ++b)
558 {
559 if (pred[b].size() < 2)
560 continue;
561
562 Node *bnode = vertex[b];
563
564 // Walk up from each predecessor to idom(b)
565 for (auto it = pred[b].get_it(); it.has_curr(); it.next_ne())
566 {
567 long runner = it.get_curr();
568 while (runner != idom_arr[b] and runner != -1)
569 {
570 df.find(vertex[runner]).insert(bnode);
571 runner = idom_arr[runner];
572 }
573 }
574 }
575
576 return df;
577 }
578
585 void operator()(GT & g, Node *root, GT & tree)
586 {
587 build_tree(g, root, tree);
588 }
589
592
594 [[nodiscard]] SA &get_filter() noexcept { return sa; }
595
597 [[nodiscard]] const SA &get_filter() const noexcept { return sa; }
598
601
604
607
610 {
611 return num_reachable;
612 }
613
615 };
616
617
618 // =========================================================================
619 // Free functions
620 // =========================================================================
621
636 template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
638 compute_dominators(GT & g, typename GT::Node *root, SA sa = SA())
639 {
640 return Lengauer_Tarjan_Dominators<GT, SA>(sa).compute_idom(g, root);
641 }
642
658 template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
660 GT & tree, SA sa = SA())
661 {
662 Lengauer_Tarjan_Dominators<GT, SA>(sa).build_tree(g, root, tree);
663 }
664
679 template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
682 SA sa = SA())
683 {
684 return Lengauer_Tarjan_Dominators<GT, SA>(sa).dominance_frontiers(g, root);
685 }
686
687 // =========================================================================
688 // Post-dominator computation (Lengauer-Tarjan on the reversed graph)
689 // =========================================================================
690
729 template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
731 {
732 SA sa;
733
734 using Node = typename GT::Node;
735 using Arc = typename GT::Arc;
736
739
740 GT *gptr = nullptr;
741 Node *exit_ptr = nullptr;
742 bool is_computed = false;
743
744 // Saved node mappings (orig ↔ rev) to avoid NODE_COOKIE conflicts
747
750 {
751 auto *p = orig_to_rev.search(orig);
752 return p ? p->second : nullptr;
753 }
754
757 {
758 auto *p = rev_to_orig.search(rev_n);
759 return p ? p->second : nullptr;
760 }
761
777 {
778 ah_domain_error_if(exit_node == nullptr)
779 << "Lengauer_Tarjan_Post_Dominators: exit node cannot be null";
780
781 gptr = &const_cast<GT &>(g);
783 is_computed = false;
784
785 // Step 1: Invert the digraph (sets NODE_COOKIE for mapping)
786 rev = invert_digraph(g);
787
788 // Step 2: Save orig↔rev mappings before dom overwrites anything
791 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
792 {
793 auto orig = it.get_curr();
794 auto rev_n = mapped_node<GT>(orig);
797 }
798
799 // Step 3: Run forward dominators on reversed graph from exit
800 // (discard return value; we only need the cached state)
801 auto rev_exit = to_rev(exit_node);
802 (void) dom.compute_idom(rev, rev_exit);
803
804 is_computed = true;
805 }
806
807 public:
813 : sa(std::move(__sa)), dom(sa)
814 { /* empty */
815 }
816
819
822
825
828
841 {
843
844 auto rev_exit = to_rev(exit_node);
845 auto rev_idoms = dom.compute_idom(rev, rev_exit);
846
848 for (auto it = rev_idoms.get_it(); it.has_curr(); it.next_ne())
849 {
850 auto [rev_n, rev_id] = it.get_curr();
851 auto orig_n = to_orig(rev_n);
852 auto orig_id = rev_id ? to_orig(rev_id) : nullptr;
853 result.append(std::make_pair(orig_n, orig_id));
854 }
855 return result;
856 }
857
870 void build_tree(const GT & g, Node *exit_node, GT & tree)
871 {
873
874 clear_graph(tree);
875
876 auto rev_exit = to_rev(exit_node);
877 auto rev_idoms = dom.compute_idom(rev, rev_exit);
878
879 if (rev_idoms.is_empty())
880 return;
881
882 // Create tree nodes with mapping to original graph.
883 // NODE_COOKIE(orig) may still point to a reversed-graph node
884 // left by invert_digraph; clear it so that map_nodes creates
885 // a clean orig↔tree bidirectional mapping.
887 for (auto it = rev_idoms.get_it(); it.has_curr(); it.next_ne())
888 {
889 auto [rev_n, rev_id] = it.get_curr();
890 auto orig = to_orig(rev_n);
891 auto tn = tree.insert_node(orig->get_info());
892 NODE_COOKIE(orig) = nullptr;
894 orig_to_tree.insert(orig, tn);
895 }
896
897 // Create arcs: ipdom(v) -> v
898 for (auto it = rev_idoms.get_it(); it.has_curr(); it.next_ne())
899 {
900 auto [rev_n, rev_id] = it.get_curr();
901 if (rev_id == nullptr)
902 continue; // exit node has no ipdom
903 auto orig = to_orig(rev_n);
904 auto orig_id = to_orig(rev_id);
906 orig_to_tree.find(orig));
907 }
908 }
909
919 [[nodiscard]] Node * get_ipdom(const GT & g, Node *exit_node, Node *node)
920 {
921 ah_domain_error_if(node == nullptr)
922 << "Lengauer_Tarjan_Post_Dominators::get_ipdom: node cannot be null";
924
925 auto rev_n = to_rev(node);
926 if (rev_n == nullptr)
927 return nullptr; // node not in graph
928
929 auto rev_exit = to_rev(exit_node);
930 auto rev_idom = dom.get_idom(rev, rev_exit, rev_n);
931 return rev_idom ? to_orig(rev_idom) : nullptr;
932 }
933
945 [[nodiscard]] bool
947 {
949
950 if (d == v)
951 return true; // reflexive
952
953 auto rev_d = to_rev(d);
954 auto rev_v = to_rev(v);
955 if (rev_d == nullptr or rev_v == nullptr)
956 return false;
957
958 auto rev_exit = to_rev(exit_node);
959 return dom.dominates(rev, rev_exit, rev_d, rev_v);
960 }
961
976 {
978
979 auto rev_exit = to_rev(exit_node);
980 auto rev_df = dom.dominance_frontiers(rev, rev_exit);
981
983 for (auto it = rev_df.get_it(); it.has_curr(); it.next_ne())
984 {
985 auto & [rev_n, rev_frontier] = it.get_curr();
986 auto orig = to_orig(rev_n);
988 for (typename DynSetTree<Node *>::Iterator fi(rev_frontier); fi.has_curr(); fi.next_ne())
989 orig_frontier.insert(to_orig(fi.get_curr()));
990 result.insert(orig, std::move(orig_frontier));
991 }
992 return result;
993 }
994
1001 void operator()(const GT & g, Node *exit_node, GT & tree)
1002 {
1003 build_tree(g, exit_node, tree);
1004 }
1005
1008
1010 [[nodiscard]] SA &get_filter() noexcept { return sa; }
1011
1013 [[nodiscard]] const SA &get_filter() const noexcept { return sa; }
1014
1017
1020
1023
1025 };
1026
1027
1028 // =========================================================================
1029 // Post-dominator free functions
1030 // =========================================================================
1031
1046 template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
1049 SA sa = SA())
1050 {
1052 .compute_ipdom(g, exit_node);
1053 }
1054
1070 template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
1072 GT & tree, SA sa = SA())
1073 {
1075 .build_tree(g, exit_node, tree);
1076 }
1077
1092 template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
1095 typename GT::Node *exit_node,
1096 SA sa = SA())
1097 {
1099 .post_dominance_frontiers(g, exit_node);
1100 }
1101} // end namespace Aleph
1102
1103# endif // DOMINATORS_H
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:527
C++20 concepts for the protocol shared by graph algorithms.
EepicNode< long > * build_tree()
Definition btreepic.C:1435
long double w
Definition btreepic.C:153
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
constexpr bool is_empty() const noexcept
Checks if the container is empty.
Definition tpl_array.H:359
T & insert(const T &data)
insert a copy of data at the beginning of the array.
Definition tpl_array.H:286
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:250
Dynamic stack of elements of generic type T based on a singly linked list.
T & top()
Return a modifiable reference to the top item of the stack.
bool is_empty() const noexcept
Check if the stack is empty.
T pop()
Remove and return the top item of the stack.
T & push(const T &data)
Push an item by copy onto the top of the stack.
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
Generic key-value map implemented on top of a binary search tree.
Pair * search(const Key &key) const noexcept
Collect all keys.
Pair * insert(const Key &key, const Data &data)
Insert a key-value pair.
Dynamic set backed by balanced binary search trees with automatic memory management.
Key * insert(const Key &key)
Inserts a key into the dynamic set.
Computes dominator tree and dominance frontiers of a digraph using the Lengauer-Tarjan algorithm.
Definition Dominators.H:150
Lengauer_Tarjan_Dominators(const Lengauer_Tarjan_Dominators &)=delete
Dominator instances should not be copied (they hold internal state)
Lengauer_Tarjan_Dominators(Lengauer_Tarjan_Dominators &&)=default
Move is allowed.
DynMapTree< Node *, DynSetTree< Node * > > dominance_frontiers(GT &g, Node *root)
Compute dominance frontiers for all reachable nodes.
Definition Dominators.H:543
void build_tree(GT &g, Node *root, GT &tree)
Build the dominator tree as a separate graph.
Definition Dominators.H:443
bool has_computation() const noexcept
Check if a computation has been performed.
Definition Dominators.H:600
void ensure_computed(GT &g, Node *root)
Ensure computation is up to date.
Definition Dominators.H:376
SA & get_filter() noexcept
Get the arc filter.
Definition Dominators.H:594
Lengauer_Tarjan_Dominators & operator=(Lengauer_Tarjan_Dominators &&)=default
Lengauer_Tarjan_Dominators & operator=(const Lengauer_Tarjan_Dominators &)=delete
void dfs(Node *root_ptr)
Iterative DFS to number nodes and build DFS tree.
Definition Dominators.H:207
void operator()(GT &g, Node *root, GT &tree)
Build dominator tree (operator() alias).
Definition Dominators.H:585
long get_num_reachable() const noexcept
Get the number of reachable nodes in the last computation.
Definition Dominators.H:609
long eval(const long v)
EVAL operation for the Union-Find forest.
Definition Dominators.H:261
bool dominates(GT &g, Node *root, Node *d, Node *v)
Test whether node d dominates node v.
Definition Dominators.H:500
Lengauer_Tarjan_Dominators(SA __sa=SA()) noexcept
Construct a dominator computation instance.
Definition Dominators.H:392
Array< DynList< long > > pred
Definition Dominators.H:168
Node * get_idom(GT &g, Node *root, Node *node)
Get the immediate dominator of a specific node.
Definition Dominators.H:476
void do_compute(GT &g, Node *root)
Core computation of dominators.
Definition Dominators.H:278
DynList< std::pair< Node *, Node * > > compute_idom(GT &g, Node *root)
Compute immediate dominators.
Definition Dominators.H:418
Node * get_root() const noexcept
Get the root of the last computation.
Definition Dominators.H:606
const SA & get_filter() const noexcept
Get the arc filter (const).
Definition Dominators.H:597
GT * get_graph() const noexcept
Get the graph of the last computation.
Definition Dominators.H:603
void compress(long v)
Path compression for Union-Find (iterative).
Definition Dominators.H:178
Computes post-dominator tree and post-dominance frontiers of a digraph using the Lengauer-Tarjan algo...
Definition Dominators.H:731
bool has_computation() const noexcept
Check if a computation has been performed.
Lengauer_Tarjan_Post_Dominators(const Lengauer_Tarjan_Post_Dominators &)=delete
Post-dominator instances should not be copied (they hold internal state)
SA & get_filter() noexcept
Get the arc filter.
DynMapTree< Node *, DynSetTree< Node * > > post_dominance_frontiers(const GT &g, Node *exit_node)
Compute post-dominance frontiers for all reachable nodes.
Definition Dominators.H:975
void build_tree(const GT &g, Node *exit_node, GT &tree)
Build the post-dominator tree as a separate graph.
Definition Dominators.H:870
void ensure_computed(const GT &g, Node *exit_node)
Ensure computation is up to date.
Definition Dominators.H:776
Node * exit_ptr
Definition Dominators.H:741
Lengauer_Tarjan_Post_Dominators & operator=(const Lengauer_Tarjan_Post_Dominators &)=delete
Lengauer_Tarjan_Post_Dominators & operator=(Lengauer_Tarjan_Post_Dominators &&)=default
const SA & get_filter() const noexcept
Get the arc filter (const).
void operator()(const GT &g, Node *exit_node, GT &tree)
Build post-dominator tree (operator() alias).
GT rev
Definition Dominators.H:737
Lengauer_Tarjan_Dominators< GT, SA > dom
Definition Dominators.H:738
bool is_computed
Definition Dominators.H:742
typename GT::Node Node
Definition Dominators.H:734
SA sa
Definition Dominators.H:732
typename GT::Arc Arc
Definition Dominators.H:735
GT * get_graph() const noexcept
Get the graph of the last computation.
DynList< std::pair< Node *, Node * > > compute_ipdom(const GT &g, Node *exit_node)
Compute immediate post-dominators.
Definition Dominators.H:840
Lengauer_Tarjan_Post_Dominators(SA __sa=SA()) noexcept
Construct a post-dominator computation instance.
Definition Dominators.H:812
Lengauer_Tarjan_Post_Dominators(Lengauer_Tarjan_Post_Dominators &&)=default
Move is allowed.
GT * gptr
Definition Dominators.H:740
DynMapTree< Node *, Node * > rev_to_orig
Definition Dominators.H:746
Node * to_rev(Node *orig) const
Map original node to reversed graph node.
Definition Dominators.H:749
bool post_dominates(const GT &g, Node *exit_node, Node *d, Node *v)
Test whether node d post-dominates node v.
Definition Dominators.H:946
Node * get_exit() const noexcept
Get the exit node of the last computation.
Node * get_ipdom(const GT &g, Node *exit_node, Node *node)
Get the immediate post-dominator of a specific node.
Definition Dominators.H:919
Node * to_orig(Node *rev_n) const
Map reversed graph node to original node.
Definition Dominators.H:756
DynMapTree< Node *, Node * > orig_to_rev
Definition Dominators.H:745
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:525
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:605
Filtered iterator for outcoming arcs of a node.
Definition tpl_graph.H:1831
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:779
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:737
void for_each_node(Operation &operation) const
Unconditionally traverse all the nodes of graph and on each one perform an operation.
Definition graph-dry.H:1531
auto get_node_it() const noexcept
Obtains an iterator to the nodes of graph.
Definition graph-dry.H:2886
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:785
static void map_nodes(N1 *p, N2 *q) noexcept
Map the nodes through their cookies.
Definition graph-dry.H:1043
#define N
Definition fib.C:294
__gmp_expr< T, __gmp_binary_expr< __gmp_expr< T, U >, unsigned long int, __gmp_root_function > > root(const __gmp_expr< T, U > &expr, unsigned long int l)
Definition gmpfrxx.h:4071
void build_post_dominator_tree(const GT &g, typename GT::Node *exit_node, GT &tree, SA sa=SA())
Build the post-dominator tree of a digraph.
#define NODE_COUNTER(p)
Get the counter of a node.
GT invert_digraph(const GT &g)
Compute the transpose (arc-reversed) digraph.
void build_dominator_tree(GT &g, typename GT::Node *root, GT &tree, SA sa=SA())
Build the dominator tree of a digraph.
Definition Dominators.H:659
#define NODE_COOKIE(p)
Return the node cookie
void clear_graph(GT &g) noexcept
Clean a graph: all its nodes and arcs are removed and freed.
Definition tpl_graph.H:3659
DynList< std::pair< typename GT::Node *, typename GT::Node * > > compute_dominators(GT &g, typename GT::Node *root, SA sa=SA())
Compute immediate dominators of a digraph from a root node.
Definition Dominators.H:638
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
DynList< std::pair< typename GT::Node *, typename GT::Node * > > compute_post_dominators(const GT &g, typename GT::Node *exit_node, SA sa=SA())
Compute immediate post-dominators of a digraph from an exit node.
DynMapTree< typename GT::Node *, DynSetTree< typename GT::Node * > > compute_post_dominance_frontiers(const GT &g, typename GT::Node *exit_node, SA sa=SA())
Compute post-dominance frontiers of a digraph.
DynMapTree< typename GT::Node *, DynSetTree< typename GT::Node * > > compute_dominance_frontiers(GT &g, typename GT::Node *root, SA sa=SA())
Compute dominance frontiers of a digraph.
Definition Dominators.H:681
Singly linked list implementations with head-tail access.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
size_t size(Node *root) noexcept
and
Check uniqueness with explicit hash + equality functors.
static long & df(typename GT::Node *p)
Internal helper: DFS discovery time stored in NODE_COUNTER(p).
STL namespace.
Dynamic array container with automatic resizing.
Dynamic stack implementation based on linked lists.
Dynamic set implementations based on balanced binary search trees.
Generic graph and digraph implementations.
Utility algorithms and operations for graphs.