Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
lca_test.cc
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
46#include <gtest/gtest.h>
47
48#include <algorithm>
49#include <chrono>
50#include <cstddef>
51#include <cstdlib>
52#include <functional>
53#include <limits>
54#include <random>
55#include <stdexcept>
56#include <utility>
57
58#include <LCA.H>
59#include <tpl_agraph.H>
60#include <tpl_array.H>
61#include <tpl_graph.H>
62#include <tpl_sgraph.H>
63#include <htlist.H>
64
65#include "test_graph_helpers.h"
66
67using namespace Aleph;
71
72namespace
73{
74 class Naive_Tree_Oracle
75 {
76 static constexpr size_t NONE = std::numeric_limits<size_t>::max();
77
78 size_t n_ = 0;
79 size_t root_ = 0;
81 Array<size_t> parent_;
82 Array<size_t> depth_;
83 Array<size_t> tin_;
84 Array<size_t> tout_;
85 size_t timer_ = 0;
86
87 void dfs(const size_t u, const size_t p, const size_t d)
88 {
89 struct Frame
90 {
91 size_t u = 0;
92 size_t p = NONE;
93 size_t d = 0;
94 bool entering = true;
95 };
96
97 Array<Frame> stack;
98 stack.reserve(n_ * 2);
99 stack.append(Frame{u, p, d, true});
100
101 while (not stack.is_empty())
102 {
103 const Frame f = stack.remove_last();
104 if (f.entering)
105 {
106 parent_[f.u] = f.p;
107 depth_[f.u] = f.d;
108 tin_[f.u] = timer_++;
109
110 stack.append(Frame{f.u, f.p, f.d, false});
111
112 Array<size_t> children;
113 for (auto it = adj_[f.u].get_it(); it.has_curr(); it.next_ne())
114 {
115 const size_t v = it.get_curr();
116 if (v != f.p)
117 children.append(v);
118 }
119
120 for (long i = static_cast<long>(children.size()) - 1; i >= 0; --i)
121 stack.append(Frame{children[static_cast<size_t>(i)], f.u, f.d + 1, true});
122 }
123 else
124 {
125 tout_[f.u] = timer_ - 1;
126 }
127 }
128 }
129
130 public:
131 Naive_Tree_Oracle(const size_t n,
132 const Array<std::pair<size_t, size_t>> & edges,
133 const size_t root)
134 : n_(n),
135 root_(root),
136 adj_(Array<DynList<size_t>>::create(n)),
137 parent_(n, NONE),
138 depth_(n, 0),
139 tin_(n, 0),
140 tout_(n, 0)
141 {
142 ah_runtime_error_if(n_ == 0) << "Naive_Tree_Oracle requires n > 0";
143 ah_runtime_error_if(root_ >= n_) << "Naive_Tree_Oracle: invalid root";
144 ah_runtime_error_if(edges.size() != n_ - 1)
145 << "Naive_Tree_Oracle: edges.size() must be n-1";
146
147 for (typename Array<std::pair<size_t, size_t>>::Iterator it(edges);
148 it.has_curr(); it.next_ne())
149 {
150 const auto & e = it.get_curr();
151 const size_t u = e.first;
152 const size_t v = e.second;
153
154 ah_runtime_error_if(u >= n_ or v >= n_ or u == v)
155 << "Naive_Tree_Oracle: invalid edge";
156 adj_[u].append(v);
157 adj_[v].append(u);
158 }
159
160 dfs(root_, NONE, 0);
161
162 for (size_t i = 0; i < n_; ++i)
163 ah_runtime_error_if(parent_[i] == NONE and i != root_)
164 << "Naive_Tree_Oracle: disconnected input";
165 }
166
167 [[nodiscard]] size_t depth(const size_t u) const
168 {
169 ah_runtime_error_if(u >= n_) << "Naive_Tree_Oracle::depth: bad index";
170 return depth_[u];
171 }
172
173 [[nodiscard]] bool is_ancestor(const size_t u, const size_t v) const
174 {
175 ah_runtime_error_if(u >= n_ or v >= n_) << "Naive_Tree_Oracle::is_ancestor: bad index";
176 return tin_[u] <= tin_[v] and tout_[v] <= tout_[u];
177 }
178
179 [[nodiscard]] size_t lca(size_t u, size_t v) const
180 {
181 ah_runtime_error_if(u >= n_ or v >= n_) << "Naive_Tree_Oracle::lca: bad index";
182
183 if (depth_[u] < depth_[v])
184 std::swap(u, v);
185
186 while (depth_[u] > depth_[v])
187 u = parent_[u];
188
189 while (u != v)
190 {
191 u = parent_[u];
192 v = parent_[v];
193 }
194
195 return u;
196 }
197
198 [[nodiscard]] size_t distance(const size_t u, const size_t v) const
199 {
200 const size_t a = lca(u, v);
201 return depth_[u] + depth_[v] - 2 * depth_[a];
202 }
203
204 [[nodiscard]] size_t kth_ancestor(const size_t u, const size_t k) const
205 {
206 ah_runtime_error_if(u >= n_) << "Naive_Tree_Oracle::kth_ancestor: bad index";
207 if (k > depth_[u])
208 return NONE;
209
210 size_t cur = u;
211 for (size_t i = 0; i < k; ++i)
212 cur = parent_[cur];
213 return cur;
214 }
215
216 [[nodiscard]] static size_t none() noexcept { return NONE; }
217 };
218
219 template <class GT>
220 class LcaTypedTest : public ::testing::Test
221 {
222 };
223
224 using GraphBackends = ::testing::Types<
228
229 TYPED_TEST_SUITE(LcaTypedTest, GraphBackends);
230}
231
232
233TYPED_TEST(LcaTypedTest, EmptyTree)
234{
235 using Graph = TypeParam;
236
237 Graph g;
238
241
242 EXPECT_TRUE(bl.is_empty());
243 EXPECT_TRUE(er.is_empty());
244 EXPECT_EQ(bl.size(), 0u);
245 EXPECT_EQ(er.size(), 0u);
246
247 EXPECT_THROW(bl.lca_id(0, 0), std::domain_error);
248 EXPECT_THROW(er.lca_id(0, 0), std::domain_error);
249}
250
251TYPED_TEST(LcaTypedTest, SingleNode)
252{
253 using Graph = TypeParam;
254 using Node = typename Graph::Node;
255
256 Graph g;
257 Node * n0 = g.insert_node(7);
258
261
262 EXPECT_EQ(bl.size(), 1u);
263 EXPECT_EQ(er.size(), 1u);
264 EXPECT_EQ(bl.root(), n0);
265 EXPECT_EQ(er.root(), n0);
266
267 EXPECT_EQ(bl.lca(n0, n0), n0);
268 EXPECT_EQ(er.lca(n0, n0), n0);
269
270 EXPECT_EQ(bl.depth_of(n0), 0u);
271 EXPECT_EQ(er.depth_of(n0), 0u);
272 EXPECT_EQ(bl.distance(n0, n0), 0u);
273 EXPECT_EQ(er.distance(n0, n0), 0u);
274
275 EXPECT_EQ(bl.parent_of(n0), nullptr);
276 EXPECT_EQ(er.parent_of(n0), nullptr);
277 EXPECT_EQ(bl.kth_ancestor(n0, 1), nullptr);
278}
279
281{
282 using Graph = TypeParam;
283
284 // Rooted at 0:
285 // 0
286 // / (right)
287 // (left) 2
288 // 1 children of 2
289 // / \ 5 6
290 // 3 4 children of 5
291 // 7 and 8
293 edges.reserve(8);
294 edges.append(std::make_pair(0, 1));
295 edges.append(std::make_pair(0, 2));
296 edges.append(std::make_pair(1, 3));
297 edges.append(std::make_pair(1, 4));
298 edges.append(std::make_pair(2, 5));
299 edges.append(std::make_pair(2, 6));
300 edges.append(std::make_pair(5, 7));
301 edges.append(std::make_pair(5, 8));
302
303 Graph g;
304 auto nodes = build_graph_with_unit_arcs(g, 9, edges);
305
308
309 auto check = [&](const size_t u, const size_t v,
310 const size_t expected_lca, const size_t expected_dist)
311 {
312 auto * bl_lca = bl.lca(nodes(u), nodes(v));
313 auto * er_lca = er.lca(nodes(u), nodes(v));
314
315 EXPECT_EQ(static_cast<size_t>(bl_lca->get_info()), expected_lca)
316 << "u=" << u << " v=" << v;
317 EXPECT_EQ(static_cast<size_t>(er_lca->get_info()), expected_lca)
318 << "u=" << u << " v=" << v;
319 EXPECT_EQ(bl_lca, er_lca) << "u=" << u << " v=" << v;
320
321 EXPECT_EQ(bl.distance(nodes(u), nodes(v)), expected_dist);
322 EXPECT_EQ(er.distance(nodes(u), nodes(v)), expected_dist);
323 };
324
325 check(3, 4, 1, 2);
326 check(3, 6, 0, 4);
327 check(7, 8, 5, 2);
328 check(7, 6, 2, 3);
329 check(0, 8, 0, 3);
330
331 EXPECT_EQ(bl.kth_ancestor(nodes(8), 1), nodes(5));
332 EXPECT_EQ(bl.kth_ancestor(nodes(8), 2), nodes(2));
333 EXPECT_EQ(bl.kth_ancestor(nodes(8), 3), nodes(0));
334 EXPECT_EQ(bl.kth_ancestor(nodes(8), 4), nullptr);
335
336 EXPECT_TRUE(bl.is_ancestor(nodes(2), nodes(7)));
337 EXPECT_FALSE(bl.is_ancestor(nodes(1), nodes(7)));
338 EXPECT_TRUE(er.is_ancestor(nodes(2), nodes(7)));
339 EXPECT_FALSE(er.is_ancestor(nodes(1), nodes(7)));
340}
341
343{
344 using Graph = TypeParam;
345 using Node = typename Graph::Node;
346
348 edges.reserve(4);
349 edges.append(std::make_pair(0, 1));
350 edges.append(std::make_pair(1, 2));
351 edges.append(std::make_pair(2, 3));
352 edges.append(std::make_pair(3, 4));
353
354 Graph g;
355 auto nodes = build_graph_with_unit_arcs(g, 5, edges);
356
357 // Find the first node returned by Node_Iterator for this backend.
358 // List_Graph / Array_Graph iterate in insertion order, so the first
359 // node is nodes(0). List_SGraph iterates by pointer address (BST
360 // in-order), so the first node may differ — this is expected behaviour.
361 Node * first_node = nullptr;
362 for (Node_Iterator<Graph> it(g); it.has_curr(); it.next_ne())
363 {
364 first_node = it.get_curr();
365 break;
366 }
367 ASSERT_NE(first_node, nullptr);
368
371
372 // Both engines must choose the same default root = first iterated node.
373 EXPECT_EQ(bl.root(), first_node);
374 EXPECT_EQ(er.root(), first_node);
375
376 // Use the oracle with the actual default root to derive the expected LCA.
377 const size_t root_info = static_cast<size_t>(first_node->get_info());
378 Naive_Tree_Oracle oracle(5, edges, root_info);
379
380 const size_t expected_lca = oracle.lca(4, 2);
381 EXPECT_EQ(static_cast<size_t>(bl.lca(nodes(4), nodes(2))->get_info()), expected_lca);
382 EXPECT_EQ(static_cast<size_t>(er.lca(nodes(4), nodes(2))->get_info()), expected_lca);
383}
384
386{
387 using Graph = TypeParam;
388
390 edges.reserve(3);
391 edges.append(std::make_pair(0, 1));
392 edges.append(std::make_pair(1, 2));
393 edges.append(std::make_pair(2, 0));
394
395 Graph g;
396 auto nodes = build_graph_with_unit_arcs(g, 3, edges);
397
398 EXPECT_THROW((Binary_Lifting_LCA<Graph>(g, nodes(0))), std::domain_error);
399 EXPECT_THROW((Euler_RMQ_LCA<Graph>(g, nodes(0))), std::domain_error);
400}
401
403{
404 using Graph = TypeParam;
405
407 edges.reserve(2);
408 edges.append(std::make_pair(0, 1));
409 edges.append(std::make_pair(2, 3));
410
411 Graph g;
412 auto nodes = build_graph_with_unit_arcs(g, 4, edges);
413
414 EXPECT_THROW((Binary_Lifting_LCA<Graph>(g, nodes(0))), std::domain_error);
415 EXPECT_THROW((Euler_RMQ_LCA<Graph>(g, nodes(0))), std::domain_error);
416}
417
419{
420 using Graph = TypeParam;
421
422 {
423 Graph g;
425 edges.reserve(3);
426 edges.append(std::make_pair(0, 1));
427 edges.append(std::make_pair(1, 2));
428 edges.append(std::make_pair(2, 2));
429 auto nodes = build_graph_with_unit_arcs(g, 3, edges);
430 EXPECT_THROW((Binary_Lifting_LCA<Graph>(g, nodes(0))), std::domain_error);
431 EXPECT_THROW((Euler_RMQ_LCA<Graph>(g, nodes(0))), std::domain_error);
432 }
433
434 {
435 Graph g;
437 edges.reserve(2);
438 edges.append(std::make_pair(0, 1));
439 edges.append(std::make_pair(0, 1));
440 auto nodes = build_graph_with_unit_arcs(g, 2, edges);
441 EXPECT_THROW((Binary_Lifting_LCA<Graph>(g, nodes(0))), std::domain_error);
442 EXPECT_THROW((Euler_RMQ_LCA<Graph>(g, nodes(0))), std::domain_error);
443 }
444}
445
447{
448 using Graph = TypeParam;
449
450 Graph g;
452 for (size_t i = 0; i < 6; ++i)
453 nodes(i) = g.insert_node(static_cast<int>(i));
454
455 // Tree edges (kept by filter).
456 g.insert_arc(nodes(0), nodes(1), 1);
457 g.insert_arc(nodes(0), nodes(2), 1);
458 g.insert_arc(nodes(1), nodes(3), 1);
459 g.insert_arc(nodes(1), nodes(4), 1);
460 g.insert_arc(nodes(2), nodes(5), 1);
461
462 // Extra non-tree edges (ignored by filter).
463 g.insert_arc(nodes(3), nodes(5), -1);
464 g.insert_arc(nodes(4), nodes(2), -1);
465
466 EXPECT_THROW((Binary_Lifting_LCA<Graph>(g, nodes(0))), std::domain_error);
467 EXPECT_THROW((Euler_RMQ_LCA<Graph>(g, nodes(0))), std::domain_error);
468
471
472 EXPECT_EQ(static_cast<size_t>(bl.lca(nodes(3), nodes(4))->get_info()), 1u);
473 EXPECT_EQ(static_cast<size_t>(er.lca(nodes(3), nodes(4))->get_info()), 1u);
474 EXPECT_EQ(static_cast<size_t>(bl.lca(nodes(3), nodes(5))->get_info()), 0u);
475 EXPECT_EQ(static_cast<size_t>(er.lca(nodes(3), nodes(5))->get_info()), 0u);
476}
477
479{
480 using Graph = TypeParam;
481
482 Graph g1;
484 edges1.reserve(2);
485 edges1.append(std::make_pair(0, 1));
486 edges1.append(std::make_pair(1, 2));
487 auto n1 = build_graph_with_unit_arcs(g1, 3, edges1);
488
489 Graph g2;
491 edges2.reserve(1);
492 edges2.append(std::make_pair(0, 1));
493 auto n2 = build_graph_with_unit_arcs(g2, 2, edges2);
494
496 Euler_RMQ_LCA<Graph> er(g1, n1(0));
497
498 EXPECT_THROW(bl.lca(n1(0), n2(0)), std::domain_error);
499 EXPECT_THROW(er.lca(n1(0), n2(0)), std::domain_error);
500 EXPECT_THROW(bl.depth_of(n2(0)), std::domain_error);
501 EXPECT_THROW(er.depth_of(n2(0)), std::domain_error);
502
503 EXPECT_THROW(bl.lca_id(0, 99), std::out_of_range);
504 EXPECT_THROW(er.lca_id(0, 99), std::out_of_range);
505 EXPECT_THROW(bl.node_of(99), std::out_of_range);
506 EXPECT_THROW(er.node_of(99), std::out_of_range);
507}
508
510{
511 using Graph = TypeParam;
512
513 std::mt19937 rng(0x1ca2026u);
514
515 for (size_t sample = 0; sample < 24; ++sample)
516 {
517 std::uniform_int_distribution<size_t> n_pick(2, 90);
518 const size_t n = n_pick(rng);
520
521 Graph g;
522 auto nodes = build_graph_with_unit_arcs(g, n, edges);
523
524 std::uniform_int_distribution<size_t> root_pick(0, n - 1);
525 const size_t root = root_pick(rng);
526
529 Naive_Tree_Oracle oracle(n, edges, root);
530
531 for (size_t u = 0; u < n; ++u)
532 {
533 EXPECT_EQ(bl.depth_of(nodes(u)), oracle.depth(u));
534 EXPECT_EQ(er.depth_of(nodes(u)), oracle.depth(u));
535 EXPECT_EQ(bl.node_of(bl.id_of(nodes(u))), nodes(u));
536 EXPECT_EQ(er.node_of(er.id_of(nodes(u))), nodes(u));
537
538 std::uniform_int_distribution<size_t> k_pick(0, oracle.depth(u) + 2);
539 const size_t k = k_pick(rng);
540 const size_t expected = oracle.kth_ancestor(u, k);
541 auto * got = bl.kth_ancestor(nodes(u), k);
542 if (expected == Naive_Tree_Oracle::none())
543 EXPECT_EQ(got, nullptr);
544 else
545 EXPECT_EQ(static_cast<size_t>(got->get_info()), expected);
546 }
547
548 std::uniform_int_distribution<size_t> node_pick(0, n - 1);
549 for (size_t q = 0; q < 450; ++q)
550 {
551 const size_t u = node_pick(rng);
552 const size_t v = node_pick(rng);
553
554 const size_t expected_lca = oracle.lca(u, v);
555 const size_t expected_dist = oracle.distance(u, v);
556
557 auto * bl_lca = bl.lca(nodes(u), nodes(v));
558 auto * er_lca = er.lca(nodes(u), nodes(v));
559
560 EXPECT_EQ(static_cast<size_t>(bl_lca->get_info()), expected_lca)
561 << "sample=" << sample;
562 EXPECT_EQ(static_cast<size_t>(er_lca->get_info()), expected_lca)
563 << "sample=" << sample;
564 EXPECT_EQ(bl_lca, er_lca) << "sample=" << sample;
565
566 EXPECT_EQ(bl.distance(nodes(u), nodes(v)), expected_dist);
567 EXPECT_EQ(er.distance(nodes(u), nodes(v)), expected_dist);
568
569 EXPECT_EQ(bl.is_ancestor(nodes(expected_lca), nodes(u)),
570 oracle.is_ancestor(expected_lca, u));
571 EXPECT_EQ(er.is_ancestor(nodes(expected_lca), nodes(v)),
572 oracle.is_ancestor(expected_lca, v));
573 }
574 }
575}
576
578{
579 using Graph = TypeParam;
580 using Clock = std::chrono::steady_clock;
581
582# ifndef LCA_PERF_TEST
583 const char * run_perf = std::getenv("ALEPH_RUN_LCA_PERF");
584 if (run_perf == nullptr or run_perf[0] != '1' or run_perf[1] != '\0')
585 GTEST_SKIP() << "LCA perf test disabled by default. "
586 << "Enable with -DLCA_PERF_TEST or ALEPH_RUN_LCA_PERF=1";
587# endif
588
589 constexpr size_t n = 100000;
590 constexpr size_t query_count = 300000;
591# ifdef NDEBUG
592 constexpr long long kBudgetMs = 12000;
593# else
594 constexpr long long kBudgetMs = 25000;
595# endif
596
597 std::mt19937 rng(0x1ca2026u);
599
600 Graph g;
601 const auto nodes = build_graph_with_unit_arcs(g, n, edges);
602
603 std::uniform_int_distribution<size_t> root_pick(0, n - 1);
604 const size_t root = root_pick(rng);
605
606 const auto t_start = Clock::now();
609 const auto t_after_build = Clock::now();
610
611 // Keep an independent sanity check without impacting timed query loop.
612 Naive_Tree_Oracle oracle(n, edges, root);
613 std::uniform_int_distribution<size_t> sanity_pick(0, n - 1);
614 for (size_t i = 0; i < 64; ++i)
615 {
616 const size_t u = sanity_pick(rng);
617 const size_t v = sanity_pick(rng);
618 const size_t expected_lca = oracle.lca(u, v);
619 const size_t expected_dist = oracle.distance(u, v);
620
621 ASSERT_EQ(static_cast<size_t>(bl.lca(nodes(u), nodes(v))->get_info()),
622 expected_lca);
623 ASSERT_EQ(static_cast<size_t>(er.lca(nodes(u), nodes(v))->get_info()),
624 expected_lca);
625 ASSERT_EQ(bl.distance(nodes(u), nodes(v)), expected_dist);
626 ASSERT_EQ(er.distance(nodes(u), nodes(v)), expected_dist);
627 }
628
629 // Reuse the same node-picking pattern as RandomTreesAgainstNaiveOracle.
630 std::uniform_int_distribution<size_t> node_pick(0, n - 1);
631 size_t checksum = 0;
632 for (size_t q = 0; q < query_count; ++q)
633 {
634 const size_t u = node_pick(rng);
635 const size_t v = node_pick(rng);
636
637 auto * bl_lca = bl.lca(nodes(u), nodes(v));
638 auto * er_lca = er.lca(nodes(u), nodes(v));
640
641 const size_t d1 = bl.distance(nodes(u), nodes(v));
642 const size_t d2 = er.distance(nodes(u), nodes(v));
643 ASSERT_EQ(d1, d2);
644
645 checksum ^= (static_cast<size_t>(bl_lca->get_info()) + 0x9e3779b9u);
646 checksum ^= (d1 + (q << 1));
647 }
648
649 const auto t_end = Clock::now();
650
651 const auto build_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
652 t_after_build - t_start).count();
653 const auto query_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
654 t_end - t_after_build).count();
655 const auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
656 t_end - t_start).count();
657
658 ASSERT_NE(checksum, 0u);
659 ASSERT_LT(elapsed_ms, kBudgetMs)
660 << "Perf regression: n=" << n
661 << ", queries=" << query_count
662 << ", build_ms=" << build_ms
663 << ", query_ms=" << query_ms
664 << ", elapsed_ms=" << elapsed_ms
665 << ", budget_ms=" << kBudgetMs;
666}
Lowest Common Ancestor (LCA) on rooted trees represented as Aleph graphs.
#define ah_runtime_error_if(C)
Throws std::runtime_error if condition holds.
Definition ah-errors.H:266
TYPED_TEST_SUITE(AStarHeapTest, HeapTypes)
WeightedDigraph::Node Node
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
constexpr bool is_empty() const noexcept
Checks if the container is empty.
Definition tpl_array.H:348
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 singly linked list with functional programming support.
Definition htlist.H:1155
void next_ne() noexcept
Advances the iterator to the next filtered element (noexcept version).
LCA via binary lifting on a rooted tree.
Definition LCA.H:440
LCA via Euler tour + RMQ on depth in a rooted tree.
Definition LCA.H:692
Arc for graphs implemented with simple adjacency lists.
Definition tpl_sgraph.H:197
Graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:428
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:524
Node Node
The graph type.
Definition tpl_graph.H:432
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
Filtered iterator on the nodes of a graph.
Definition tpl_graph.H:1206
static mt19937 rng
std::chrono::steady_clock Clock
__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
DynArray< Graph::Node * > nodes
Definition graphpic.C:406
Singly linked list implementations with head-tail access.
TYPED_TEST(LcaTypedTest, EmptyTree)
Definition lca_test.cc:233
DFSResult< typename Domain::Distance > dfs(Domain &domain, typename Domain::State &state, SearchPath< typename Domain::Move > &path, const typename Domain::Distance g, const typename Domain::Distance threshold, const size_t depth, IDAStarResult< Solution, typename Domain::Distance > &result, OnSolution &on_solution)
Core recursive DFS used by IDA* for a single threshold pass.
Aleph::Array< typename GT::Node * > build_graph_with_unit_arcs(GT &g, const size_t n, const std::vector< std::pair< size_t, size_t > > &edges)
EdgeContainer make_random_tree_edges(const size_t n, std::mt19937 &rng)
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
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.
bool none(const Container &container, Operation &operation)
Return true if no element satisfies operation.
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
bool check(GT &g)
static int * k
Array-based graph implementation.
Dynamic array container with automatic resizing.
Generic graph and digraph implementations.
Simple graph implementation with adjacency lists.