Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
Zero_One_BFS.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
83# ifndef ZERO_ONE_BFS_H
84# define ZERO_ONE_BFS_H
85
86# include <ah-graph-concepts.H>
87
88# include <limits>
89# include <type_traits>
90# include <tpl_dynDlist.H>
91# include <tpl_graph_utils.H>
92# include <ah-errors.H>
93
94namespace Aleph
95{
96
127template <AlephGraph GT,
129 template <typename, class> class Itor = Node_Arc_Iterator,
132{
133public:
135 using Node = typename GT::Node;
136 using Arc = typename GT::Arc;
137
138private:
139 SA sa;
141 bool painted = false;
142 GT * ptr_g = nullptr;
143 Node * s = nullptr;
144
145 static constexpr Distance_Type Inf =
146 std::numeric_limits<Distance_Type>::max();
147
149 {
153
154 Node_Info() noexcept : dist(Inf), parent(nullptr), parent_arc(nullptr) {}
155 };
156
163
166
167#define ZOB_INFO(p) (static_cast<Node_Info *>(NODE_COOKIE(p)))
168#define ZOB_PNTD(p) (static_cast<Painted_Info *>(NODE_COOKIE(p)))
169#define ZOB_DIST(p) (ZOB_INFO(p)->dist)
170#define ZOB_PARENT(p) (ZOB_INFO(p)->parent)
171#define ZOB_PARENT_ARC(p) (ZOB_INFO(p)->parent_arc)
172
174 {
175 for (auto it = owned_node_infos.get_it(); it.has_curr(); it.next())
176 {
177 auto item = it.get_curr();
178 auto p = item.first;
179 auto info = item.second;
180 if (info != nullptr)
181 delete info;
182 if (NODE_COOKIE(p) == info)
183 NODE_COOKIE(p) = nullptr;
184 }
185 owned_node_infos.empty();
186 }
187
189 {
190 for (auto it = owned_painted_infos.get_it(); it.has_curr(); it.next())
191 {
192 auto item = it.get_curr();
193 auto p = item.first;
194 auto info = item.second;
195 if (info != nullptr)
196 delete info;
197 if (NODE_COOKIE(p) == info)
198 NODE_COOKIE(p) = nullptr;
199 }
200 owned_painted_infos.empty();
201 }
202
204 {
205 painted = false;
206 ptr_g = nullptr;
207 s = nullptr;
208 }
209
212 {
213 Zero_One_BFS * owner = nullptr;
214 const GT * g = nullptr;
215 bool committed = false;
216
217 public:
223 : owner(&__owner), g(&__g)
224 {
225 // empty
226 }
227
236
238 void commit() noexcept { committed = true; }
239
242 {
243 if (not committed)
244 {
247 }
248 }
249 };
250
251 void init(const GT & g)
252 {
253 ptr_g = &const_cast<GT &>(g);
256 for (typename GT::Node_Iterator it(g); it.has_curr(); it.next())
257 {
258 auto p = it.get_curr();
260 NODE_COOKIE(p) = nullptr;
261 }
262 for (typename GT::Arc_Iterator it(g); it.has_curr(); it.next())
263 g.reset_bit(it.get_curr(), Aleph::Spanning_Tree);
264
265 try
266 {
267 for (typename GT::Node_Iterator it(g); it.has_curr(); it.next())
268 {
269 auto p = it.get_curr();
270 auto info = new Node_Info;
271 NODE_COOKIE(p) = info;
272 try
273 {
274 owned_node_infos.append({p, info});
275 }
276 catch (...)
277 {
278 delete info;
279 NODE_COOKIE(p) = nullptr;
280 throw;
281 }
282 }
283 }
284 catch (...)
285 {
288 throw;
289 }
290 }
291
293 {
294 // Two-phase conversion to be exception-safe:
295 // 1. Allocate all Painted_Info objects
296 // 2. Atomically swap and delete old Node_Info
298 try
299 {
300 for (typename GT::Node_Iterator it(*ptr_g); it.has_curr(); it.next())
301 {
302 auto p = it.get_curr();
303 auto info = ZOB_INFO(p);
304 pending.append({p, new Painted_Info{info->parent, info->dist}});
305 }
306 }
307 catch (...)
308 {
309 for (auto it = pending.get_it(); it.has_curr(); it.next())
310 delete it.get_curr().second;
311 throw;
312 }
313
314 // Phase 2: Apply changes
316 for (auto it = pending.get_it(); it.has_curr(); it.next())
317 {
318 auto item = it.get_curr();
319 auto p = item.first;
320 auto pinfo = item.second;
321 NODE_COOKIE(p) = pinfo;
322 }
323 owned_painted_infos.swap(pending);
324 }
325
327 {
328 if (ptr_g == nullptr)
329 return;
330
333
334 for (typename GT::Node_Iterator it(*ptr_g); it.has_curr(); it.next())
335 {
336 auto p = it.get_curr();
338 }
339
340 for (typename GT::Arc_Iterator it(*ptr_g); it.has_curr(); it.next())
341 ptr_g->reset_bit(it.get_curr(), Aleph::Spanning_Tree);
342 }
343
344 void run_bfs(const GT & g, Node * start, Node * end = nullptr)
345 {
346 ZOB_DIST(start) = 0;
347 NODE_BITS(start).set_bit(Aleph::Spanning_Tree, true);
348
350 deque.append(start);
351
352 while (not deque.is_empty())
353 {
354 auto curr = deque.remove_first();
355 auto curr_dist = ZOB_DIST(curr);
356
357 if (end != nullptr and curr == end)
358 break;
359
360 for (Itor<GT, SA> it(curr, sa); it.has_curr(); it.next())
361 {
362 auto arc = it.get_current_arc();
363 auto tgt = g.get_connected_node(arc, curr);
364
365 auto w = distance(arc);
367 << "Zero_One_BFS: arc weight must be 0 or 1, got " << w;
368
369 auto new_dist = curr_dist + w;
370
371 if (new_dist < ZOB_DIST(tgt))
372 {
374 if (prev_parent_arc != nullptr)
376
377 ZOB_DIST(tgt) = new_dist;
378 ZOB_PARENT(tgt) = curr;
379 ZOB_PARENT_ARC(tgt) = arc;
380 NODE_BITS(tgt).set_bit(Aleph::Spanning_Tree, true);
381
382 // Mark the selected parent arc in the spanning tree
383 ARC_BITS(arc).set_bit(Aleph::Spanning_Tree, true);
384
385 if (w == Distance_Type(0))
386 deque.insert(tgt); // push front
387 else
388 deque.append(tgt); // push back
389 }
390 }
391 }
392 }
393
394public:
400 Zero_One_BFS(Distance dist = Distance(), SA __sa = SA())
401 : sa(__sa), distance(dist)
402 {
403 // empty
404 }
405
416
421
426
431
446 void paint_min_paths_tree(const GT & g, Node * start)
447 {
448 ah_domain_error_if(start == nullptr) << "start node cannot be null";
449 ah_domain_error_if(g.get_num_nodes() == 0) << "graph is empty";
450
451 if (ptr_g != nullptr)
453
454 painted = false;
455 s = nullptr;
456
457 init(g);
458 ZOB_Init_Guard guard(*this, g);
459 s = start;
460 run_bfs(g, start);
461 uninit_paint();
462 guard.commit();
463 painted = true;
464 }
465
476 {
477 ah_domain_error_if(not painted) << "Graph has not been painted";
478 ah_domain_error_if(node == nullptr) << "node cannot be null";
479
480 if (node == s)
481 return Distance_Type(0);
482
484 << "node is not reachable from start";
485
486 // O(1) access thanks to Painted_Info
487 auto dist_val = ZOB_PNTD(node)->dist;
488 if (dist_val != Inf)
489 return dist_val;
490
491 // Fallback: Compute distance by walking the path
493 for (auto curr = node; curr != s;)
494 {
495 auto pinfo = ZOB_PNTD(curr);
496 auto parent = pinfo->parent;
497 if (parent == nullptr)
498 break;
499
500 for (Itor<GT, SA> it(parent, sa); it.has_curr(); it.next())
501 {
502 auto arc = it.get_current_arc();
503 auto tgt = ptr_g->get_connected_node(arc, parent);
504 if (tgt == curr and IS_ARC_VISITED(arc, Aleph::Spanning_Tree))
505 {
506 total += distance(arc);
507 break;
508 }
509 }
510 curr = parent;
511 }
512
513 return total;
514 }
515
526 {
527 ah_domain_error_if(not painted) << "Graph has not been painted";
528 ah_domain_error_if(ptr_g == nullptr) << "No computation has been done";
529 ah_domain_error_if(end == nullptr) << "end pointer is null";
530
531 path.empty();
532 if (end == s)
533 {
534 path.set_graph(*ptr_g, s);
535 return 0;
536 }
537
539 return Inf;
540
542 path.set_graph(*ptr_g, s);
544 for (auto curr = end; curr != s;)
545 {
546 auto parent = ZOB_PNTD(curr)->parent;
547 if (parent == nullptr)
548 return Inf;
549
550 bool found = false;
551 for (Itor<GT, SA> it(parent, sa); it.has_curr(); it.next())
552 {
553 auto arc = it.get_current_arc();
554 if (ptr_g->get_connected_node(arc, parent) == curr and
556 {
557 arcs.insert(arc);
558 total += distance(arc);
559 curr = parent;
560 found = true;
561 break;
562 }
563 }
564 if (not found)
565 return Inf;
566 }
567
568 for (auto it = arcs.get_it(); it.has_curr(); it.next())
569 path.append(it.get_curr());
570
571 return total;
572 }
573
591 Distance_Type find_min_path(const GT & g, Node * start, Node * end,
592 Path<GT> & path)
593 {
594 ah_domain_error_if(start == nullptr) << "start node cannot be null";
595 ah_domain_error_if(end == nullptr) << "end node cannot be null";
596 ah_domain_error_if(g.get_num_nodes() == 0) << "graph is empty";
597
598 if (ptr_g != nullptr)
600
601 path.empty();
602
603 painted = false;
604 s = nullptr;
605
606 init(g);
607 ZOB_Init_Guard guard(*this, g);
608 s = start;
609 run_bfs(g, start, end);
610 uninit_paint();
611 guard.commit();
612 painted = true;
613
615 return Inf;
616
617 return get_min_path(end, path);
618 }
619
628 Distance_Type operator()(const GT & g, Node * start, Node * end,
629 Path<GT> & path)
630 {
631 return find_min_path(g, start, end, path);
632 }
633
634#undef ZOB_INFO
635#undef ZOB_PNTD
636#undef ZOB_DIST
637#undef ZOB_PARENT
638#undef ZOB_PARENT_ARC
639};
640
641} // end namespace Aleph
642
643# endif // ZERO_ONE_BFS_H
#define ZOB_INFO(p)
#define ZOB_PARENT_ARC(p)
#define ZOB_PARENT(p)
#define ZOB_DIST(p)
#define ZOB_PNTD(p)
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
Default distance accessor for arc weights.
Dynamic doubly linked list with O(1) size and bidirectional access.
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & insert(const T &item)
Definition htlist.H:1220
T & append(const T &item)
Definition htlist.H:1271
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
void append(Arc *arc)
Append an arc to the path.
Definition tpl_graph.H:2975
RAII guard for Zero_One_BFS initialization and cleanup.
ZOB_Init_Guard(const ZOB_Init_Guard &)=delete
Deleted copy constructor.
void commit() noexcept
Commits the operation, preventing cleanup on destruction.
ZOB_Init_Guard & operator=(const ZOB_Init_Guard &)=delete
Deleted copy assignment.
~ZOB_Init_Guard() noexcept
Destructor.
ZOB_Init_Guard(ZOB_Init_Guard &&)=delete
Deleted move constructor.
ZOB_Init_Guard(Zero_One_BFS &__owner, const GT &__g) noexcept
Constructor.
0-1 BFS algorithm for shortest paths in graphs with 0/1 weights.
void init(const GT &g)
void release_owned_painted_infos() noexcept
~Zero_One_BFS() noexcept
Destructor.
bool is_painted() const noexcept
Check if a computation has been performed.
void release_owned_node_infos() noexcept
static constexpr Distance_Type Inf
GT * get_graph() const noexcept
Get the graph of the last computation.
Distance_Type operator()(const GT &g, Node *start, Node *end, Path< GT > &path)
Computes shortest path (operator interface).
Distance_Type get_min_path(Node *end, Path< GT > &path)
Extracts a shortest path from a previously painted graph.
void run_bfs(const GT &g, Node *start, Node *end=nullptr)
typename Distance::Distance_Type Distance_Type
DynList< std::pair< Node *, Node_Info * > > owned_node_infos
Zero_One_BFS(Distance dist=Distance(), SA __sa=SA())
Constructor.
Distance_Type find_min_path(const GT &g, Node *start, Node *end, Path< GT > &path)
Computes the shortest path from start to end.
typename GT::Node Node
void reset_state_after_failure() noexcept
void paint_min_paths_tree(const GT &g, Node *start)
Paints the shortest paths tree on the graph from start.
Distance_Type get_distance(Node *node)
Gets the accumulated distance to a node after painting.
Node * get_start_node() const noexcept
Get the start node of the last computation.
DynList< std::pair< Node *, Painted_Info * > > owned_painted_infos
typename GT::Arc Arc
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:737
Node * get_connected_node(Arc *arc, Node *node) const noexcept
Return the adjacent node to node through arc.
Definition graph-dry.H:820
void reset_bit(Node *node, int bit) const noexcept
Reset the bit of node (to zero)
Definition graph-dry.H:849
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:228
Definition deque.H:48
DynArray< Graph::Arc * > arcs
Definition graphpic.C:408
#define IS_NODE_VISITED(p, bit)
Determine whether the control bit is set or not to one.
#define ARC_BITS(p)
Return the control bits of arc p.
#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 IS_ARC_VISITED(p, bit)
Determine whether the bit field is or not set to one.
#define NODE_BITS(p)
Get the control bits of a node.
@ Spanning_Tree
Definition aleph-graph.H:79
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
static std::atomic< bool > init
Definition hash-fct.C:54
Default filter for filtered iterators on arcs.
Definition tpl_graph.H:1001
Filtered iterator of adjacent arcs of a node.
Definition tpl_graph.H:1120
Stores parent and distance after painting for O(1) access.
Distance accessor.
Dynamic doubly linked list implementation.
Utility algorithms and operations for graphs.