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
53#ifndef TREE_DP_H
54#define TREE_DP_H
55
56# include <ah-graph-concepts.H>
57
58#include <algorithm>
59#include <cstddef>
60#include <functional>
61#include <limits>
62#include <utility>
63
64#include <ah-errors.H>
65#include <tpl_array.H>
66#include <tpl_dynListStack.H>
67#include <tpl_dynMapOhash.H>
68#include <tpl_dynMapTree.H>
69#include <tpl_graph.H>
70
71namespace Aleph {
72namespace tree_dp_detail {
81template <AlephGraph GT, ArcFilter<GT> SA>
83{
84public:
85 using Node = typename GT::Node;
86 using Arc = typename GT::Arc;
89 static constexpr size_t NONE = std::numeric_limits<size_t>::max();
90
91private:
92 const GT *graph_ = nullptr;
93 SA sa_;
94 Node *root_ = nullptr;
95 size_t n_ = 0;
105 {
107 if (n_ == 0)
108 {
109 ah_domain_error_if(root_ != nullptr)
110 << "Tree_Topology: non-null root provided for empty graph";
111 return;
112 }
113
115 {
117 node_to_id_.swap(tmp);
118 }
119
120 size_t next_id = 0;
121 for (Node_Iterator<GT> it(*graph_); it.has_curr(); it.next_ne())
122 {
123 Node *p = it.get_curr();
124 id_to_node_(next_id) = p;
126 ++next_id;
127 }
128
129 if (root_ == nullptr)
130 root_ = id_to_node_(0);
131 else
133 << "Tree_Topology: root node is not part of the graph";
134 }
135
138 {
139 if (n_ == 0)
140 return;
141
142 children_.reserve(n_);
143 for (size_t i = 0; i < n_; ++i)
144 children_.append(Array<size_t>());
145
146 using Pair_Key = std::pair<size_t, size_t>;
148 size_t edge_count = 0;
149
150 for (Arc_Iterator<GT, SA> it(*graph_, sa_); it.has_curr(); it.next_ne())
151 {
152 Arc *a = it.get_curr_ne();
153 Node *src = graph_->get_src_node(a);
154 Node *tgt = graph_->get_tgt_node(a);
155
156 const auto *si = node_to_id_.search(src);
157 const auto *ti = node_to_id_.search(tgt);
158 ah_runtime_error_unless(si != nullptr and ti != nullptr)
159 << "Tree_Topology: arc endpoint not indexed";
160
161 const size_t u = si->second;
162 const size_t v = ti->second;
163 ah_domain_error_if(u == v) << "Tree_Topology: self-loop detected";
164
165 Pair_Key key = u < v ? std::make_pair(u, v) : std::make_pair(v, u);
166 if (unique_edges.search(key) != nullptr)
167 continue; // skip duplicate
168 unique_edges.insert(key, 1);
169 ++edge_count;
170 }
171
173 << "Tree_Topology: not a tree (expected " << (n_ - 1) << " edges, got " << edge_count << ")";
174
175 for (typename DynMapTree<Pair_Key, char>::Iterator it(unique_edges); it.has_curr(); it.next_ne())
176 {
177 const auto &[fst, snd] = it.get_curr();
178 const size_t u = fst.first;
179 const size_t v = fst.second;
180 children_(u).append(v);
181 children_(v).append(u);
182 }
183 }
184
187 {
188 if (n_ == 0)
189 return;
190
192 for (size_t i = 0; i < n_; ++i)
193 parent_(i) = NONE;
194
196
198 for (size_t i = 0; i < n_; ++i)
199 visited(i) = 0;
200
201 const size_t root_id = node_to_id_.find(root_);
202
203 struct Frame
204 {
205 size_t node;
206 size_t next_child;
207 };
209
210 visited(root_id) = 1;
211 stack.push({root_id, 0});
212
213 while (not stack.is_empty())
214 {
215 auto &fr = stack.top();
216 if (fr.next_child == children_(fr.node).size())
217 {
218 order_.append(fr.node);
219 (void) stack.pop();
220 continue;
221 }
222
223 const size_t nxt = children_(fr.node)(fr.next_child++);
224 if (visited(nxt))
225 continue;
226
227 visited(nxt) = 1;
228 parent_(nxt) = fr.node;
229 stack.push({nxt, 0});
230 }
231
232 ah_domain_error_if(order_.size() != n_) << "Tree_Topology: graph is not connected";
233
234 // Filter children_ to only contain children after rooting
235 for (size_t i = 0; i < n_; ++i)
236 {
238 const size_t p = parent_(i);
239 for (size_t j = 0; j < children_(i).size(); ++j)
240 if (children_(i)[j] != p)
242 children_(i).swap(children);
243 }
244 }
245
246public:
253 Tree_Topology(const GT &g, Node *root, SA sa = SA()) : graph_(&g), sa_(std::move(sa)), root_(root)
254 {
255 index_nodes();
257 build_order();
258 }
259
262 {
263 return n_;
264 }
265
268 {
269 return root_;
270 }
271
273 [[nodiscard]] size_t id_of(Node *node) const
274 {
275 const auto *item = node_to_id_.search(node);
276 ah_domain_error_if(item == nullptr) << "Tree_Topology::id_of: node not in graph";
277 return item->second;
278 }
279
281 [[nodiscard]] Node *node_of(size_t id) const
282 {
283 ah_out_of_range_error_if(id >= n_) << "Tree_Topology::node_of: id out of range";
284 return id_to_node_(id);
285 }
286
288 [[nodiscard]] const Array<size_t> &children(size_t id) const
289 {
290 return children_(id);
291 }
292
294 [[nodiscard]] size_t parent(size_t id) const noexcept
295 {
296 return parent_(id);
297 }
298
301 {
302 return order_;
303 }
304
307 {
308 return id_to_node_;
309 }
310};
311} // namespace tree_dp_detail
312
339template <AlephGraph GT, typename T, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
341{
342public:
343 using Node = typename GT::Node;
348 using Init_Fn = std::function<T(Node *)>;
349
354 using Combine_Fn = std::function<T(Node *, const T &, Node *, const T &)>;
355
356private:
360public:
369 Gen_Tree_DP(const GT &g, Node *root, Init_Fn init, Combine_Fn combine, SA sa = SA())
370 : topo_(g, root, std::move(sa))
371 {
372 const size_t n = topo_.size();
373 if (n == 0)
374 return;
375
377
378 // Initialize all nodes
379 for (size_t i = 0; i < n; ++i)
380 dp_(i) = init(topo_.node_of(i));
381
382 // Process in post-order (leaves first)
383 const auto &order = topo_.post_order();
384 for (size_t k = 0; k < n; ++k)
385 {
386 const size_t v = order[k];
387 const size_t par = topo_.parent(v);
389 continue; // root, no parent to update
390 dp_(par) = combine(topo_.node_of(par), dp_(par), topo_.node_of(v), dp_(v));
391 }
392 }
393
398 [[nodiscard]] const T &value(Node *node) const
399 {
400 return dp_(topo_.id_of(node));
401 }
402
405 {
406 return dp_;
407 }
408
411 {
412 return topo_.size();
413 }
414
419 [[nodiscard]] Node *node_of(size_t id) const
420 {
421 return topo_.node_of(id);
422 }
423
428 [[nodiscard]] size_t id_of(Node *node) const
429 {
430 return topo_.id_of(node);
431 }
432};
433
439template <class GT, typename T, class SA = Dft_Show_Arc<GT>>
441
477template <AlephGraph GT, typename T, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
479{
480public:
481 using Node = typename GT::Node;
486 using Init_Fn = std::function<T(Node *)>;
487
491 using Merge_Fn = std::function<T(const T &, const T &)>;
492
497 using Apply_Edge_Fn = std::function<T(Node *, Node *, const T &)>;
498
499private:
507public:
519 Node *root,
520 const T &identity,
524 SA sa = SA())
525 : topo_(g, root, std::move(sa)), identity_(identity)
526 {
527 const size_t n = topo_.size();
528 if (n == 0)
529 return;
530
535
536 for (size_t i = 0; i < n; ++i)
537 {
538 init_vals_(i) = init(topo_.node_of(i));
539 dp_down_(i) = init_vals_[i];
540 dp_up_(i) = identity_;
541 }
542
543 // Phase 1: bottom-up
544 const auto &order = topo_.post_order();
545 for (size_t k = 0; k < n; ++k)
546 {
547 const size_t v = order[k];
548 const size_t par = topo_.parent(v);
550 continue;
551 const T contrib = apply_edge(topo_.node_of(par), topo_.node_of(v), dp_down_(v));
552 dp_down_(par) = merge(dp_down_(par), contrib);
553 }
554
555 // Phase 2: top-down with prefix/suffix
556 // Process nodes in reverse post-order (root first)
557 for (size_t k = n; k-- > 0;)
558 {
559 const size_t v = order[k];
560 Node *vn = topo_.node_of(v);
561
562 // Collect children of v
563 const auto &children = topo_.children(v);
564 const size_t nc = children.size();
565 if (nc == 0)
566 continue;
567
569 for (size_t j = 0; j < nc; ++j)
570 {
571 const size_t c = children[j];
572 contribs(j) = apply_edge(vn, topo_.node_of(c), dp_down_(c));
573 }
574
575 // Build prefix and suffix arrays of merged contributions
578 prefix(0) = identity_;
580
581 for (size_t j = 0; j < nc; ++j)
582 prefix(j + 1) = merge(prefix(j), contribs(j));
583
584 for (size_t j = nc; j-- > 0;)
585 suffix(j) = merge(suffix(j + 1), contribs(j));
586
587 const T base = merge(init_vals_[v], dp_up_(v));
588
589 // For each child, compute dp_up
590 for (size_t j = 0; j < nc; ++j)
591 {
592 const size_t c = children[j];
593 Node *cn = topo_.node_of(c);
594 // Value of v without child c's subtree:
595 // merge(init(v), dp_up(v), prefix(j), suffix(j+1))
596 T without_c = merge(base, prefix(j));
597 without_c = merge(without_c, suffix(j + 1));
598 dp_up_(c) = apply_edge(cn, vn, without_c);
599 }
600 }
601
602 // Phase 3: compute answers
603 for (size_t i = 0; i < n; ++i)
604 answer_(i) = merge(dp_down_(i), dp_up_(i));
605 }
606
611 [[nodiscard]] const T &value(Node *node) const
612 {
613 return answer_(topo_.id_of(node));
614 }
615
618 {
619 return answer_;
620 }
621
624 {
625 return topo_.size();
626 }
627
632 [[nodiscard]] Node *node_of(size_t id) const
633 {
634 return topo_.node_of(id);
635 }
636
641 [[nodiscard]] size_t id_of(Node *node) const
642 {
643 return topo_.id_of(node);
644 }
645};
646
652template <class GT, typename T, class SA = Dft_Show_Arc<GT>>
654
655// ── Convenience functions ─────────────────────────────────────────
656
666template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
667[[nodiscard]] Array<size_t> tree_subtree_sizes(const GT &g, typename GT::Node *root, SA sa = SA())
668{
670 root,
671 [](auto *) -> size_t
672 {
673 return 1;
674 },
675 [](auto *, const size_t &acc, auto *, const size_t &child) -> size_t
676 {
677 return acc + child;
678 },
679 std::move(sa));
680
681 // Copy values out
682 const auto &vals = dp.values();
684 for (size_t i = 0; i < vals.size(); ++i)
685 result(i) = vals[i];
686 return result;
687}
688
701template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
702[[nodiscard]] Array<size_t> tree_max_distance(const GT &g, typename GT::Node *root, SA sa = SA())
703{
705 root,
706 static_cast<size_t>(0),
707 [](auto *) -> size_t
708 {
709 return 0;
710 },
711 [](const size_t &a, const size_t &b) -> size_t
712 {
713 return std::max(a, b);
714 },
715 [](auto *, auto *, const size_t &v) -> size_t
716 {
717 return v + 1;
718 },
719 std::move(sa));
720
721 const auto &vals = dp.values();
723 for (size_t i = 0; i < vals.size(); ++i)
724 result(i) = vals[i];
725 return result;
726}
727
739template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
740[[nodiscard]] Array<size_t> tree_sum_of_distances(const GT &g, typename GT::Node *root, SA sa = SA())
741{
742 using P = std::pair<size_t, size_t>; // (count, sum_dist)
743
745 root,
746 P{0, 0},
747 [](auto *) -> P
748 {
749 return {1, 0};
750 },
751 [](const P &a, const P &b) -> P
752 {
753 return {a.first + b.first, a.second + b.second};
754 },
755 [](auto *, auto *, const P &v) -> P
756 {
757 return {v.first, v.second + v.first};
758 },
759 std::move(sa));
760
761 const auto &vals = dp.values();
763 for (size_t i = 0; i < vals.size(); ++i)
764 result(i) = vals[i].second;
765 return result;
766}
767} // namespace Aleph
768
769#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:255
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:584
#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.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
static Array create(size_t n)
Create an array with n logical elements.
Definition tpl_array.H:196
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:365
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:250
void reserve(size_t cap)
Reserves cap cells into the array.
Definition tpl_array.H:320
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).
Generic rerooting dynamic programming (all-roots DP).
Definition Tree_DP.H:479
Array< T > dp_up_
Top-down contribution from parent side.
Definition Tree_DP.H:504
std::function< T(Node *)> Init_Fn
Initialization function signature.
Definition Tree_DP.H:486
std::function< T(const T &, const T &)> Merge_Fn
Merge function signature.
Definition Tree_DP.H:491
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:518
typename GT::Node Node
Node type.
Definition Tree_DP.H:481
Node * node_of(size_t id) const
Returns the node pointer for a given internal ID.
Definition Tree_DP.H:632
size_t id_of(Node *node) const
Returns the internal ID for a given node pointer.
Definition Tree_DP.H:641
Array< T > dp_down_
Bottom-up DP results.
Definition Tree_DP.H:503
Array< T > init_vals_
Cached per-node base values.
Definition Tree_DP.H:502
tree_dp_detail::Tree_Topology< GT, SA > topo_
Tree topology and order.
Definition Tree_DP.H:500
std::function< T(Node *, Node *, const T &)> Apply_Edge_Fn
Edge transformation signature.
Definition Tree_DP.H:497
Array< T > answer_
Final answer for each node as root.
Definition Tree_DP.H:505
const Array< T > & values() const noexcept
Returns all computed answers (indexed by internal ID).
Definition Tree_DP.H:617
size_t size() const noexcept
Returns the number of nodes in the tree.
Definition Tree_DP.H:623
T identity_
Identity for merge operation.
Definition Tree_DP.H:501
const T & value(Node *node) const
Returns the answer for a given node as root.
Definition Tree_DP.H:611
Generic bottom-up tree dynamic programming.
Definition Tree_DP.H:341
const Array< T > & values() const noexcept
Returns all DP values (indexed by internal node ID).
Definition Tree_DP.H:404
typename GT::Node Node
Node type.
Definition Tree_DP.H:343
Node * node_of(size_t id) const
Returns the node pointer for a given internal ID.
Definition Tree_DP.H:419
size_t id_of(Node *node) const
Returns the internal ID for a given node pointer.
Definition Tree_DP.H:428
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:369
size_t size() const noexcept
Returns the number of nodes in the tree.
Definition Tree_DP.H:410
Array< T > dp_
Computed DP values.
Definition Tree_DP.H:358
tree_dp_detail::Tree_Topology< GT, SA > topo_
Tree topology and order.
Definition Tree_DP.H:357
std::function< T(Node *, const T &, Node *, const T &)> Combine_Fn
Combine function signature.
Definition Tree_DP.H:354
std::function< T(Node *)> Init_Fn
Initialization function signature.
Definition Tree_DP.H:348
const T & value(Node *node) const
Returns the DP value for a given node.
Definition Tree_DP.H:398
Filtered iterator on the nodes of a graph.
Definition tpl_graph.H:1207
Pre-processes and extracts tree topology from a graph.
Definition Tree_DP.H:83
const Array< size_t > & children(size_t id) const
Returns children IDs of a node.
Definition Tree_DP.H:288
static constexpr size_t NONE
Sentinel for null/none parent or id.
Definition Tree_DP.H:89
size_t n_
Number of nodes.
Definition Tree_DP.H:95
const Array< size_t > & post_order() const noexcept
Returns post-order traversal (leaves first, root last).
Definition Tree_DP.H:300
Array< Array< size_t > > children_
Children list in the rooted tree.
Definition Tree_DP.H:99
Node * node_of(size_t id) const
Returns node pointer for a given ID.
Definition Tree_DP.H:281
const GT * graph_
Source graph.
Definition Tree_DP.H:92
size_t id_of(Node *node) const
Returns internal ID of a node.
Definition Tree_DP.H:273
typename GT::Arc Arc
Arc type.
Definition Tree_DP.H:86
void index_nodes()
Assign unique IDs to nodes and validate the root.
Definition Tree_DP.H:104
MapOLhash< Node *, size_t > node_to_id_
Mapping from node pointer to id.
Definition Tree_DP.H:98
Array< size_t > parent_
Parent id for each node.
Definition Tree_DP.H:100
Array< Node * > id_to_node_
Mapping from id to node pointer.
Definition Tree_DP.H:97
Node * root() const noexcept
Returns root node pointer.
Definition Tree_DP.H:267
void build_order()
BFS/DFS traversal to establish parent-child relations and order.
Definition Tree_DP.H:186
size_t parent(size_t id) const noexcept
Returns parent ID of a node.
Definition Tree_DP.H:294
size_t size() const noexcept
Returns number of nodes.
Definition Tree_DP.H:261
void build_adjacency()
Build undirected adjacency list and verify tree properties.
Definition Tree_DP.H:137
Array< size_t > order_
Post-order traversal (leaves first).
Definition Tree_DP.H:101
const Array< Node * > & nodes() const noexcept
Returns all node pointers indexed by ID.
Definition Tree_DP.H:306
Tree_Topology(const GT &g, Node *root, SA sa=SA())
Preprocess tree topology.
Definition Tree_DP.H:253
typename GT::Node Node
Node type.
Definition Tree_DP.H:85
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
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:785
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:4071
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
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
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:667
static void suffix(Node *root, DynList< Node * > &acc)
and
Check uniqueness with explicit hash + equality functors.
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:702
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:740
static std::atomic< bool > init
Definition hash-fct.C:54
STL namespace.
Filtered iterator on all the arcs of a graph.
Definition tpl_graph.H:1165
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.