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 <utility>
109# include <tpl_graph.H>
110# include <tpl_graph_utils.H>
111# include <tpl_array.H>
112# include <htlist.H>
113# include <tpl_dynListStack.H>
114# include <ah-errors.H>
115# include <tpl_dynSetTree.H>
116
117namespace Aleph
118{
146 template <class GT, class SA = Dft_Show_Arc<GT>>
148 {
150
151 using Node = typename GT::Node;
152 using Arc = typename GT::Arc;
153
154 GT *gptr = nullptr;
155 Node *root_ptr = nullptr;
156 bool is_computed = false;
158
159 // Internal arrays indexed by DFS number
160 Array<Node *> vertex; // DFS number -> node pointer
161 Array<long> par; // DFS parent (as DFS number)
162 Array<long> semi; // semi-dominator (as DFS number)
163 Array<long> idom_arr; // immediate dominator (as DFS number)
164 Array<long> anc; // Union-Find ancestor
165 Array<long> label_arr; // Union-Find label (best semi on path)
166 Array<DynList<long>> pred; // predecessors[i] = DFS numbers of predecessors of node i
167
176 void compress(long v)
177 {
178 if (anc[v] == -1 or anc[anc[v]] == -1)
179 return;
180
181 // First pass: find the path to the root
182 Array<long> path;
183 long root = v;
184 while (anc[root] != -1 and anc[anc[root]] != -1)
185 {
186 path.append(root);
187 root = anc[root];
188 }
189
190 // Second pass: compress path and update labels
191 // Iterate from root-child down to v
192 while (not path.is_empty())
193 {
194 const long u = path.remove_last();
195 if (semi[label_arr[anc[u]]] < semi[label_arr[u]])
196 label_arr[u] = label_arr[anc[u]];
197 anc[u] = anc[anc[u]];
198 }
199 }
200
206 {
207 struct Frame
208 {
209 Node *u;
211 };
212
214
215 // Initialize root
216 const long root_num = num_reachable++;
219 par[root_num] = -1;
222 anc[root_num] = -1;
223
225
226 while (not stack.is_empty())
227 {
228 if (Frame & top = stack.top(); top.it.has_curr())
229 {
230 Node *v = gptr->get_tgt_node(top.it.get_curr());
231 top.it.next_ne();
232
233 if (NODE_COUNTER(v) == -1)
234 {
235 const long v_num = num_reachable++;
236 NODE_COUNTER(v) = v_num;
237 vertex[v_num] = v;
238 par[v_num] = NODE_COUNTER(top.u);
239 semi[v_num] = v_num;
241 anc[v_num] = -1;
242
243 stack.push(Frame{v, Out_Iterator<GT, SA>(v, sa)});
244 }
245 }
246 else
247 static_cast<void>(stack.pop());
248 }
249 }
250
259 [[nodiscard]] long eval(const long v)
260 {
261 if (anc[v] == -1)
262 return v;
263 compress(v);
264 return label_arr[v];
265 }
266
276 void do_compute(GT & g, Node *root)
277 {
278 gptr = &g;
279 root_ptr = root;
280 is_computed = false;
281 num_reachable = 0;
282
283 const size_t N = g.get_num_nodes();
284 if (N == 0)
285 {
286 is_computed = true;
287 return;
288 }
289
290 // Allocate internal arrays
291 vertex = Array<Node *>(N, nullptr);
292 par = Array<long>(N, -1L);
293 semi = Array<long>(N, -1L);
294 idom_arr = Array<long>(N, -1L);
295 anc = Array<long>(N, -1L);
296 label_arr = Array<long>(N, -1L);
298
299 // Mark all nodes as unvisited
300 gptr->for_each_node([](Node *p) { NODE_COUNTER(p) = -1; });
301
302 // Phase 1: DFS from root
303 dfs(root); // dfs updates num_reachable
304
305 if (num_reachable <= 1)
306 {
307 if (num_reachable == 1)
308 idom_arr[0] = -1; // root has no dominator
309 is_computed = true;
310 return;
311 }
312
313 // Build predecessor lists by iterating over all arcs.
314 // In_Iterator does not work on List_Digraph because arcs are
315 // only stored in the source node's adjacency list.
316 pred = Array<DynList<long>>(static_cast<size_t>(num_reachable), DynList<long>());
317 for (typename GT::Arc_Iterator ait(g); ait.has_curr(); ait.next_ne())
318 {
319 auto arc = ait.get_curr();
320 if (not sa(arc))
321 continue;
322 long s = NODE_COUNTER(gptr->get_src_node(arc));
323 long t = NODE_COUNTER(gptr->get_tgt_node(arc));
325 pred[t].append(s);
326 }
327
328 // Allocate buckets (one per reachable node)
329 Array<DynList<long>> bucket(static_cast<size_t>(num_reachable), DynList<long>());
330
331 // Phase 2: Semi-dominators (process in reverse DFS order)
332 for (long w = num_reachable - 1; w >= 1; --w)
333 {
334 // For each predecessor of w
335 for (auto pit = pred[w].get_it(); pit.has_curr(); pit.next_ne())
336 {
337 const long v_num = pit.get_curr();
338 const long u = eval(v_num);
339 if (semi[u] < semi[w])
340 semi[w] = semi[u];
341 }
342
343 bucket[semi[w]].append(w);
344 anc[w] = par[w]; // LINK(parent[w], w)
345
346 // Process bucket of parent[w]
347 while (not bucket[par[w]].is_empty())
348 {
349 const long v = bucket[par[w]].remove_first();
350 long u = eval(v);
351 idom_arr[v] = (semi[u] == semi[v]) ? par[w] : u;
352 }
353 }
354
355 // Phase 3: Resolve deferred idom assignments
356 for (long w = 1; w < num_reachable; ++w)
357 {
358 if (idom_arr[w] != semi[w])
360 }
361
362 idom_arr[0] = -1; // root has no dominator
363 is_computed = true;
364 }
365
375 {
376 ah_domain_error_if(root == nullptr)
377 << "Lengauer_Tarjan_Dominators: root cannot be null";
378
379 if (is_computed and gptr == &g and root_ptr == root)
380 return;
381
382 do_compute(g, root);
383 }
384
385 public:
391 : sa(std::move(__sa))
392 { /* empty */
393 }
394
397
399
402
404
417 {
419
421 for (long i = 0; i < num_reachable; ++i)
422 {
423 Node *idom_node = (idom_arr[i] >= 0) ? vertex[idom_arr[i]] : nullptr;
424 result.append(std::make_pair(vertex[i], idom_node));
425 }
426 return result;
427 }
428
441 void build_tree(GT & g, Node *root, GT & tree)
442 {
444
445 clear_graph(tree);
446
447 if (num_reachable == 0)
448 return;
449
450 // Create tree nodes and establish mapping
452 for (long i = 0; i < num_reachable; ++i)
453 {
454 auto tn = tree.insert_node(vertex[i]->get_info());
456 tree_nodes[i] = tn;
457 }
458
459 // Create arcs: idom(v) -> v
460 for (long i = 1; i < num_reachable; ++i)
461 if (idom_arr[i] >= 0)
463 }
464
474 [[nodiscard]] Node * get_idom(GT & g, Node *root, Node *node)
475 {
476 ah_domain_error_if(node == nullptr)
477 << "Lengauer_Tarjan_Dominators::get_idom: node cannot be null";
479
480 long v = NODE_COUNTER(node);
481 if (v < 0 or v >= num_reachable or vertex[v] != node)
482 return nullptr; // unreachable node
483
484 return (idom_arr[v] >= 0) ? vertex[idom_arr[v]] : nullptr;
485 }
486
498 [[nodiscard]] bool dominates(GT & g, Node *root, Node *d, Node *v)
499 {
501
502 if (d == v)
503 return true; // reflexive
504
505 long d_num = NODE_COUNTER(d);
506 long v_num = NODE_COUNTER(v);
507
509 return false;
511 return false;
512
513 // Walk up the idom chain from v
514 long curr = idom_arr[v_num];
515 while (curr != -1)
516 {
517 if (curr == d_num)
518 return true;
519 curr = idom_arr[curr];
520 }
521 return false;
522 }
523
542 {
544
546
547 // Initialize empty frontiers for all reachable nodes
548 for (long i = 0; i < num_reachable; ++i)
550
551 if (num_reachable <= 1)
552 return df;
553
554 // For each node with 2+ predecessors, walk up from each pred
555 for (long b = 0; b < num_reachable; ++b)
556 {
557 if (pred[b].size() < 2)
558 continue;
559
560 Node *bnode = vertex[b];
561
562 // Walk up from each predecessor to idom(b)
563 for (auto it = pred[b].get_it(); it.has_curr(); it.next_ne())
564 {
565 long runner = it.get_curr();
566 while (runner != idom_arr[b] and runner != -1)
567 {
568 df.find(vertex[runner]).insert(bnode);
569 runner = idom_arr[runner];
570 }
571 }
572 }
573
574 return df;
575 }
576
583 void operator()(GT & g, Node *root, GT & tree)
584 {
585 build_tree(g, root, tree);
586 }
587
590
592 [[nodiscard]] SA &get_filter() noexcept { return sa; }
593
595 [[nodiscard]] const SA &get_filter() const noexcept { return sa; }
596
599
602
605
608 {
609 return num_reachable;
610 }
611
613 };
614
615
616 // =========================================================================
617 // Free functions
618 // =========================================================================
619
634 template <class GT, class SA = Dft_Show_Arc<GT>>
636 compute_dominators(GT & g, typename GT::Node *root, SA sa = SA())
637 {
638 return Lengauer_Tarjan_Dominators<GT, SA>(sa).compute_idom(g, root);
639 }
640
656 template <class GT, class SA = Dft_Show_Arc<GT>>
658 GT & tree, SA sa = SA())
659 {
660 Lengauer_Tarjan_Dominators<GT, SA>(sa).build_tree(g, root, tree);
661 }
662
677 template <class GT, class SA = Dft_Show_Arc<GT>>
680 SA sa = SA())
681 {
682 return Lengauer_Tarjan_Dominators<GT, SA>(sa).dominance_frontiers(g, root);
683 }
684
685 // =========================================================================
686 // Post-dominator computation (Lengauer-Tarjan on the reversed graph)
687 // =========================================================================
688
727 template <class GT, class SA = Dft_Show_Arc<GT>>
729 {
731
732 using Node = typename GT::Node;
733 using Arc = typename GT::Arc;
734
737
738 GT *gptr = nullptr;
739 Node *exit_ptr = nullptr;
740 bool is_computed = false;
741
742 // Saved node mappings (orig ↔ rev) to avoid NODE_COOKIE conflicts
745
748 {
749 auto *p = orig_to_rev.search(orig);
750 return p ? p->second : nullptr;
751 }
752
755 {
756 auto *p = rev_to_orig.search(rev_n);
757 return p ? p->second : nullptr;
758 }
759
775 {
776 ah_domain_error_if(exit_node == nullptr)
777 << "Lengauer_Tarjan_Post_Dominators: exit node cannot be null";
778
779 gptr = &const_cast<GT &>(g);
781 is_computed = false;
782
783 // Step 1: Invert the digraph (sets NODE_COOKIE for mapping)
784 rev = invert_digraph(g);
785
786 // Step 2: Save orig↔rev mappings before dom overwrites anything
789 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
790 {
791 auto orig = it.get_curr();
792 auto rev_n = mapped_node<GT>(orig);
795 }
796
797 // Step 3: Run forward dominators on reversed graph from exit
798 // (discard return value; we only need the cached state)
799 auto rev_exit = to_rev(exit_node);
800 (void) dom.compute_idom(rev, rev_exit);
801
802 is_computed = true;
803 }
804
805 public:
811 : sa(std::move(__sa)), dom(sa)
812 { /* empty */
813 }
814
817
820
823
826
839 {
841
842 auto rev_exit = to_rev(exit_node);
843 auto rev_idoms = dom.compute_idom(rev, rev_exit);
844
846 for (auto it = rev_idoms.get_it(); it.has_curr(); it.next_ne())
847 {
848 auto [rev_n, rev_id] = it.get_curr();
849 auto orig_n = to_orig(rev_n);
850 auto orig_id = rev_id ? to_orig(rev_id) : nullptr;
851 result.append(std::make_pair(orig_n, orig_id));
852 }
853 return result;
854 }
855
868 void build_tree(const GT & g, Node *exit_node, GT & tree)
869 {
871
872 clear_graph(tree);
873
874 auto rev_exit = to_rev(exit_node);
875 auto rev_idoms = dom.compute_idom(rev, rev_exit);
876
877 if (rev_idoms.is_empty())
878 return;
879
880 // Create tree nodes with mapping to original graph.
881 // NODE_COOKIE(orig) may still point to a reversed-graph node
882 // left by invert_digraph; clear it so that map_nodes creates
883 // a clean orig↔tree bidirectional mapping.
885 for (auto it = rev_idoms.get_it(); it.has_curr(); it.next_ne())
886 {
887 auto [rev_n, rev_id] = it.get_curr();
888 auto orig = to_orig(rev_n);
889 auto tn = tree.insert_node(orig->get_info());
890 NODE_COOKIE(orig) = nullptr;
892 orig_to_tree.insert(orig, tn);
893 }
894
895 // Create arcs: ipdom(v) -> v
896 for (auto it = rev_idoms.get_it(); it.has_curr(); it.next_ne())
897 {
898 auto [rev_n, rev_id] = it.get_curr();
899 if (rev_id == nullptr)
900 continue; // exit node has no ipdom
901 auto orig = to_orig(rev_n);
902 auto orig_id = to_orig(rev_id);
904 orig_to_tree.find(orig));
905 }
906 }
907
917 [[nodiscard]] Node * get_ipdom(const GT & g, Node *exit_node, Node *node)
918 {
919 ah_domain_error_if(node == nullptr)
920 << "Lengauer_Tarjan_Post_Dominators::get_ipdom: node cannot be null";
922
923 auto rev_n = to_rev(node);
924 if (rev_n == nullptr)
925 return nullptr; // node not in graph
926
927 auto rev_exit = to_rev(exit_node);
928 auto rev_idom = dom.get_idom(rev, rev_exit, rev_n);
929 return rev_idom ? to_orig(rev_idom) : nullptr;
930 }
931
943 [[nodiscard]] bool
945 {
947
948 if (d == v)
949 return true; // reflexive
950
951 auto rev_d = to_rev(d);
952 auto rev_v = to_rev(v);
953 if (rev_d == nullptr or rev_v == nullptr)
954 return false;
955
956 auto rev_exit = to_rev(exit_node);
957 return dom.dominates(rev, rev_exit, rev_d, rev_v);
958 }
959
974 {
976
977 auto rev_exit = to_rev(exit_node);
978 auto rev_df = dom.dominance_frontiers(rev, rev_exit);
979
981 for (auto it = rev_df.get_it(); it.has_curr(); it.next_ne())
982 {
983 auto & [rev_n, rev_frontier] = it.get_curr();
984 auto orig = to_orig(rev_n);
986 for (typename DynSetTree<Node *>::Iterator fi(rev_frontier); fi.has_curr(); fi.next_ne())
987 orig_frontier.insert(to_orig(fi.get_curr()));
988 result.insert(orig, std::move(orig_frontier));
989 }
990 return result;
991 }
992
999 void operator()(const GT & g, Node *exit_node, GT & tree)
1000 {
1001 build_tree(g, exit_node, tree);
1002 }
1003
1006
1008 [[nodiscard]] SA &get_filter() noexcept { return sa; }
1009
1011 [[nodiscard]] const SA &get_filter() const noexcept { return sa; }
1012
1015
1018
1021
1023 };
1024
1025
1026 // =========================================================================
1027 // Post-dominator free functions
1028 // =========================================================================
1029
1044 template <class GT, class SA = Dft_Show_Arc<GT>>
1047 SA sa = SA())
1048 {
1050 .compute_ipdom(g, exit_node);
1051 }
1052
1068 template <class GT, class SA = Dft_Show_Arc<GT>>
1070 GT & tree, SA sa = SA())
1071 {
1073 .build_tree(g, exit_node, tree);
1074 }
1075
1090 template <class GT, class SA = Dft_Show_Arc<GT>>
1093 typename GT::Node *exit_node,
1094 SA sa = SA())
1095 {
1097 .post_dominance_frontiers(g, exit_node);
1098 }
1099} // end namespace Aleph
1100
1101# 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:522
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:139
constexpr bool is_empty() const noexcept
Checks if the container is empty.
Definition tpl_array.H:348
T & insert(const T &data)
insert a copy of data at the beginning of the array.
Definition tpl_array.H:281
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:245
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.
Dynamic singly linked list with functional programming support.
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:148
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:541
void build_tree(GT &g, Node *root, GT &tree)
Build the dominator tree as a separate graph.
Definition Dominators.H:441
bool has_computation() const noexcept
Check if a computation has been performed.
Definition Dominators.H:598
void ensure_computed(GT &g, Node *root)
Ensure computation is up to date.
Definition Dominators.H:374
SA & get_filter() noexcept
Get the arc filter.
Definition Dominators.H:592
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:205
void operator()(GT &g, Node *root, GT &tree)
Build dominator tree (operator() alias).
Definition Dominators.H:583
long get_num_reachable() const noexcept
Get the number of reachable nodes in the last computation.
Definition Dominators.H:607
long eval(const long v)
EVAL operation for the Union-Find forest.
Definition Dominators.H:259
bool dominates(GT &g, Node *root, Node *d, Node *v)
Test whether node d dominates node v.
Definition Dominators.H:498
Lengauer_Tarjan_Dominators(SA __sa=SA()) noexcept
Construct a dominator computation instance.
Definition Dominators.H:390
Array< DynList< long > > pred
Definition Dominators.H:166
Node * get_idom(GT &g, Node *root, Node *node)
Get the immediate dominator of a specific node.
Definition Dominators.H:474
void do_compute(GT &g, Node *root)
Core computation of dominators.
Definition Dominators.H:276
DynList< std::pair< Node *, Node * > > compute_idom(GT &g, Node *root)
Compute immediate dominators.
Definition Dominators.H:416
Node * get_root() const noexcept
Get the root of the last computation.
Definition Dominators.H:604
const SA & get_filter() const noexcept
Get the arc filter (const).
Definition Dominators.H:595
GT * get_graph() const noexcept
Get the graph of the last computation.
Definition Dominators.H:601
void compress(long v)
Path compression for Union-Find (iterative).
Definition Dominators.H:176
Computes post-dominator tree and post-dominance frontiers of a digraph using the Lengauer-Tarjan algo...
Definition Dominators.H:729
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:973
void build_tree(const GT &g, Node *exit_node, GT &tree)
Build the post-dominator tree as a separate graph.
Definition Dominators.H:868
void ensure_computed(const GT &g, Node *exit_node)
Ensure computation is up to date.
Definition Dominators.H:774
Node * exit_ptr
Definition Dominators.H:739
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).
Definition Dominators.H:999
GT rev
Definition Dominators.H:735
Lengauer_Tarjan_Dominators< GT, SA > dom
Definition Dominators.H:736
bool is_computed
Definition Dominators.H:740
typename GT::Node Node
Definition Dominators.H:732
SA sa
Definition Dominators.H:730
typename GT::Arc Arc
Definition Dominators.H:733
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:838
Lengauer_Tarjan_Post_Dominators(SA __sa=SA()) noexcept
Construct a post-dominator computation instance.
Definition Dominators.H:810
Lengauer_Tarjan_Post_Dominators(Lengauer_Tarjan_Post_Dominators &&)=default
Move is allowed.
GT * gptr
Definition Dominators.H:738
DynMapTree< Node *, Node * > rev_to_orig
Definition Dominators.H:744
Node * to_rev(Node *orig) const
Map original node to reversed graph node.
Definition Dominators.H:747
bool post_dominates(const GT &g, Node *exit_node, Node *d, Node *v)
Test whether node d post-dominates node v.
Definition Dominators.H:944
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:917
Node * to_orig(Node *rev_n) const
Map reversed graph node to original node.
Definition Dominators.H:754
DynMapTree< Node *, Node * > orig_to_rev
Definition Dominators.H:743
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:524
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:604
Filtered iterator for outcoming arcs of a node.
Definition tpl_graph.H:1750
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:737
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:695
auto get_node_it() const noexcept
Obtains an iterator to the nodes of graph.
Definition graph-dry.H:2786
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:743
static void map_nodes(N1 *p, N2 *q) noexcept
Map the nodes through their cookies.
Definition graph-dry.H:1001
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:1482
#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:4060
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:657
#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:3556
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:636
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:679
Singly linked list implementations with head-tail access.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
size_t size(Node *root) noexcept
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
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.