Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
Tarjan.H
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
91#ifndef TARJAN_H
92#define TARJAN_H
93
94# include <ah-graph-concepts.H>
95
96#include <tpl_dynListStack.H>
97#include <tpl_dynSetTree.H>
98#include <htlist.H>
99#include <tpl_graph_utils.H>
100#include <tpl_find_path.H>
101#include <ah-errors.H>
102
103namespace Aleph {
167template <AlephGraph GT, template <typename, class> class Itor = Out_Iterator, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
169{
170 SA sa_;
171
172 GT *g_ptr_ = nullptr;
173
175
176 long df_count_ = 0;
177 mutable size_t n_ = 0; // number of nodes in the graph
178
179 Path<GT> *path_ptr_ = nullptr;
180
181public:
184
186
189
191
198 { /* empty */
199 }
200
201private:
207 {
208 void operator () (const GT &g, typename GT::Node *p) const noexcept
209 {
210 g.reset_bits(p);
211 g.reset_counter(p); // initialize df
212 low<GT>(p) = -1; // initialize low
213 }
214 };
215
220 static bool is_node_in_stack(typename GT::Node *p) noexcept
221 {
222 assert(p != nullptr);
223 return IS_NODE_VISITED(p, Aleph::Min);
224 }
225
234 {
236
237 stack_.push(p);
238 NODE_BITS(p).set_bit(Aleph::Min, true);
239 NODE_BITS(p).set_bit(Aleph::Depth_First, true);
240 df<GT>(p) = low<GT>(p) = df_count_++;
241 }
242
247 {
248 auto ret = stack_.pop();
249 NODE_BITS(ret).set_bit(Aleph::Min, false);
250
251 return ret;
252 }
253
263 {
265
266 // depth-first traverse all nodes connected to v
267 for (Itor<GT, SA> it(v, sa_); it.has_curr(); it.next_ne())
268 if (auto w = g_ptr_->get_tgt_node(it.get_curr()); not IS_NODE_VISITED(w, Aleph::Depth_First))
269 {
270 // map_nodes() called inside scc_by_blocks corrupts low<GT>(w)
271 // via NODE_COOKIE when w's SCC is finalized. Save the result
272 // before that corruption can propagate to v.
273 const long w_low = scc_by_blocks(w, blk_list);
274 low<GT>(v) = std::min(low<GT>(v), w_low);
275 }
276 else if (is_node_in_stack(w))
277 // if on stack ==> v was visited before w
278 low<GT>(v) = std::min(low<GT>(v), df<GT>(w));
279
280 // Save low[v] before the SCC-finalization loop overwrites NODE_COOKIE
281 // (via map_nodes) and NODE_COUNTER (with blk_idx) on every node in v's SCC.
282 const long result = low<GT>(v);
283
284 if (low<GT>(v) == df<GT>(v)) // first visited node of the block?
285 { // yes ==> pop block nodes from stack
286 const size_t blk_idx = blk_list.size(); // capture by value, not reference
287 GT &blk = blk_list.append(GT());
288
289 while (true) // remove block from stack until v is removed
290 {
291 auto p = pop_from_stack();
292 auto q = blk.insert_node(p->get_info());
293 *q = *p; // copy node content
294 NODE_COOKIE(p) = NODE_COOKIE(q) = nullptr;
295 GT::map_nodes(p, q);
296 NODE_COUNTER(p) = NODE_COUNTER(q) = static_cast<long>(blk_idx);
297 if (p == v)
298 break;
299 }
300 }
301 return result;
302 }
303
313 {
315
316 // depth traversal all nodes connected to v
317 for (Itor<GT, SA> it(v, sa_); it.has_curr(); it.next_ne())
318 if (auto w = g_ptr_->get_tgt_node(it.get_curr()); not IS_NODE_VISITED(w, Aleph::Depth_First))
319 {
321 low<GT>(v) = std::min(low<GT>(v), low<GT>(w));
322 }
323 else if (is_node_in_stack(w))
324 // if on stack ==> v was visited before w
325 low<GT>(v) = std::min(low<GT>(v), df<GT>(w));
326
327 if (low<GT>(v) == df<GT>(v)) // first visited node of the block?
328 { // yes pop out block nodes that are on stack
330 while (true) // remove block from stack until reaching v
331 {
332 auto p = pop_from_stack();
333 l.append(p);
334 if (p == v)
335 break;
336 }
337 }
338 }
339
348 void scc_by_len(typename GT::Node *v, DynList<size_t> &sizes)
349 {
351
352 // depth traverse all nodes connected to v
353 for (Itor<GT, SA> it(v, sa_); it.has_curr(); it.next_ne())
354 if (auto w = g_ptr_->get_tgt_node(it.get_curr()); not IS_NODE_VISITED(w, Aleph::Depth_First))
355 {
356 scc_by_len(w, sizes);
357 low<GT>(v) = std::min(low<GT>(v), low<GT>(w));
358 }
359 else if (is_node_in_stack(w))
360 // if on stack ==> v was visited before w
361 low<GT>(v) = std::min(low<GT>(v), df<GT>(w));
362
363 if (low<GT>(v) == df<GT>(v)) // first visited node of the block?
364 { // yes, pop out block nodes that are on the stack
365 size_t count = 0;
366 while (true) // remove block from the stack until reaching v
367 {
368 auto p = pop_from_stack();
369 ++count;
370
371 if (p == v)
372 break;
373 }
374 sizes.append(count);
375 }
376 }
377
389 void init_tarjan(const GT &g)
390 {
391 Operate_On_Nodes<GT, Init_Tarjan_Node>()(g); // initialize bits, df and low
392 df_count_ = 0; // visitor counter
393 stack_.empty();
394 n_ = g.get_num_nodes();
395
396 g_ptr_ = &const_cast<GT &>(g);
397 }
398
407 bool has_cycle(typename GT::Node *v)
408 {
410
411 // depth traverse all nodes connected to v
412 for (Itor<GT, SA> it(v, sa_); it.has_curr(); it.next_ne())
413 {
414 auto w = g_ptr_->get_tgt_node(it.get_curr());
415
416 // Check for self-loop (a cycle of length 1)
417 if (w == v)
418 return true;
419
421 {
422 if (has_cycle(w))
423 return true;
424
425 low<GT>(v) = std::min(low<GT>(v), low<GT>(w));
426 }
427 else if (is_node_in_stack(w))
428 // if on stack ==> v was visited before w
429 low<GT>(v) = std::min(low<GT>(v), df<GT>(w));
430 }
431
432 if (low<GT>(v) == df<GT>(v)) // first visited node of block?
433 { // yes, check if component has two or more nodes
434 size_t count = 0;
435 while (true)
436 {
437 ++count;
438 if (pop_from_stack() == v)
439 break;
440 }
441
442 return count >= 2; // if count >= 2 ==> there is a cycle
443 }
444
445 return false; // everything was covered without finding a cycle
446 }
447
457 {
458 // Search for a cycle in the block
459 auto a = block.get_first_arc();
460 auto start = block.get_tgt_node(a);
461 auto end = block.get_src_node(a);
462 assert(start != end);
463
464 auto aux_path = Directed_Find_Path<GT, Itor, SA>(block, sa_).dfs(start, end);
465 assert(not aux_path.is_empty()); // since it's connected it must be found
466
467 // aux_path is about the mapped block. We need to translate it back
468 // to the original graph using the mapping table.
469 path_ptr_->empty();
470 for (typename Path<GT>::Iterator i(aux_path); i.has_curr(); i.next_ne())
471 path_ptr_->append_directed(table.find(i.get_current_node_ne()));
472
473 path_ptr_->append_directed(path_ptr_->get_first_node());
474 }
475
483 bool build_cycle(typename GT::Node *v)
484 {
486
487 // depth traverse all nodes connected to v
488 for (Itor<GT, SA> it(v, sa_); it.has_curr(); it.next_ne())
489 {
490 auto w = g_ptr_->get_tgt_node(it.get_curr());
491
492 // Check for self-loop (a cycle of length 1)
493 if (w == v)
494 {
495 // Build a simple self-loop path: v -> v
496 path_ptr_->empty();
497 path_ptr_->init(v);
498 path_ptr_->append_directed(v);
499 return true;
500 }
501
503 {
504 if (build_cycle(w))
505 return true;
506
507 low<GT>(v) = std::min(low<GT>(v), low<GT>(w));
508 }
509 else if (is_node_in_stack(w))
510 // if on stack ==> v was visited before w
511 low<GT>(v) = std::min(low<GT>(v), df<GT>(w));
512 }
513
514 if (low<GT>(v) == df<GT>(v)) // first visited node of the block?
515 {
516 GT blk; // auxiliary graph
517
518 // g node mapping to blk (cookies are busy)
520
521 // pop nodes from stack and insert them into auxiliary block
522 while (true) // pop the component and insert into blk
523 {
524 auto p = pop_from_stack();
525 auto q = blk.insert_node();
526 *q = *p; // copy node content
527 table.insert(q, p);
528 table.insert(p, q);
529 if (p == v)
530 break;
531 }
532
533 if (blk.get_num_nodes() == 1)
534 return false; // single node without self-loop ==> no cycle
535
536 // finish constructing the block with the arcs
537 for (typename GT::Node_Iterator j(blk); j.has_curr(); j.next_ne())
538 {
539 auto bsrc = j.get_curr();
540 auto gsrc = table.find(bsrc);
541
542 // traverse the arcs of gsrc
543 for (Itor<GT, SA> k(gsrc, sa_); k.has_curr(); k.next_ne())
544 {
545 auto ga = k.get_curr();
546 auto gtgt = g_ptr_->get_tgt_node(ga);
547 auto ptr = table.search(gtgt);
548 if (ptr == nullptr) // arc of the block?
549 continue;
550
551 auto ta = blk.insert_arc(bsrc, ptr->second);
552 *ta = *ga; // copy arc content
553 }
554 }
555
556 build_path(blk, table);
557
558 return true;
559 }
560
561 assert(path_ptr_->is_empty());
562
563 return false;
564 }
565
574 bool is_connected(typename GT::Node *v)
575 {
577
578 // depth-first traverse all nodes connected to v
579 for (Itor<GT, SA> it(v, sa_); it.has_curr(); it.next_ne())
580 {
581 if (auto w = g_ptr_->get_tgt_node(it.get_curr()); not IS_NODE_VISITED(w, Aleph::Depth_First))
582 {
583 if (not is_connected(w))
584 return false;
585
586 low<GT>(v) = std::min(low<GT>(v), low<GT>(w));
587 }
588 else if (is_node_in_stack(w))
589 low<GT>(v) = std::min(low<GT>(v), df<GT>(w));
590 }
591
592 if (low<GT>(v) == df<GT>(v)) // first visited node of the block?
593 { // pop nodes from stack until v is found
594 while (pop_from_stack() != v)
595 ;
596
597 return stack_.is_empty();
598 }
599
600 return true;
601 }
602
603public:
623 {
624 init_tarjan(g);
625
626 for (typename GT::Node_Iterator it(g); df_count_ < n_; it.next_ne())
627 if (auto v = it.get_curr(); not IS_NODE_VISITED(v, Aleph::Depth_First))
629
631
632 // traverse each partial subgraph and add its arcs
633 for (typename DynList<GT>::Iterator i(blk_list); i.has_curr(); i.next_ne())
634 { // traverse all nodes of the block
635 GT &blk = i.get_curr();
636 for (typename GT::Node_Iterator j(blk); j.has_curr(); j.next_ne())
637 {
638 auto bsrc = j.get_curr();
639 auto gsrc = mapped_node<GT>(bsrc);
640
641 // traverse arcs of gsrc
642 for (Itor<GT, SA> k(gsrc, sa_); k.has_curr(); k.next_ne())
643 {
644 auto ga = k.get_curr();
645 auto gtgt = g_ptr_->get_tgt_node(ga);
647 { // inter-block arc ==> add it to arc_list
648 arc_list.append(ga);
649 continue;
650 }
651
652 // insert and map the arc in the sub-block
653 auto btgt = mapped_node<GT>(gtgt);
654 auto ba = blk.insert_arc(bsrc, btgt);
655 *ba = *ga; // copy arc content
657 }
658 }
659 }
660 }
661
685 {
686 init_tarjan(g);
687 for (typename GT::Node_Iterator it(g); df_count_ < n_; it.next_ne())
688 if (auto v = it.get_curr(); not IS_NODE_VISITED(v, Aleph::Depth_First))
689 scc_by_lists(v, blks);
690 }
691
698
710 {
711 DynList<size_t> sizes;
712 connected_components(g, sizes);
713 return sizes.size();
714 }
715
730 {
731 init_tarjan(g);
732 for (typename GT::Node_Iterator it(g); df_count_ < n_; it.next_ne())
733 if (auto v = it.get_curr(); not IS_NODE_VISITED(v, Aleph::Depth_First))
734 scc_by_len(v, blks);
735 }
736
747 {
748 connected_components(g, blk_list, arc_list);
749 }
750
762
767
778 {
782
783 for (typename DynList<GT>::Iterator it(blist); it.has_curr(); it.next_ne())
784 {
785 GT &curr = it.get_curr();
786 GT &block = blk_list.append(GT());
787 curr.swap(block);
788 }
789
790 for (typename DynList<typename GT::Arc *>::Iterator it(alist); it.has_curr(); it.next_ne())
791 arc_list.append(it.get_curr());
792 }
793
803 {
806
807 for (typename DynList<DynList<typename GT::Node *>>::Iterator it(b); it.has_curr(); it.next_ne())
808 {
810
811 auto &blk = it.get_curr();
812 while (not blk.is_empty())
813 tgt_list.append(blk.remove_first());
814 }
815 }
816
828 [[nodiscard]] bool has_cycle(const GT &g)
829 {
830 init_tarjan(g);
831 for (typename GT::Node_Iterator it(g); df_count_ < n_; it.next_ne())
832 if (auto v = it.get_curr(); not IS_NODE_VISITED(v, Aleph::Depth_First))
833 if (has_cycle(v))
834 return true;
835
836 return false;
837 }
838
849 [[nodiscard]] bool is_dag(const GT &g)
850 {
851 return not has_cycle(g);
852 }
853
867 bool compute_cycle(const GT &g, Path<GT> &path)
868 {
869 init_tarjan(g);
870 path_ptr_ = &path;
872
873 for (typename GT::Node_Iterator it(g); df_count_ < n_; it.next_ne())
874 if (auto v = it.get_curr(); not IS_NODE_VISITED(v, Aleph::Depth_First)) // p visited?
875 if (build_cycle(v))
876 return true;
877
878 path.empty();
879 return false;
880 }
881
896 [[nodiscard]] bool compute_cycle(const GT &g, typename GT::Node *src, Path<GT> &path)
897 {
898 ah_domain_error_if(src == nullptr) << "compute_cycle: source node cannot be null";
899
900 init_tarjan(g);
901 path_ptr_ = &path;
903 return build_cycle(src);
904 }
905
917 [[nodiscard]] bool test_connectivity(const GT &g)
918 {
919 init_tarjan(g);
920
921 // In a strongly connected graph, a single DFS from any node should reach
922 // all nodes. If we have to start from a second unvisited node, it means
923 // the graph has multiple disconnected components.
924 bool started = false;
925 for (typename GT::Node_Iterator it(g); df_count_ < n_; it.next_ne())
926 if (auto v = it.get_curr(); not IS_NODE_VISITED(v, Aleph::Depth_First))
927 {
928 if (started) // Second DFS root → not strongly connected
929 return false;
930 started = true;
931 if (not is_connected(v))
932 return false;
933 }
934
936
937 return true;
938 }
939
942
947 {
948 return sa_;
949 }
950
955 {
956 return sa_;
957 }
958
963 {
964 return g_ptr_ != nullptr;
965 }
966
971 {
972 return g_ptr_;
973 }
974
976};
977
998template <AlephGraph GT, template <typename, class> class Itor = Out_Iterator, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
1000{
1002
1003public:
1010 { /* empty */
1011 }
1012
1021 [[nodiscard]] bool operator () (const GT &g, Path<GT> &path) const
1022 {
1024
1025 return tarjan.compute_cycle(g, path);
1026 }
1027
1034 [[nodiscard]] Path<GT> operator () (const GT &g) const
1035 {
1036 Path<GT> ret(g);
1038 return ret;
1039 }
1040
1049 [[nodiscard]] Path<GT> operator () (const GT &g, typename GT::Node *src) const
1050 {
1051 Path<GT> ret(g);
1053 return ret;
1054 }
1055};
1056} // end namespace Aleph
1057
1058#endif // TARJAN_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:527
C++20 concepts for the protocol shared by graph algorithms.
List_Graph< Graph_Node< Node_Info >, Graph_Arc< Arc_Info > > GT
long double w
Definition btreepic.C:153
Determines if a digraph contains a cycle and constructs it.
Definition Tarjan.H:1000
bool operator()(const GT &g, Path< GT > &path) const
Invokes the computation of a cycle in a digraph.
Definition Tarjan.H:1021
Compute_Cycle_In_Digraph(SA __sa=SA())
Constructs a cycle computation instance with an arc filter.
Definition Tarjan.H:1009
Dynamic doubly linked list with O(1) size and bidirectional access.
T & append(const T &item)
Append a copied item at the end of the list.
Dynamic stack of elements of generic type T based on a singly linked list.
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.
void empty() noexcept
Remove all elements from the stack.
Iterator on the items of list.
Definition htlist.H:1420
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
Dynamic map implemented with an AVL tree.
Pair * search(const Key &key) const noexcept
Collect all keys.
Pair * insert(const Key &key, const Data &data)
Insert a key-value pair.
Data & find(const Key &key)
Find the value associated with key.
bool has_curr() const noexcept
Definition htlist.H:930
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1065
void swap(List_Graph &g) noexcept
Swap in constant time this with g
Definition tpl_graph.H:984
Filtered iterator for outcoming arcs of a node.
Definition tpl_graph.H:1831
Iterator on nodes and arcs of a path.
Definition tpl_graph.H:3311
Path on a graph.
Definition tpl_graph.H:2772
void empty()
Clean the path: all the nodes and arc are removed.
Definition tpl_graph.H:2922
void set_graph(const GT &__g, Node *start_node=nullptr)
Set the graph of the path.
Definition tpl_graph.H:2900
Computes strongly connected components (SCCs) in a directed graph using Tarjan's algorithm.
Definition Tarjan.H:169
void init_tarjan(const GT &g)
Initialize internal state for a Tarjan traversal.
Definition Tarjan.H:389
bool has_computation() const noexcept
Check if a computation has been performed.
Definition Tarjan.H:962
SA & get_filter() noexcept
Returns the arc filter used by this instance.
Definition Tarjan.H:946
DynList< DynList< typename GT::Node * > > connected_components(const GT &g)
Definition Tarjan.H:692
Tarjan_Connected_Components(const Tarjan_Connected_Components &)=delete
Tarjan instances should not be copied (they hold internal traversal state)
void init_node_and_push_in_stack(typename GT::Node *p)
Initialize a node and push it onto the traversal stack.
Definition Tarjan.H:233
bool build_cycle(typename GT::Node *v)
Recursive DFS to find and construct a cycle starting from v.
Definition Tarjan.H:483
Tarjan_Connected_Components & operator=(const Tarjan_Connected_Components &)=delete
void connected_components(const GT &g, DynList< DynList< typename GT::Node * > > &blks)
Computes the strongly connected components (SCCs) of a digraph.
Definition Tarjan.H:684
bool test_connectivity(const GT &g)
Tests whether the digraph is strongly connected.
Definition Tarjan.H:917
bool has_cycle(typename GT::Node *v)
Recursive DFS to detect if a cycle exists starting from v.
Definition Tarjan.H:407
void connected_components(const GT &g, DynList< GT > &blk_list, DynList< typename GT::Arc * > &arc_list)
Computes the strongly connected components (SCCs) of a digraph.
Definition Tarjan.H:622
bool compute_cycle(const GT &g, typename GT::Node *src, Path< GT > &path)
Finds and constructs a cycle starting from a specific node, if one exists.
Definition Tarjan.H:896
long scc_by_blocks(typename GT::Node *v, DynList< GT > &blk_list)
Recursive DFS to find SCCs and build mapped subgraphs.
Definition Tarjan.H:262
void scc_by_lists(typename GT::Node *v, DynList< DynList< typename GT::Node * > > &blks)
Recursive DFS to find SCCs and collect nodes into lists.
Definition Tarjan.H:312
bool compute_cycle(const GT &g, Path< GT > &path)
Finds and constructs a cycle in the digraph, if one exists.
Definition Tarjan.H:867
void build_path(const GT &block, DynMapAvlTree< typename GT::Node *, typename GT::Node * > &table)
Build a cycle path from a strongly connected block.
Definition Tarjan.H:456
GT * get_graph() const noexcept
Get the graph of the last computation.
Definition Tarjan.H:970
const SA & get_filter() const noexcept
Returns the arc filter used by this instance (const version).
Definition Tarjan.H:954
bool has_cycle(const GT &g)
Determines whether the digraph contains at least one cycle.
Definition Tarjan.H:828
Tarjan_Connected_Components(Tarjan_Connected_Components &&)=default
Move is allowed.
bool is_dag(const GT &g)
Determines whether the directed graph is acyclic (a DAG).
Definition Tarjan.H:849
Tarjan_Connected_Components(SA __sa=SA()) noexcept
Constructs a Tarjan algorithm instance for computing strongly connected components.
Definition Tarjan.H:197
void scc_by_len(typename GT::Node *v, DynList< size_t > &sizes)
Recursive DFS to find SCCs and count their sizes.
Definition Tarjan.H:348
DynListStack< typename GT::Node * > stack_
Definition Tarjan.H:174
GT::Node * pop_from_stack()
Pop a node from the traversal stack.
Definition Tarjan.H:246
static bool is_node_in_stack(typename GT::Node *p) noexcept
Check if a node is currently on the traversal stack.
Definition Tarjan.H:220
void connected_components(const GT &g, DynList< size_t > &blks)
Computes the sizes of the strongly connected components (SCCs).
Definition Tarjan.H:729
void operator()(const GT &g, DynList< GT > &blk_list, DynList< typename GT::Arc * > &arc_list)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition Tarjan.H:746
bool is_connected(typename GT::Node *v)
Recursive DFS to test if the graph is strongly connected.
Definition Tarjan.H:574
size_t num_connected_components(const GT &g)
Returns the number of strongly connected components in the graph.
Definition Tarjan.H:709
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:737
static void map_arcs(A1 *p, A2 *q) noexcept
Map the arcs through their cookies.
Definition graph-dry.H:1074
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:785
static void map_nodes(N1 *p, N2 *q) noexcept
Map the nodes through their cookies.
Definition graph-dry.H:1043
#define NODE_COUNTER(p)
Get the counter of a node.
#define IS_NODE_VISITED(p, bit)
Determine whether the control bit is set or not to one.
#define NODE_COOKIE(p)
Return the node cookie
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
#define NODE_BITS(p)
Get the control bits of a node.
@ Depth_First
Definition aleph-graph.H:73
Singly linked list implementations with head-tail access.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
STL namespace.
Default filter for filtered iterators on arcs.
Definition tpl_graph.H:1001
Functor to initialize node metadata for Tarjan traversal.
Definition Tarjan.H:207
void operator()(const GT &g, typename GT::Node *p) const noexcept
Definition Tarjan.H:208
static int * k
Dynamic stack implementation based on linked lists.
Dynamic set implementations based on balanced binary search trees.
Path finding algorithms in graphs.
Utility algorithms and operations for graphs.
DynList< int > l