Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
mo_on_trees_example.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
57# include <tpl_mo_on_trees.H>
58# include <tpl_graph.H>
59# include <tpl_sgraph.H>
60# include <tpl_agraph.H>
61# include <tpl_dynListStack.H>
62# include <tpl_dynSetHash.H>
63
64# include <cassert>
65# include <cstdio>
66
67using namespace Aleph;
68
69// ================================================================
70// Brute-force helpers for verification
71// ================================================================
72
73// Brute-force distinct count over a subtree rooted at subtree_root,
74// where tree_root defines the parent/child orientation.
75template <class GT>
76static size_t brute_subtree_distinct(const GT & g,
77 typename GT::Node * tree_root,
78 typename GT::Node * subtree_root)
79{
80 using Node = typename GT::Node;
81 // 1. Compute parent map via DFS from tree_root
83 parent.insert(tree_root, nullptr);
85 stk.push({tree_root, nullptr});
86 while (not stk.is_empty())
87 {
88 auto [cur, par] = stk.pop();
89 for (auto it = typename GT::Node_Arc_Iterator(cur);
90 it.has_curr(); it.next_ne())
91 {
92 auto * a = it.get_curr();
93 auto * nb = g.get_connected_node(a, cur);
94 if (nb != par)
95 {
96 parent.insert(nb, cur);
97 stk.push({nb, cur});
98 }
99 }
100 }
101 // 2. DFS subtree_root following only children (not parent)
105 while (not stk2.is_empty())
106 {
107 auto * cur = stk2.pop();
108 seen.insert(cur->get_info());
109 for (auto it = typename GT::Node_Arc_Iterator(cur);
110 it.has_curr(); it.next_ne())
111 {
112 auto * a = it.get_curr();
113 auto * nb = g.get_connected_node(a, cur);
114 if (nb != parent.find(cur))
115 stk2.push(nb);
116 }
117 }
118 return seen.size();
119}
120
121// Brute-force distinct count on the path u→v in a tree
122template <class GT>
123static size_t brute_path_distinct(const GT & g,
124 typename GT::Node * root,
125 typename GT::Node * u,
126 typename GT::Node * v)
127{
128 using Node = typename GT::Node;
129 // Find path via DFS from root, then extract u→v
131 parent.insert(root, nullptr);
133 stk.push({root, nullptr});
134 while (not stk.is_empty())
135 {
136 auto [cur, par] = stk.pop();
137 for (auto it = typename GT::Node_Arc_Iterator(cur);
138 it.has_curr(); it.next_ne())
139 {
140 auto * a = it.get_curr();
141 auto * nb = g.get_connected_node(a, cur);
142 if (nb != par)
143 {
144 parent.insert(nb, cur);
145 stk.push({nb, cur});
146 }
147 }
148 }
149 // Collect ancestors of u
151 for (auto * p = u; p; p = parent.find(p))
153 // Find LCA
154 Node * lca_node = v;
155 while (!ancestors_u.has(lca_node))
156 lca_node = parent.find(lca_node);
157 // Collect values on path u → lca → v
159 for (auto * p = u; p != lca_node; p = parent.find(p))
160 vals.insert(p->get_info());
161 for (auto * p = v; p != lca_node; p = parent.find(p))
162 vals.insert(p->get_info());
163 vals.insert(lca_node->get_info());
164 return vals.size();
165}
166
167// ================================================================
168// Scenario 1: Rainforest Biodiversity (List_Graph, subtree queries)
169// ================================================================
170
172{
173 printf("=== SCENARIO 1: Rainforest Biodiversity (List_Graph) ===\n\n");
174 printf("A hierarchical forest canopy: each section stores its\n");
175 printf("dominant species ID. Subtree queries count distinct\n");
176 printf("species beneath each section.\n\n");
177
178 /* Tree structure (species IDs):
179 *
180 * 3 (root)
181 * / | \
182 * 1 4 1
183 * / \ |
184 * 5 9 3
185 * /
186 * 2
187 */
188
190 G g;
191
192 auto * r = g.insert_node(3); // root
193 auto * a = g.insert_node(1);
194 auto * b = g.insert_node(4);
195 auto * c = g.insert_node(1);
196 auto * d = g.insert_node(5);
197 auto * e = g.insert_node(9);
198 auto * f = g.insert_node(3);
199 auto * h = g.insert_node(2);
200
201 g.insert_arc(r, a);
202 g.insert_arc(r, b);
203 g.insert_arc(r, c);
204 g.insert_arc(a, d);
205 g.insert_arc(a, e);
206 g.insert_arc(c, f);
207 g.insert_arc(d, h);
208
209 printf(" Nodes: %zu, Edges: %zu\n\n", g.vsize(), g.esize());
210
212
213 auto ans = mot.subtree_solve({r, a, b, c, d});
214
215 printf("%-25s %s\n", "Subtree Root (species)", "Distinct species");
216 printf("%-25s %s\n", "------------------------", "----------------");
217 printf("%-25s %zu\n", "root (3)", ans(0));
218 printf("%-25s %zu\n", "a (1)", ans(1));
219 printf("%-25s %zu\n", "b (4)", ans(2));
220 printf("%-25s %zu\n", "c (1)", ans(3));
221 printf("%-25s %zu\n", "d (5)", ans(4));
222
223 assert(ans(0) == brute_subtree_distinct(g, r, r));
224 assert(ans(1) == brute_subtree_distinct(g, r, a));
225 assert(ans(2) == brute_subtree_distinct(g, r, b));
226 assert(ans(3) == brute_subtree_distinct(g, r, c));
227 assert(ans(4) == brute_subtree_distinct(g, r, d));
228
229 printf("\nAll assertions passed!\n\n");
230}
231
232// ================================================================
233// Scenario 2: Network Latency Analysis (List_SGraph, path queries)
234// ================================================================
235
236static void network_latency()
237{
238 printf("=== SCENARIO 2: Network Latency Analysis (List_SGraph) ===\n\n");
239 printf("A tree-shaped data-centre network. Each router has a\n");
240 printf("latency class (1-5). Path queries count distinct latency\n");
241 printf("classes between pairs of routers.\n\n");
242
243 /* Network tree (latency class):
244 *
245 * 2 (R0)
246 * / \
247 * 3(R1) 2(R2)
248 * / \ \
249 * 1(R3) 5(R4) 3(R5)
250 * | |
251 * 4(R6) 1(R7)
252 */
253
255 G g;
256
257 auto * r0 = g.insert_node(2);
258 auto * r1 = g.insert_node(3);
259 auto * r2 = g.insert_node(2);
260 auto * r3 = g.insert_node(1);
261 auto * r4 = g.insert_node(5);
262 auto * r5 = g.insert_node(3);
263 auto * r6 = g.insert_node(4);
264 auto * r7 = g.insert_node(1);
265
266 g.insert_arc(r0, r1);
267 g.insert_arc(r0, r2);
268 g.insert_arc(r1, r3);
269 g.insert_arc(r1, r4);
270 g.insert_arc(r2, r5);
271 g.insert_arc(r3, r6);
272 g.insert_arc(r5, r7);
273
274 printf(" Nodes: %zu, Edges: %zu\n\n", g.vsize(), g.esize());
275
277
278 auto ans = mot.path_solve({
279 {r6, r4}, // R6→R3→R1→R4: classes {4,1,3,5} = 4
280 {r6, r7}, // R6→R3→R1→R0→R2→R5→R7: {4,1,3,2,2,3,1} → {1,2,3,4}
281 {r0, r0}, // trivial: just R0 → {2} = 1
282 {r3, r5}, // R3→R1→R0→R2→R5: {1,3,2,2,3} → {1,2,3}
283 {r1, r2} // R1→R0→R2: {3,2,2} → {2,3}
284 });
285
286 printf("%-20s %s\n", "Path (routers)", "Distinct classes");
287 printf("%-20s %s\n", "-------------------", "----------------");
288 printf("%-20s %zu\n", "R6 → R4", ans(0));
289 printf("%-20s %zu\n", "R6 → R7", ans(1));
290 printf("%-20s %zu\n", "R0 → R0", ans(2));
291 printf("%-20s %zu\n", "R3 → R5", ans(3));
292 printf("%-20s %zu\n", "R1 → R2", ans(4));
293
294 assert(ans(0) == brute_path_distinct(g, r0, r6, r4));
295 assert(ans(1) == brute_path_distinct(g, r0, r6, r7));
296 assert(ans(2) == brute_path_distinct(g, r0, r0, r0));
297 assert(ans(3) == brute_path_distinct(g, r0, r3, r5));
298 assert(ans(4) == brute_path_distinct(g, r0, r1, r2));
299
300 printf("\nAll assertions passed!\n\n");
301}
302
303// ================================================================
304// Scenario 3: Corporate Org Chart (Array_Graph, subtree + path)
305// ================================================================
306
307static void org_chart()
308{
309 printf("=== SCENARIO 3: Corporate Org Chart (Array_Graph) ===\n\n");
310 printf("Org chart: each node stores a department ID.\n");
311 printf("Subtree queries: distinct departments under a VP.\n");
312 printf("Path queries: distinct departments between employees.\n\n");
313
314 /* Org chart (dept IDs):
315 *
316 * 10 (CEO)
317 * / \
318 * 20(VP1) 30(VP2)
319 * / \ \
320 * 10(D1) 20(D2) 30(D3)
321 * |
322 * 40(D4)
323 */
324
326 G g;
327
328 auto * ceo = g.insert_node(10);
329 auto * vp1 = g.insert_node(20);
330 auto * vp2 = g.insert_node(30);
331 auto * d1 = g.insert_node(10);
332 auto * d2 = g.insert_node(20);
333 auto * d3 = g.insert_node(30);
334 auto * d4 = g.insert_node(40);
335
336 g.insert_arc(ceo, vp1);
337 g.insert_arc(ceo, vp2);
338 g.insert_arc(vp1, d1);
339 g.insert_arc(vp1, d2);
340 g.insert_arc(vp2, d3);
341 g.insert_arc(d1, d4);
342
343 printf(" Nodes: %zu, Edges: %zu\n\n", g.vsize(), g.esize());
344
346
347 // Subtree queries
348 auto sub_ans = mot.subtree_solve({ceo, vp1, vp2});
349
350 printf("--- Subtree queries ---\n");
351 printf("%-20s %s\n", "Root", "Distinct depts");
352 printf("%-20s %s\n", "-------------------", "--------------");
353 printf("%-20s %zu\n", "CEO (10)", sub_ans(0));
354 printf("%-20s %zu\n", "VP1 (20)", sub_ans(1));
355 printf("%-20s %zu\n", "VP2 (30)", sub_ans(2));
356
360
361 // Path queries
362 auto path_ans = mot.path_solve({
363 {d4, d2}, // D4→D1→VP1→D2: {40,10,20,20} → {10,20,40}
364 {d4, d3}, // D4→D1→VP1→CEO→VP2→D3: {40,10,20,10,30,30} → {10,20,30,40}
365 {vp1, vp2} // VP1→CEO→VP2: {20,10,30} → {10,20,30}
366 });
367
368 printf("\n--- Path queries ---\n");
369 printf("%-20s %s\n", "Path", "Distinct depts");
370 printf("%-20s %s\n", "-------------------", "--------------");
371 printf("%-20s %zu\n", "D4 → D2", path_ans(0));
372 printf("%-20s %zu\n", "D4 → D3", path_ans(1));
373 printf("%-20s %zu\n", "VP1 → VP2", path_ans(2));
374
375 assert(path_ans(0) == brute_path_distinct(g, ceo, d4, d2));
376 assert(path_ans(1) == brute_path_distinct(g, ceo, d4, d3));
378
379 printf("\nAll assertions passed!\n\n");
380}
381
382// ================================================================
383// Scenario 4: File-system inode types (Tree_Node)
384// ================================================================
385
386static void filesystem_inodes()
387{
388 printf("=== SCENARIO 4: File-system Inode Types (Tree_Node) ===\n\n");
389 printf("A directory tree where each node stores a file-type ID.\n");
390 printf("Subtree queries count distinct file types under a dir.\n");
391 printf("Path queries count distinct types between two files.\n\n");
392
393 using TN = Tree_Node<int>;
394
395 // root(1)
396 // / | \ .
397 // a(2) b(1) c(3)
398 // / \ |
399 // d(4) e(2) f(1)
400 // |
401 // g(5)
402
403 auto * root = new TN(1);
404 auto * a = new TN(2);
405 auto * b = new TN(1);
406 auto * c = new TN(3);
407 auto * d = new TN(4);
408 auto * e = new TN(2);
409 auto * f = new TN(1);
410 auto * g = new TN(5);
411
412 root->insert_rightmost_child(a);
413 root->insert_rightmost_child(b);
414 root->insert_rightmost_child(c);
415 a->insert_rightmost_child(d);
416 a->insert_rightmost_child(e);
417 c->insert_rightmost_child(f);
418 d->insert_rightmost_child(g);
419
420 printf(" Nodes: 8\n\n");
421
423
424 // --- Subtree queries ---
425 auto sub_ans = mot.subtree_solve({root, a, c, d});
426
427 printf("--- Subtree queries ---\n");
428 printf("Root Distinct types\n");
429 printf("------------------- --------------\n");
430 printf("root (1) %zu\n", sub_ans(0));
431 printf("a (2) %zu\n", sub_ans(1));
432 printf("c (3) %zu\n", sub_ans(2));
433 printf("d (4) %zu\n", sub_ans(3));
434
435 // root subtree: {1,2,1,3,4,2,1,5} → distinct = 5
436 assert(sub_ans(0) == 5);
437 // a subtree: {2,4,2,5} → distinct {2,4,5} = 3
438 assert(sub_ans(1) == 3);
439 // c subtree: {3,1} → distinct = 2
440 assert(sub_ans(2) == 2);
441 // d subtree: {4,5} → distinct = 2
442 assert(sub_ans(3) == 2);
443
444 // --- Path queries ---
445 auto path_ans = mot.path_solve({{g, f}, {e, b}, {d, c}});
446
447 printf("\n--- Path queries ---\n");
448 printf("Path Distinct types\n");
449 printf("------------------- --------------\n");
450 printf("g → f %zu\n", path_ans(0));
451 printf("e → b %zu\n", path_ans(1));
452 printf("d → c %zu\n", path_ans(2));
453
454 // g→f: g(5)→d(4)→a(2)→root(1)→c(3)→f(1) → {5,4,2,1,3} = 5
455 assert(path_ans(0) == 5);
456 // e→b: e(2)→a(2)→root(1)→b(1) → {2,1} = 2
457 assert(path_ans(1) == 2);
458 // d→c: d(4)→a(2)→root(1)→c(3) → {4,2,1,3} = 4
459 assert(path_ans(2) == 4);
460
461 printf("\nAll assertions passed!\n\n");
462
463 // Clean up
465}
466
467// ================================================================
468// Main
469// ================================================================
470
471int main()
472{
473 printf("Mo's Algorithm on Trees — Offline Subtree & Path Queries\n");
474 printf("========================================================\n\n");
475
478 org_chart();
480
481 printf("All scenarios completed successfully.\n");
482 return 0;
483}
WeightedDigraph::Node Node
long double h
Definition btreepic.C:154
Self-adjusting dynamic hash table.
Key * insert(const Key &key)
Inserts key into the hash set.
Dynamic stack of elements of generic type T based on a singly linked list.
T & push(const T &data)
Push an item by copy onto the top of the stack.
Pair * insert(const Key &key, const Data &data)
Inserts into the hash map the pair (key, record) indexed by key.
Data & find(const Key &key)
Finds and returns a reference to the value associated with key.
Offline subtree and path queries on N-ary trees (Tree_Node).
Offline subtree and path queries on trees via Mo's algorithm.
Arc for graphs implemented with simple adjacency lists.
Definition tpl_sgraph.H:197
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
Graph class implemented with singly-linked adjacency lists.
Definition tpl_sgraph.H:274
Generic m-ary trees.
Node * get_connected_node(Arc *arc, Node *node) const noexcept
Return the adjacent node to node through arc.
Definition graph-dry.H:778
constexpr size_t vsize() const noexcept
Definition graph-dry.H:704
size_t esize() const noexcept
Return the total of arcs of graph.
Definition graph-dry.H:798
__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 destroy_tree(Node *root)
Destroys (frees memory) the tree whose root is root.
static void rainforest_biodiversity()
static void org_chart()
static size_t brute_subtree_distinct(const GT &g, typename GT::Node *tree_root, typename GT::Node *subtree_root)
static size_t brute_path_distinct(const GT &g, typename GT::Node *root, typename GT::Node *u, typename GT::Node *v)
static void network_latency()
int main()
static void filesystem_inodes()
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
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.
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
gsl_rng * r
Array-based graph implementation.
Dynamic stack implementation based on linked lists.
Dynamic set implementations based on hash tables.
Generic graph and digraph implementations.
Mo's algorithm on trees: offline subtree and path queries.
Simple graph implementation with adjacency lists.