Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
Tree_DP.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
48# ifndef TREE_DP_H
49# define TREE_DP_H
50
51# include <algorithm>
52# include <cstddef>
53# include <functional>
54# include <limits>
55# include <utility>
56
57# include <ah-errors.H>
58# include <tpl_array.H>
59# include <tpl_dynListStack.H>
60# include <tpl_dynMapOhash.H>
61# include <tpl_dynMapTree.H>
62# include <tpl_graph.H>
63
64namespace Aleph
65{
66 namespace tree_dp_detail
67 {
76 template <class GT, class SA>
78 {
79 public:
80 using Node = typename GT::Node;
81 using Arc = typename GT::Arc;
84 static constexpr size_t NONE = std::numeric_limits<size_t>::max();
85
86 private:
87 const GT *graph_ = nullptr;
89 Node *root_ = nullptr;
90 size_t n_ = 0;
100 {
102 if (n_ == 0)
103 {
104 ah_domain_error_if(root_ != nullptr)
105 << "Tree_Topology: non-null root provided for empty graph";
106 return;
107 }
108
111 node_to_id_.swap(tmp);
112 }
113
114 size_t next_id = 0;
115 for (Node_Iterator<GT> it(*graph_); it.has_curr(); it.next_ne())
116 {
117 Node *p = it.get_curr();
118 id_to_node_(next_id) = p;
120 ++next_id;
121 }
122
123 if (root_ == nullptr)
124 root_ = id_to_node_(0);
125 else
127 << "Tree_Topology: root node is not part of the graph";
128 }
129
132 {
133 if (n_ == 0)
134 return;
135
136 children_.reserve(n_);
137 for (size_t i = 0; i < n_; ++i)
138 children_.append(Array<size_t>());
139
140 using Pair_Key = std::pair<size_t, size_t>;
142 size_t edge_count = 0;
143
144 for (Arc_Iterator<GT, SA> it(*graph_, sa_); it.has_curr(); it.next_ne())
145 {
146 Arc *a = it.get_curr_ne();
147 Node *src = graph_->get_src_node(a);
148 Node *tgt = graph_->get_tgt_node(a);
149
150 const auto *si = node_to_id_.search(src);
151 const auto *ti = node_to_id_.search(tgt);
152 ah_runtime_error_unless(si != nullptr and ti != nullptr)
153 << "Tree_Topology: arc endpoint not indexed";
154
155 const size_t u = si->second;
156 const size_t v = ti->second;
157 ah_domain_error_if(u == v)
158 << "Tree_Topology: self-loop detected";
159
160 Pair_Key key = u < v ? std::make_pair(u, v) : std::make_pair(v, u);
161 if (unique_edges.search(key) != nullptr)
162 continue; // skip duplicate
163 unique_edges.insert(key, 1);
164 ++edge_count;
165 }
166
168 << "Tree_Topology: not a tree (expected " << (n_ - 1)
169 << " edges, got " << edge_count << ")";
170
172 it.has_curr(); it.next_ne())
173 {
174 const auto & [fst, snd] = it.get_curr();
175 const size_t u = fst.first;
176 const size_t v = fst.second;
177 children_(u).append(v);
178 children_(v).append(u);
179 }
180 }
181
184 {
185 if (n_ == 0)
186 return;
187
189 for (size_t i = 0; i < n_; ++i)
190 parent_(i) = NONE;
191
193
195 for (size_t i = 0; i < n_; ++i)
196 visited(i) = 0;
197
198 const size_t root_id = node_to_id_.find(root_);
199
200 struct Frame
201 {
202 size_t node;
203 size_t next_child;
204 };
206
207 visited(root_id) = 1;
208 stack.push({root_id, 0});
209
210 while (not stack.is_empty())
211 {
212 auto & fr = stack.top();
213 if (fr.next_child == children_(fr.node).size())
214 {
215 order_.append(fr.node);
216 (void) stack.pop();
217 continue;
218 }
219
220 const size_t nxt = children_(fr.node)(fr.next_child++);
221 if (visited(nxt))
222 continue;
223
224 visited(nxt) = 1;
225 parent_(nxt) = fr.node;
226 stack.push({nxt, 0});
227 }
228
230 << "Tree_Topology: graph is not connected";
231
232 // Filter children_ to only contain children after rooting
233 for (size_t i = 0; i < n_; ++i)
234 {
236 const size_t p = parent_(i);
237 for (size_t j = 0; j < children_(i).size(); ++j)
238 if (children_(i)[j] != p)
240 children_(i).swap(children);
241 }
242 }
243
244 public:
251 Tree_Topology(const GT & g, Node *root, SA sa = SA())
252 : graph_(&g), sa_(std::move(sa)), root_(root)
253 {
254 index_nodes();
256 build_order();
257 }
258
260 [[nodiscard]] size_t size() const noexcept { return n_; }
261
263 [[nodiscard]] Node * root() const noexcept { return root_; }
264
266 [[nodiscard]] size_t id_of(Node *node) const
267 {
268 const auto *item = node_to_id_.search(node);
269 ah_domain_error_if(item == nullptr)
270 << "Tree_Topology::id_of: node not in graph";
271 return item->second;
272 }
273
275 [[nodiscard]] Node * node_of(size_t id) const
276 {
278 << "Tree_Topology::node_of: id out of range";
279 return id_to_node_(id);
280 }
281
283 [[nodiscard]] const Array<size_t> &children(size_t id) const
284 {
285 return children_(id);
286 }
287
289 [[nodiscard]] size_t parent(size_t id) const noexcept
290 {
291 return parent_(id);
292 }
293
296 {
297 return order_;
298 }
299
302 {
303 return id_to_node_;
304 }
305 };
306 } // namespace tree_dp_detail
307
308
331 template <class GT, typename T, class SA = Dft_Show_Arc<GT>>
333 {
334 public:
335 using Node = typename GT::Node;
338 using Init_Fn = std::function<T(Node *)>;
339
345 using Combine_Fn = std::function<T(Node *, const T &, Node *, const T &)>;
346
347 private:
351 public:
360 Gen_Tree_DP(const GT & g, Node *root,
361 Init_Fn init, Combine_Fn combine, SA sa = SA())
362 : topo_(g, root, std::move(sa))
363 {
364 const size_t n = topo_.size();
365 if (n == 0)
366 return;
367
369
370 // Initialize all nodes
371 for (size_t i = 0; i < n; ++i)
372 dp_(i) = init(topo_.node_of(i));
373
374 // Process in post-order (leaves first)
375 const auto & order = topo_.post_order();
376 for (size_t k = 0; k < n; ++k)
377 {
378 const size_t v = order[k];
379 const size_t par = topo_.parent(v);
381 continue; // root, no parent to update
382 dp_(par) = combine(topo_.node_of(par), dp_(par),
383 topo_.node_of(v), dp_(v));
384 }
385 }
386
391 [[nodiscard]] const T &value(Node *node) const
392 {
393 return dp_(topo_.id_of(node));
394 }
395
398 {
399 return dp_;
400 }
401
404 {
405 return topo_.size();
406 }
407
412 [[nodiscard]] Node * node_of(size_t id) const
413 {
414 return topo_.node_of(id);
415 }
416
421 [[nodiscard]] size_t id_of(Node *node) const
422 {
423 return topo_.id_of(node);
424 }
425 };
426
432 template <class GT, typename T, class SA = Dft_Show_Arc<GT>>
434
435
460 template <class GT, typename T, class SA = Dft_Show_Arc<GT>>
462 {
463 public:
464 using Node = typename GT::Node;
467 using Init_Fn = std::function<T(Node *)>;
468
470 using Merge_Fn = std::function<T(const T &, const T &)>;
471
477 using Apply_Edge_Fn = std::function<T(Node *, Node *, const T &)>;
478
479 private:
487 public:
499 const T & identity, Init_Fn init,
501 SA sa = SA())
502 : topo_(g, root, std::move(sa)), identity_(identity)
503 {
504 const size_t n = topo_.size();
505 if (n == 0)
506 return;
507
512
513 for (size_t i = 0; i < n; ++i)
514 {
515 init_vals_(i) = init(topo_.node_of(i));
516 dp_down_(i) = init_vals_[i];
517 dp_up_(i) = identity_;
518 }
519
520 // Phase 1: bottom-up
521 const auto & order = topo_.post_order();
522 for (size_t k = 0; k < n; ++k)
523 {
524 const size_t v = order[k];
525 const size_t par = topo_.parent(v);
527 continue;
528 const T contrib = apply_edge(topo_.node_of(par),
529 topo_.node_of(v), dp_down_(v));
530 dp_down_(par) = merge(dp_down_(par), contrib);
531 }
532
533 // Phase 2: top-down with prefix/suffix
534 // Process nodes in reverse post-order (root first)
535 for (size_t k = n; k-- > 0; )
536 {
537 const size_t v = order[k];
538 Node *vn = topo_.node_of(v);
539
540 // Collect children of v
541 const auto & children = topo_.children(v);
542 const size_t nc = children.size();
543 if (nc == 0)
544 continue;
545
547 for (size_t j = 0; j < nc; ++j)
548 {
549 const size_t c = children[j];
550 contribs(j) = apply_edge(vn, topo_.node_of(c), dp_down_(c));
551 }
552
553 // Build prefix and suffix arrays of merged contributions
556 prefix(0) = identity_;
558
559 for (size_t j = 0; j < nc; ++j)
560 prefix(j + 1) = merge(prefix(j), contribs(j));
561
562 for (size_t j = nc; j-- > 0; )
563 suffix(j) = merge(suffix(j + 1), contribs(j));
564
565 const T base = merge(init_vals_[v], dp_up_(v));
566
567 // For each child, compute dp_up
568 for (size_t j = 0; j < nc; ++j)
569 {
570 const size_t c = children[j];
571 Node *cn = topo_.node_of(c);
572 // Value of v without child c's subtree:
573 // merge(init(v), dp_up(v), prefix(j), suffix(j+1))
574 T without_c = merge(base, prefix(j));
575 without_c = merge(without_c, suffix(j + 1));
576 dp_up_(c) = apply_edge(cn, vn, without_c);
577 }
578 }
579
580 // Phase 3: compute answers
581 for (size_t i = 0; i < n; ++i)
582 answer_(i) = merge(dp_down_(i), dp_up_(i));
583 }
584
589 [[nodiscard]] const T &value(Node *node) const
590 {
591 return answer_(topo_.id_of(node));
592 }
593
596 {
597 return answer_;
598 }
599
602 {
603 return topo_.size();
604 }
605
610 [[nodiscard]] Node * node_of(size_t id) const
611 {
612 return topo_.node_of(id);
613 }
614
619 [[nodiscard]] size_t id_of(Node *node) const
620 {
621 return topo_.id_of(node);
622 }
623 };
624
630 template <class GT, typename T, class SA = Dft_Show_Arc<GT>>
632
633
634 // ── Convenience functions ─────────────────────────────────────────
635
645 template <class GT, class SA = Dft_Show_Arc<GT>>
647 tree_subtree_sizes(const GT & g, typename GT::Node *root, SA sa = SA())
648 {
650 [](auto *) -> size_t { return 1; },
651 [](auto *, const size_t & acc, auto *, const size_t & child) -> size_t
652 {
653 return acc + child;
654 },
655 std::move(sa));
656
657 // Copy values out
658 const auto & vals = dp.values();
660 for (size_t i = 0; i < vals.size(); ++i)
661 result(i) = vals[i];
662 return result;
663 }
664
665
678 template <class GT, class SA = Dft_Show_Arc<GT>>
680 tree_max_distance(const GT & g, typename GT::Node *root, SA sa = SA())
681 {
682 Gen_Reroot_DP<GT, size_t, SA> dp(g, root, static_cast<size_t>(0),
683 [](auto *) -> size_t { return 0; },
684 [](const size_t & a, const size_t & b) -> size_t
685 {
686 return std::max(a, b);
687 },
688 [](auto *, auto *, const size_t & v) -> size_t { return v + 1; },
689 std::move(sa));
690
691 const auto & vals = dp.values();
693 for (size_t i = 0; i < vals.size(); ++i)
694 result(i) = vals[i];
695 return result;
696 }
697
698
710 template <class GT, class SA = Dft_Show_Arc<GT>>
712 tree_sum_of_distances(const GT & g, typename GT::Node *root, SA sa = SA())
713 {
714 using P = std::pair<size_t, size_t>; // (count, sum_dist)
715
717 P{0, 0},
718 [](auto *) -> P { return {1, 0}; },
719 [](const P & a, const P & b) -> P
720 {
721 return {a.first + b.first, a.second + b.second};
722 },
723 [](auto *, auto *, const P & v) -> P
724 {
725 return {v.first, v.second + v.first};
726 },
727 std::move(sa));
728
729 const auto & vals = dp.values();
731 for (size_t i = 0; i < vals.size(); ++i)
732 result(i) = vals[i].second;
733 return result;
734 }
735} // namespace Aleph
736
737# endif // TREE_DP_H
Exception handling system with formatted messages for Aleph-w.
#define ah_runtime_error_unless(C)
Throws std::runtime_error if condition does NOT hold.
Definition ah-errors.H:250
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:579
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:139
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:194
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:351
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:245
void reserve(size_t cap)
Reserves cap cells into the array.
Definition tpl_array.H:315
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.
Generic key-value map implemented on top of a binary search tree.
typename Base::Iterator Iterator
void next_ne() noexcept
Advances the iterator to the next filtered element (noexcept version).
Rerooting DP: O(n) computation of DP answer for all roots.
Definition Tree_DP.H:462
Array< T > dp_up_
Top-down contribution from parent side.
Definition Tree_DP.H:484
std::function< T(Node *)> Init_Fn
Initialization function: base contribution of a node.
Definition Tree_DP.H:467
std::function< T(const T &, const T &)> Merge_Fn
Merge function: associative binary operation to combine results.
Definition Tree_DP.H:470
Gen_Reroot_DP(const GT &g, Node *root, const T &identity, Init_Fn init, Merge_Fn merge, Apply_Edge_Fn apply_edge, SA sa=SA())
Construct and compute rerooting DP.
Definition Tree_DP.H:498
typename GT::Node Node
Node type.
Definition Tree_DP.H:464
Node * node_of(size_t id) const
Returns the node pointer for a given internal ID.
Definition Tree_DP.H:610
size_t id_of(Node *node) const
Returns the internal ID for a given node pointer.
Definition Tree_DP.H:619
Array< T > dp_down_
Bottom-up DP results.
Definition Tree_DP.H:483
Array< T > init_vals_
Cached per-node base values.
Definition Tree_DP.H:482
tree_dp_detail::Tree_Topology< GT, SA > topo_
Tree topology and order.
Definition Tree_DP.H:480
std::function< T(Node *, Node *, const T &)> Apply_Edge_Fn
Edge transformation function: applies edge effects to a subtree result.
Definition Tree_DP.H:477
Array< T > answer_
Final answer for each node as root.
Definition Tree_DP.H:485
const Array< T > & values() const noexcept
Returns all computed answers (indexed by internal ID).
Definition Tree_DP.H:595
size_t size() const noexcept
Returns the number of nodes in the tree.
Definition Tree_DP.H:601
T identity_
Identity for merge operation.
Definition Tree_DP.H:481
const T & value(Node *node) const
Returns the answer for a given node as root.
Definition Tree_DP.H:589
Generic bottom-up tree DP.
Definition Tree_DP.H:333
const Array< T > & values() const noexcept
Returns all DP values (indexed by internal node ID).
Definition Tree_DP.H:397
typename GT::Node Node
Node type.
Definition Tree_DP.H:335
Node * node_of(size_t id) const
Returns the node pointer for a given internal ID.
Definition Tree_DP.H:412
size_t id_of(Node *node) const
Returns the internal ID for a given node pointer.
Definition Tree_DP.H:421
Gen_Tree_DP(const GT &g, Node *root, Init_Fn init, Combine_Fn combine, SA sa=SA())
Construct and compute bottom-up DP.
Definition Tree_DP.H:360
size_t size() const noexcept
Returns the number of nodes in the tree.
Definition Tree_DP.H:403
Array< T > dp_
Computed DP values.
Definition Tree_DP.H:349
tree_dp_detail::Tree_Topology< GT, SA > topo_
Tree topology and order.
Definition Tree_DP.H:348
std::function< T(Node *, const T &, Node *, const T &)> Combine_Fn
Combine function: folds a child's value into the accumulator.
Definition Tree_DP.H:345
std::function< T(Node *)> Init_Fn
Initialization function: maps a leaf/node to its base value.
Definition Tree_DP.H:338
const T & value(Node *node) const
Returns the DP value for a given node.
Definition Tree_DP.H:391
Filtered iterator on the nodes of a graph.
Definition tpl_graph.H:1206
Extract tree topology: node indexing, adjacency, parent, order.
Definition Tree_DP.H:78
const Array< size_t > & children(size_t id) const
Returns children IDs of a node.
Definition Tree_DP.H:283
static constexpr size_t NONE
Sentinel for null/none parent or id.
Definition Tree_DP.H:84
size_t n_
Number of nodes.
Definition Tree_DP.H:90
const Array< size_t > & post_order() const noexcept
Returns post-order traversal (leaves first, root last).
Definition Tree_DP.H:295
Array< Array< size_t > > children_
Children list in the rooted tree.
Definition Tree_DP.H:94
Node * node_of(size_t id) const
Returns node pointer for a given ID.
Definition Tree_DP.H:275
const GT * graph_
Source graph.
Definition Tree_DP.H:87
size_t id_of(Node *node) const
Returns internal ID of a node.
Definition Tree_DP.H:266
typename GT::Arc Arc
Arc type.
Definition Tree_DP.H:81
void index_nodes()
Assign unique IDs to nodes and validate the root.
Definition Tree_DP.H:99
MapOLhash< Node *, size_t > node_to_id_
Mapping from node pointer to id.
Definition Tree_DP.H:93
Array< size_t > parent_
Parent id for each node.
Definition Tree_DP.H:95
Array< Node * > id_to_node_
Mapping from id to node pointer.
Definition Tree_DP.H:92
Node * root() const noexcept
Returns root node pointer.
Definition Tree_DP.H:263
void build_order()
BFS/DFS traversal to establish parent-child relations and order.
Definition Tree_DP.H:183
size_t parent(size_t id) const noexcept
Returns parent ID of a node.
Definition Tree_DP.H:289
size_t size() const noexcept
Returns number of nodes.
Definition Tree_DP.H:260
void build_adjacency()
Build undirected adjacency list and verify tree properties.
Definition Tree_DP.H:131
Array< size_t > order_
Post-order traversal (leaves first).
Definition Tree_DP.H:96
const Array< Node * > & nodes() const noexcept
Returns all node pointers indexed by ID.
Definition Tree_DP.H:301
Tree_Topology(const GT &g, Node *root, SA sa=SA())
Preprocess tree topology.
Definition Tree_DP.H:251
typename GT::Node Node
Node type.
Definition Tree_DP.H:80
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
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:743
pair< size_t, string > P
__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
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
Array< size_t > tree_subtree_sizes(const GT &g, typename GT::Node *root, SA sa=SA())
Compute subtree sizes for every node.
Definition Tree_DP.H:647
static void suffix(Node *root, DynList< Node * > &acc)
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.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
static void prefix(Node *root, DynList< Node * > &acc)
Itor3 merge(Itor1 source1Beg, Itor1 source1End, Itor2 source2Beg, Itor2 source2End, Itor3 destBeg)
Merge two sorted ranges.
Definition ahAlgo.H:1410
Array< size_t > tree_max_distance(const GT &g, typename GT::Node *root, SA sa=SA())
Compute the maximum distance from each node to any leaf.
Definition Tree_DP.H:680
Array< size_t > tree_sum_of_distances(const GT &g, typename GT::Node *root, SA sa=SA())
Compute sum of distances from each node to all others.
Definition Tree_DP.H:712
static std::atomic< bool > init
Definition hash-fct.C:53
STL namespace.
Filtered iterator on all the arcs of a graph.
Definition tpl_graph.H:1164
Open addressing hash map using linear probing.
Data & find(const Key &key)
Find and return the value for a key.
Pair * insert(const Key &key, const Data &data)
Insert a key-value pair (copy semantics).
Pair * search(const Key &key) const noexcept
Search for a key in the map.
static int * k
Dynamic array container with automatic resizing.
Dynamic stack implementation based on linked lists.
Dynamic map with open hashing.
Dynamic key-value map based on balanced binary search trees.
Generic graph and digraph implementations.