Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_agraph.H
Go to the documentation of this file.
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
44# ifndef TPL_AGRAPH_H
45# define TPL_AGRAPH_H
46
47# include <tpl_dynSetTree.H>
48# include <array_it.H>
49# include <tpl_sgraph.H>
50# include <ah-errors.H>
51
52namespace Aleph
53{
54 using namespace Aleph;
55
60 template <typename Node_Info = Empty_Class>
62 : public Dlink,
63 public GTNodeCommon<Node_Info>
64 {
66 friend class GTNodeCommon<Node_Info>;
67
68 static constexpr size_t Contract_Factor = 4;
69 static constexpr size_t Default_Cap = 4;
70
71 void init(const size_t dim)
72 {
73 arcs_dim = dim;
74 this->num_arcs = 0;
76 arc_array = nullptr;
77 if (arcs_dim == 0)
78 return;
79
80 arc_array = static_cast<void **>(malloc(arcs_dim * sizeof(void *)));
81 ah_bad_alloc_if(arc_array == nullptr);
82 }
83
84 public:
85 void **arc_array = nullptr;
86 size_t arcs_dim = 0;
88
90 {
91 init(0);
92 }
93
94 Graph_Anode(const Node_Info & info) : Base(info)
95 {
97 }
98
99 Graph_Anode(Node_Info && info) : Base(std::move(info))
100 {
102 }
103
104 Graph_Anode(const Graph_Anode & node) : Dlink(), Base(node.node_info)
105 {
106 init(0);
107 }
108
110 {
111 if (&node == this)
112 return *this;
113 this->node_info = node.node_info;
114 return *this;
115 }
116
118 {
119 init(0);
120 }
121
122 virtual ~Graph_Anode()
123 {
124 if (arc_array != nullptr)
126 }
127
129 {
130 if (new_size == 0)
131 new_size = 1;
132
133 const auto new_array = static_cast<void **>(realloc(arc_array, new_size * sizeof(void *)));
134 ah_bad_alloc_if(new_array == nullptr);
135
139 }
140
141 void * insert_arc(void * arc)
142 {
143 // Defensive: adjacency storage must be consistent before insertion.
144 // If any invariant is broken, reset and reallocate using malloc.
145 // NOTE: Do NOT free arc_array here - if we hit this condition, arc_array
146 // likely contains garbage from uninitialized memory (not a valid allocation).
147 if (arc_array == nullptr or arcs_dim == 0 or this->num_arcs > arcs_dim)
148 {
149 arc_array = static_cast<void **>(malloc(Default_Cap * sizeof(void *)));
150 ah_bad_alloc_if(arc_array == nullptr);
153 this->num_arcs = 0;
154 }
155
156 if (this->num_arcs == arcs_dim)
157 allocate_more(arcs_dim << 1); // 2*arcs_dim
158
159 arc_array[this->num_arcs++] = arc;
160
161 return arc;
162 }
163
164 void remove_arc_ne(const void *arc) noexcept
165 {
166 for (size_t i = 0; i < this->num_arcs; ++i)
167 if (arc_array[i] == arc)
168 {
169 arc_array[i] = arc_array[--(this->num_arcs)];
170 break;
171 }
172
173 if (this->num_arcs > contract_threshold)
174 return;
175
176 // contraction
177 const size_t new_sz = arcs_dim >> 1; // num_arcs/2
178 arc_array = static_cast<void **>(realloc(arc_array, new_sz * sizeof(void *)));
181 }
182
183 void remove_arc(const void *arc)
184 {
185 bool removed = false;
186 for (size_t i = 0; i < this->num_arcs; ++i)
187 if (arc_array[i] == arc)
188 {
189 arc_array[i] = arc_array[--(this->num_arcs)];
190 removed = true;
191 break;
192 }
193
194 ah_domain_error_if(not removed) << "arc for deleting not found";
195
196 if (this->num_arcs > contract_threshold)
197 return;
198
199 // contraction
200 const size_t new_sz = arcs_dim >> 1; // num_arcs/2
201 arc_array = static_cast<void **>(realloc(arc_array, new_sz * sizeof(void *)));
204 }
205
207 {
208 const auto new_array = static_cast<void **>(realloc(arc_array,
209 this->num_arcs * sizeof(void *)));
210 if (new_array == nullptr)
211 return false;
212
213 arc_array = new_array;
214 arcs_dim = this->num_arcs;
215 contract_threshold = this->num_arcs / Contract_Factor;
216
217 return true;
218 }
219 };
220
221
222 template <typename Arc_Info = Empty_Class>
224 : public Dlink,
225 public GTArcCommon<Arc_Info>
226 {
227 friend class GTArcCommon<Arc_Info>;
229
230 public:
231 Graph_Aarc(const Arc_Info & info)
232 : Base(info)
233 {
234 /* empty */
235 }
236
237 Graph_Aarc(Arc_Info && info = Arc_Info())
238 : Base(std::move(info))
239 {
240 /* empty */
241 }
242
244 : Graph_Aarc(arc.arc_info)
245 { /* empty */
246 }
247
249 {
250 if (&arc == this)
251 return *this;
252 this->arc_info = arc.arc_info;
253 return *this;
254 }
255
256 Graph_Aarc(void *src, void *tgt, const Arc_Info & data)
257 : Base(src, tgt, data)
258 {
259 // empty
260 }
261
262 Graph_Aarc(void *src, void *tgt, Arc_Info && data = Arc_Info())
263 : Base(src, tgt, std::move(data))
264 {
265 // empty
266 }
267 };
268
269
270 template <class __Graph_Node = Graph_Anode<unsigned long>,
271 class __Graph_Arc = Graph_Aarc<unsigned long>>
273 : public GraphCommon<Array_Graph<__Graph_Node, __Graph_Arc>,
274 __Graph_Node, __Graph_Arc>
275 {
276 public:
279 using Node_Type = typename Node::Node_Type;
280 using Arc_Type = typename Arc::Arc_Type;
281
284
287
290
291 private:
292 // using DynSetNode = DynSetTree<Node*, Avl_Tree>;
294
297
298 public:
301
304
305 struct Node_Iterator : public GTNodeIterator<Array_Graph>
306 {
308 using Base::Base;
309
311 : Base(const_cast<Dlink &>(g.node_set))
312 {
313 // empty
314 }
315 };
316
324 struct Arc_Iterator : public GTArcIterator<Array_Graph>
325 {
327 using Base::Base;
328
331 {
332 // empty
333 }
334 };
335
336 class Node_Arc_Iterator : public Array_Iterator<void *>
337 {
338 Node *src_node = nullptr;
339
340 public:
342 using Item_Type = Arc *;
343
345 using Set_Type = Node *;
346
349 { /* empty */
350 }
351
355 src->arc_array, src->arcs_dim, src->num_arcs),
356 src_node(src)
357 {
358 // empty
359 }
360
361 Arc * get_curr() const
362 {
363 return static_cast<Arc *>(const_cast<Node_Arc_Iterator *>(this)->
365 }
366
368 {
369 return static_cast<Arc *>(const_cast<Node_Arc_Iterator *>(this)->
371 }
372
375
377 Arc * get_current_arc() const { return get_curr(); }
378
381 {
382 Arc *a = get_curr_ne();
383 return static_cast<Node *>(a->get_connected_node(src_node));
384 }
385
387 {
388 Arc *a = get_curr();
389 return static_cast<Node *>(a->get_connected_node(src_node));
390 }
391 };
392
393 virtual Node * insert_node(Node *p)
394 {
395 assert(p != nullptr);
396 assert(p->num_arcs == 0);
397
398 node_set.append(p);
399 ++this->num_nodes;
400
401 return p;
402 }
403
404 void compress()
405 {
406 for (Node_Iterator it(*this); it.has_curr(); it.next_ne())
407 it.get_curr()->compress();
408 }
409
410 private:
411 Arc * try_insert_arc(Node *src, Node *tgt, void *a)
412 {
413 Arc *aptr = static_cast<Arc *>(a);
414
415 aptr->src_node = src;
416 aptr->tgt_node = tgt;
417 src->insert_arc(aptr);
418
419 if (not this->digraph and src != tgt)
420 {
421 try
422 {
423 tgt->insert_arc(aptr);
424 }
425 catch (const std::bad_alloc &)
426 {
427 src->remove_arc(aptr);
428 throw;
429 }
430 }
431
432 try
433 {
435 ++this->num_arcs;
436 }
437 catch (const std::bad_alloc &)
438 {
439 src->remove_arc(aptr);
440 if (not this->digraph and src != tgt)
441 tgt->remove_arc(aptr);
442 throw;
443 }
444
445 return aptr;
446 }
447
448 public:
450 {
451 return
452 try_insert_arc(this->get_src_node(arc), this->get_tgt_node(arc), arc);
453 }
454
455 private:
456 Arc * insert_arc(Node *src, Node *tgt, void *a)
457 {
458 bool compress_done = false;
459
460 retry:
461 try
462 {
463 return try_insert_arc(src, tgt, a);
464 }
465 catch (const std::bad_alloc &)
466 {
467 if (compress_done)
468 throw;
469
470 compress();
471 compress_done = true;
472 goto retry;
473 }
474 }
475
476 public:
478 {
479 Node *src = static_cast<Node *>(arc->src_node);
480 Node *tgt = static_cast<Node *>(arc->tgt_node);
481
482 src->remove_arc_ne(arc);
483 if (not this->digraph and src != tgt)
484 tgt->remove_arc_ne(arc);
485
486 arc->del(); // delete it from arc_set
487 --this->num_arcs;
488
489 return arc;
490 }
491
492 virtual void remove_arc(Arc *a)
493 {
494 delete disconnect_arc(a);
495 }
496
497 virtual void remove_node(Node *p)
498 {
499 if (this->digraph)
500 // traverse all arcs of graph and remove those whose source or target is p
501 this->remove_arcs_if([p, this](auto arc) {
502 return this->get_src_node(arc) == p or this->get_tgt_node(arc) == p;
503 });
504 else
505 {
506 // traverse arcs of node (collect then delete for safe iteration)
508 for (size_t i = 0, n = p->num_arcs; i < n; ++i)
509 arcs.append(static_cast<Arc *>(p->arc_array[i]));
510 arcs.for_each([this](auto arc) { this->remove_arc(arc); });
511 }
512
513 p->del(); // remove from node_set
514 --this->num_nodes;
515
516 delete p;
517 }
518
520 {
521 return static_cast<Node *>(node_set.get_first());
522 }
523
525 {
526 return static_cast<Arc *>(arc_set.get_first());
527 }
528
530 {
531 ah_range_error_if(this->get_num_arcs(p) == 0) << "Node has no arcs";
532 return static_cast<Arc *>(p->arc_array[0]);
533 }
534
536 {
537 assert(this->num_nodes == 0 and this->num_arcs == 0 and
538 node_set.is_empty() and arc_set.is_empty());
539 }
540
541 private:
543 {
544 while (not arc_set.is_empty())
545 delete static_cast<Arc *>(arc_set.remove_first());
546
547 while (not node_set.is_empty())
548 delete static_cast<Node *>(node_set.remove_first());
549
550 this->num_nodes = this->num_arcs = 0;
551 }
552
553 public:
555 {
556 clear();
557 }
558
559 void swap(Array_Graph & g) noexcept
560 {
561 this->common_swap(g);
562 node_set.swap(g.node_set);
563 arc_set.swap(g.arc_set);
564 }
565
568
569 private:
570 template <class Cmp>
571 struct Cmp_Arc
572 {
573 Cmp & cmp;
574
575 Cmp_Arc(Cmp && __cmp = Cmp())
576 : cmp(__cmp)
577 { /* empty */
578 }
579
581 : cmp(__cmp)
582 { /* empty */
583 }
584
585 bool operator ()(Arc *a1, Arc *a2) const noexcept
586 {
587 return cmp(a1, a2);
588 }
589 };
590
591 // sort_nodes() and sort_arcs() are inherited from GraphCommon via CRTP
592 // They use the get_node_dlink() and get_arc_dlink() accessors defined above
593 };
594
615 template <typename __Graph_Node = Graph_Anode<int>,
616 typename __Graph_Arc = Graph_Aarc<int>>
618
619} // namespace Aleph {
620
621# endif // TPL_AGRAPH_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:522
#define ah_bad_alloc_if(C)
Throws std::bad_alloc if condition holds.
Definition ah-errors.H:429
#define ah_range_error_if(C)
Throws std::range_error if condition holds.
Definition ah-errors.H:207
@ no_exception_ctor
Definition ahDefs.H:72
Iterator wrapper for C++ raw arrays and circular buffers.
Node_Arc_Iterator(Node *src) noexcept
Instantiate an iterator over node src.
Definition tpl_agraph.H:353
Node * get_tgt_node_ne() const
Return the target node of the current arc.
Definition tpl_agraph.H:380
Node_Arc_Iterator() noexcept
Instantiate an empty (invalid) iterator.
Definition tpl_agraph.H:348
Node * Set_Type
The set type over which iteration is performed.
Definition tpl_agraph.H:345
Arc * get_current_arc_ne() const noexcept
Return the current arc.
Definition tpl_agraph.H:374
Arc * Item_Type
The data type returned by get_curr().
Definition tpl_agraph.H:342
Arc * get_curr_ne() const noexcept
Definition tpl_agraph.H:367
Arc * get_current_arc() const
Return the current arc.
Definition tpl_agraph.H:377
typename Arc::Arc_Type Arc_Type
Definition tpl_agraph.H:280
virtual void remove_arc(Arc *a)
Definition tpl_agraph.H:492
virtual Node * insert_node(Node *p)
Definition tpl_agraph.H:393
void swap(Array_Graph &g) noexcept
Definition tpl_agraph.H:559
Arc * get_first_arc(Node *p) const
Definition tpl_agraph.H:529
Arc * disconnect_arc(Arc *arc)
Definition tpl_agraph.H:477
Dlink & get_arc_dlink() noexcept
Returns reference to internal arc Dlink for sorting operations.
Definition tpl_agraph.H:303
Arc * try_insert_arc(Node *src, Node *tgt, void *a)
Definition tpl_agraph.H:411
virtual ~Array_Graph() noexcept
Definition tpl_agraph.H:554
virtual void remove_node(Node *p)
Definition tpl_agraph.H:497
Arc * get_first_arc() const
Definition tpl_agraph.H:524
Node * get_first_node() const
Definition tpl_agraph.H:519
__Graph_Node Node
Definition tpl_agraph.H:277
Arc * insert_arc(Node *src, Node *tgt, void *a)
Definition tpl_agraph.H:456
void clear() noexcept
Definition tpl_agraph.H:542
Arc * connect_arc(Arc *arc)
Definition tpl_agraph.H:449
typename Node::Node_Type Node_Type
Definition tpl_agraph.H:279
Dlink & get_node_dlink() noexcept
Returns reference to internal node Dlink for sorting operations.
Definition tpl_agraph.H:300
__Graph_Arc Arc
Definition tpl_agraph.H:278
Iterator wrapper for C++ raw arrays.
Definition array_it.H:77
Generic directed graph (digraph) wrapper template.
Definition graph-dry.H:3848
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
Graph_Aarc(Arc_Info &&info=Arc_Info())
Definition tpl_agraph.H:237
Graph_Aarc(const Arc_Info &info)
Definition tpl_agraph.H:231
Graph_Aarc(void *src, void *tgt, const Arc_Info &data)
Definition tpl_agraph.H:256
Graph_Aarc(const Graph_Aarc &arc)
Definition tpl_agraph.H:243
Graph_Aarc(void *src, void *tgt, Arc_Info &&data=Arc_Info())
Definition tpl_agraph.H:262
Graph_Aarc & operator=(const Graph_Aarc &arc)
Definition tpl_agraph.H:248
Node of Array_Graph
Definition tpl_agraph.H:64
Graph_Anode & operator=(const Graph_Anode &node)
Definition tpl_agraph.H:109
void remove_arc(const void *arc)
Definition tpl_agraph.H:183
static constexpr size_t Default_Cap
Definition tpl_agraph.H:69
void * insert_arc(void *arc)
Definition tpl_agraph.H:141
void remove_arc_ne(const void *arc) noexcept
Definition tpl_agraph.H:164
Graph_Anode(Node_Info &&info)
Definition tpl_agraph.H:99
size_t contract_threshold
Definition tpl_agraph.H:87
void allocate_more(size_t new_size)
Definition tpl_agraph.H:128
static constexpr size_t Contract_Factor
Definition tpl_agraph.H:68
Graph_Anode(const Node_Info &info)
Definition tpl_agraph.H:94
bool compress() noexcept
Definition tpl_agraph.H:206
virtual ~Graph_Anode()
Definition tpl_agraph.H:122
Graph_Anode(const Graph_Anode &node)
Definition tpl_agraph.H:104
Graph_Anode(Graph_Anode *p)
Definition tpl_agraph.H:117
void init(const size_t dim)
Definition tpl_agraph.H:71
Common methods for the arc of a graph.
Definition graph-dry.H:528
ArcInfo arc_info
Definition graph-dry.H:542
Common attributes and methods for nodes (vertexes) belonging to graphs.
Definition graph-dry.H:435
NodeInfo node_info
Definition graph-dry.H:443
NodeInfo & get_info() noexcept
Return a modifiable reference to the data contained in the node.
Definition graph-dry.H:494
size_t num_arcs
data associated to the node. Access it with get_info()
Definition graph-dry.H:454
Common methods to the Aleph-w ( ) graph classes.
Definition graph-dry.H:618
Container< Arc * > arcs() const
Return a container with all the arcs of the graph.
Definition graph-dry.H:2738
size_t num_nodes
Definition graph-dry.H:625
Node * insert_node(const Node_Type &node_info)
Allocate a new node, set by copy its data content and insert it into the graph.
Definition graph-dry.H:1116
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:731
size_t num_arcs
Definition graph-dry.H:626
void common_swap(GT &g) noexcept
Definition graph-dry.H:641
Arc * insert_arc(Node *src, Node *tgt, const Arc_Type &arc_info)
Create and insert a new arc linking two nodes and copying data.
Definition graph-dry.H:1193
constexpr size_t get_num_arcs() const noexcept
Definition graph-dry.H:778
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:737
void remove_arcs_if(Predicate pred)
Remove all arcs matching a predicate.
Definition graph-dry.H:3665
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_dim_function > > dim(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4052
#define ALEPH_GRAPH_COPY_MOVE_CTORS(GraphClass)
Macro to generate copy/move constructors and assignment operators.
Definition graph-dry.H:3786
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynList< T > maps(const C &c, Op op)
Classic map operation.
STL namespace.
Iterator over arcs of a graph.
Definition tpl_agraph.H:325
Arc_Iterator(const Array_Graph &g)
Definition tpl_agraph.H:329
bool operator()(Arc *a1, Arc *a2) const noexcept
Definition tpl_agraph.H:585
Cmp_Arc(Cmp &&__cmp=Cmp())
Definition tpl_agraph.H:575
Node_Iterator(const Array_Graph &g) noexcept
Definition tpl_agraph.H:310
GTNodeIterator< Array_Graph > Base
Definition tpl_agraph.H:307
Common arc iterator for graph having its arcs derived from Dlink class.
Definition graph-dry.H:301
Common node iterator for graph having its node derived from Dlink class.
Definition graph-dry.H:256
Dynamic set implementations based on balanced binary search trees.
Simple graph implementation with adjacency lists.