Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
graph-traverse.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
32
43# ifndef GRAPH_TRAVERSE_H
44# define GRAPH_TRAVERSE_H
45
46# include <ah-graph-concepts.H>
47
48# include <tuple>
49# include <cassert>
50# include <tpl_agraph.H>
51# include <tpl_dynListStack.H>
52# include <tpl_dynListQueue.H>
53
54namespace // local constants to avoid collisions with aleph-graph.H
55{
56 constexpr unsigned char GT_Unprocessed = 0;
57 constexpr unsigned char GT_Processing = 1;
58 constexpr unsigned char GT_Processed = 2;
59}
60
82template <AlephGraph GT, class Itor,
83 template <typename T> class Q = DynListStack,
86{
87 GT & g;
89
106 static bool seed_arc(typename GT::Arc *a, typename GT::Node *tgt) noexcept
107 {
108 if (tgt->state() != GT_Unprocessed)
109 {
110 a->set_state(GT_Processed);
111 return false;
112 }
113 a->set_state(GT_Processing);
114 tgt->set_state(GT_Processing);
115 return true;
116 }
117
118public:
121
129 template <class Node_Op>
130 size_t operator ()(typename GT::Node *start, Node_Op & op)
131 {
132 assert(start != nullptr);
133 g.reset_nodes();
134 g.reset_arcs();
135
136 size_t count = 1;
137 start->set_state(GT_Processed);
138 if (not op(start))
139 return count;
140
142 for (Itor it(start, sa); it.has_curr(); it.next_ne())
143 {
144 typename GT::Arc *a = it.get_curr();
145 typename GT::Node *tgt = g.get_connected_node(a, start);
146 if (seed_arc(a, tgt))
147 q.put(a);
148 }
149
150 const size_t n = g.vsize();
151 while (not q.is_empty() and count < n)
152 {
153 typename GT::Arc *arc = q.get();
154 assert(arc->state() == GT_Processing);
156
157 typename GT::Node *s = g.get_src_node(arc);
158 typename GT::Node *t = g.get_tgt_node(arc);
159 if (s->state() == GT_Processed and t->state() == GT_Processed)
160 continue;
161
162 typename GT::Node *curr = s->state() == GT_Processed ? t : s;
163 assert(curr->state() == GT_Processing);
164 ++count;
165 curr->set_state(GT_Processed);
166 if (not op(curr))
167 return count;
168
169 for (Itor it(curr, sa); it.has_curr(); it.next_ne())
170 {
171 typename GT::Arc *a = it.get_curr();
172 if (a->state() != GT_Unprocessed)
173 continue;
174 typename GT::Node *tgt = g.get_connected_node(a, curr);
175 if (seed_arc(a, tgt))
176 q.put(a);
177 }
178 }
179
180 return count;
181 }
182
184 template <class Node_Op>
185 size_t operator ()(typename GT::Node *start, Node_Op && op = Node_Op())
186 {
187 return (*this)(start, op);
188 }
189
199 template <class Op>
200 size_t exec(typename GT::Node *start, Op & op)
201 {
202 assert(start != nullptr);
203 g.reset_nodes();
204 g.reset_arcs();
205
206 size_t count = 1;
207 start->set_state(GT_Processed);
208 if (not op(start, nullptr))
209 return count;
210
211 using Pair = std::tuple<typename GT::Node *, typename GT::Arc *>;
212 Q<Pair> q;
213 for (Itor it(start, sa); it.has_curr(); it.next_ne())
214 {
215 typename GT::Arc *a = it.get_curr();
216 typename GT::Node *tgt = g.get_connected_node(a, start);
217 if (seed_arc(a, tgt))
218 q.put(std::make_tuple(start, a));
219 }
220
221 const size_t n = g.vsize();
222 while (not q.is_empty() and count < n)
223 {
224 const Pair p = q.get();
225 typename GT::Arc *arc = get<1>(p);
226 assert(arc->state() == GT_Processing);
227 assert(get<0>(p)->state() == GT_Processed);
229
230 typename GT::Node *curr = g.get_connected_node(arc, get<0>(p));
231 assert(curr->state() == GT_Processing);
232 ++count;
233 curr->set_state(GT_Processed);
234 if (not op(curr, arc))
235 return count;
236
237 for (Itor it(curr, sa); it.has_curr(); it.next_ne())
238 {
239 typename GT::Arc *a = it.get_curr();
240 if (a->state() != GT_Unprocessed)
241 continue;
242 typename GT::Node *tgt = g.get_connected_node(a, curr);
243 if (seed_arc(a, tgt))
244 q.put(std::make_tuple(curr, a));
245 }
246 }
247
248 return count;
249 }
250
252 template <class Operation>
253 size_t exec(typename GT::Node *start, Operation && op = Operation())
254 {
255 return exec(start, op);
256 }
257
265 template <class Node_Op, class Arc_Op>
266 std::tuple<size_t, size_t> operator ()(typename GT::Node *start,
267 Node_Op & node_op, Arc_Op & arc_op)
268 {
269 assert(start != nullptr);
270 g.reset_nodes();
271 g.reset_arcs();
273
274 size_t node_count = 1;
275 size_t arc_count = 0;
276
277 start->set_state(GT_Processed);
278 if (not node_op(start))
279 return std::make_tuple(1, 0);
280
281 for (Itor it(start, sa); it.has_curr(); it.next_ne())
282 {
283 typename GT::Arc *a = it.get_curr();
284 typename GT::Node *tgt = g.get_connected_node(a, start);
285 // Deliberately NOT the shared seed_arc() helper: this overload
286 // reports "back edges" too (arcs into an already-Processing node
287 // discovered via another arc), which is why it tests
288 // `!= GT_Processed` instead of `== GT_Unprocessed` — a `Processing`
289 // tgt still enqueues `a` and calls arc_op(a) here, unlike the
290 // Unprocessed-only seed_arc() used by the other two overloads. See
291 // DualOpVisitsNodesAndArcs. This still guards the self-loop case
292 // (tgt == start is already Processed by this point).
293 if (tgt->state() != GT_Processed)
294 {
297 q.put(a);
298 ++arc_count;
299 if (not arc_op(a))
300 return std::make_tuple(node_count, arc_count);
301 }
302 else
304 }
305
306 while (not q.is_empty())
307 {
308 typename GT::Arc *arc = q.get();
309 assert(arc->state() == GT_Processing);
311
312 typename GT::Node *s = g.get_src_node(arc);
313 typename GT::Node *t = g.get_tgt_node(arc);
314 if (s->state() == GT_Processed and t->state() == GT_Processed)
315 continue;
316
317 typename GT::Node *curr = s->state() == GT_Processed ? t : s;
318 assert(curr->state() == GT_Processing);
319 ++node_count;
320 curr->set_state(GT_Processed);
321 if (not node_op(curr))
322 return std::make_tuple(node_count, arc_count);
323
324 for (Itor it(curr, sa); it.has_curr(); it.next_ne())
325 {
326 typename GT::Arc *a = it.get_curr();
327 if (a->state() != GT_Unprocessed)
328 continue;
329 typename GT::Node *tgt = g.get_connected_node(a, curr);
330 if (tgt->state() != GT_Processed)
331 {
332 q.put(a);
335 ++arc_count;
336 if (not arc_op(a))
337 return std::make_tuple(node_count, arc_count);
338 }
339 else
341 }
342 }
343
344 return std::make_tuple(node_count, arc_count);
345 }
346
348 template <class Node_Op, class Arc_Op>
349 std::tuple<size_t, size_t> operator ()(typename GT::Node *start,
350 Node_Op && node_op = Node_Op(),
351 Arc_Op && arc_op = Arc_Op())
352 {
353 return (*this)(start, node_op, arc_op);
354 }
355};
356
357
358template <class GT, class Itor,
361
362template <class GT, class Itor,
365
366
367# endif // GRAPH_TRAVERSE_H
C++20 concepts for the protocol shared by graph algorithms.
List_Graph< Graph_Node< Node_Info >, Graph_Arc< Arc_Info > > GT
Dynamic stack of elements of generic type T based on a singly linked list.
void set_state(unsigned int s) noexcept
Set the state of arc to value s
Definition graph-dry.H:631
unsigned int state() const noexcept
Return the state of arc.
Definition graph-dry.H:628
unsigned int state() const noexcept
Return the state's value.
Definition graph-dry.H:542
void set_state(unsigned int s) noexcept
Set the state to value s
Definition graph-dry.H:545
void reset_arcs() const
Reset all the arcs of graph (the control bits, the state, the counter and the cookie)
Definition graph-dry.H:975
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:779
Node * get_connected_node(Arc *arc, Node *node) const noexcept
Return the adjacent node to node through arc.
Definition graph-dry.H:820
constexpr size_t vsize() const noexcept
Definition graph-dry.H:746
void reset_nodes() const
Reset all the nodes of graph (the control bits, the state, the counter and the cookie)
Definition graph-dry.H:968
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:785
Traverse a graph depth-first or breadth-first and execute a visit function.
static bool seed_arc(typename GT::Arc *a, typename GT::Node *tgt) noexcept
Prepare arc a (leading to tgt) for frontier expansion out of start/curr, and report whether the calle...
size_t operator()(typename GT::Node *start, Node_Op &op)
Traverse the graph starting from start and execute op on each node.
Graph_Traverse(GT &__g, Show_Arc __sa=Show_Arc())
Construct a traverser with a graph and arc filter.
size_t exec(typename GT::Node *start, Operation &&op=Operation())
This is an overloaded member function, provided for convenience. It differs from the above function o...
size_t exec(typename GT::Node *start, Op &op)
Execute operation op(curr, arc) where curr is the visited node and arc is the incoming arc.
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
and
Check uniqueness with explicit hash + equality functors.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
Default filter for filtered iterators on arcs.
Definition tpl_graph.H:1001
Array-based graph implementation.
Dynamic queue implementation based on linked lists.
Dynamic stack implementation based on linked lists.