Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
Graph_Coloring.H
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
66#ifndef GRAPH_COLORING_H
67#define GRAPH_COLORING_H
68
69# include <ah-graph-concepts.H>
70
71#include <tpl_graph.H>
72#include <tpl_array.H>
73#include <tpl_dynMapTree.H>
74#include <tpl_dynSetTree.H>
75#include <tpl_sort_utils.H>
76#include <cookie_guard.H>
77#include <ah-errors.H>
78
79namespace Aleph {
80
81namespace graph_coloring_detail {
82
83inline void *encode_color(size_t c) noexcept
84{
85 return reinterpret_cast<void *>(static_cast<uintptr_t>(c + 1));
86}
87
88inline bool is_colored(void *cookie) noexcept
89{
90 return cookie != nullptr;
91}
92
93inline size_t decode_color(void *cookie) noexcept
94{
95 return static_cast<size_t>(reinterpret_cast<uintptr_t>(cookie)) - 1;
96}
97
99{
100 size_t c = 0;
101 while (used.search(c) != nullptr)
102 ++c;
103 return c;
104}
105
112template <AlephGraph GT, ArcFilter<GT> SA>
115{
116 using Node = typename GT::Node;
117
118 // Ensure all nodes are present in the adjacency map with empty lists.
119 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
120 adj.insert(it.get_curr(), DynList<Node *>());
121
122 // Temporary per-node neighbor sets to deduplicate parallel arcs.
124 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
125 neighbor_sets.insert(it.get_curr(), DynSetTree<Node *>());
126
127 // Collect undirected neighbors, deduplicating parallel arcs.
128 for (auto it = g.get_arc_it(); it.has_curr(); it.next_ne())
129 {
130 auto *arc = it.get_curr();
131 if (not SA()(arc))
132 continue;
133 Node *u = g.get_src_node(arc);
134 Node *v = g.get_tgt_node(arc);
135 if (u == v)
136 continue;
137 neighbor_sets[u].insert(v);
138 neighbor_sets[v].insert(u);
139 }
140
141 // Materialize deduplicated neighbor sets into adjacency lists.
142 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
143 {
144 Node *u = it.get_curr();
145 auto &adj_list = adj[u];
146 auto &nbrs = neighbor_sets[u];
147 for (auto sit = nbrs.get_it(); sit.has_curr(); sit.next_ne())
148 adj_list.append(sit.get_curr());
149 }
150}
151
152template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
154{
155 for (auto it = g.get_arc_it(); it.has_curr(); it.next_ne())
156 {
157 auto *arc = it.get_curr();
158 ah_domain_error_if(SA()(arc) and g.get_src_node(arc) == g.get_tgt_node(arc))
159 << "graph coloring does not support self-loops";
160 }
161}
162
163} // end namespace graph_coloring_detail
164
196template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
198{
199 using Node = typename GT::Node;
200 using namespace graph_coloring_detail;
201
202 colors = {};
203 if (g.get_num_nodes() == 0)
204 return 0;
205
207
210
211 Cookie_Saver<GT> saver(g, true, false);
212 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
213 NODE_COOKIE(it.get_curr()) = nullptr;
214
215 size_t num_colors = 0;
216 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
217 {
218 Node *v = it.get_curr();
220
221 for (auto nit = adj[v].get_it(); nit.has_curr(); nit.next_ne())
222 if (Node *w = nit.get_curr(); is_colored(NODE_COOKIE(w)))
223 used.insert(decode_color(NODE_COOKIE(w)));
224
225 size_t c = smallest_available(used);
226 NODE_COOKIE(v) = encode_color(c);
227 colors.insert(v, c);
228
229 if (c + 1 > num_colors)
230 num_colors = c + 1;
231 }
232
233 return num_colors;
234}
235
264template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
266{
267 using Node = typename GT::Node;
268 using namespace graph_coloring_detail;
269
270 colors = {};
271 if (g.get_num_nodes() == 0)
272 return 0;
273
275
278
279 Cookie_Saver<GT> saver(g, true, false);
281 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
282 {
283 Node *p = it.get_curr();
284 NODE_COOKIE(p) = nullptr;
285 nodes.append(p);
286 }
287
288 mergesort(nodes, [&adj](Node *a, Node *b)
289 {
290 return adj[a].size() > adj[b].size();
291 });
292
293 size_t num_colors = 0;
294 for (auto nit = nodes.get_it(); nit.has_curr(); nit.next_ne())
295 {
296 Node *v = nit.get_curr();
298
299 for (auto ait = adj[v].get_it(); ait.has_curr(); ait.next_ne())
300 {
301 Node *w = ait.get_curr();
302 if (is_colored(NODE_COOKIE(w)))
303 used.insert(decode_color(NODE_COOKIE(w)));
304 }
305
306 size_t c = smallest_available(used);
307 NODE_COOKIE(v) = encode_color(c);
308 colors.insert(v, c);
309
310 if (c + 1 > num_colors)
311 num_colors = c + 1;
312 }
313
314 return num_colors;
315}
316
347template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
349{
350 using Node = typename GT::Node;
351 using namespace graph_coloring_detail;
352
353 colors = {};
354 if (const size_t n = g.get_num_nodes(); n == 0)
355 return 0;
356
358
361
362 Cookie_Saver<GT> saver(g, true, false);
365
366 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
367 {
368 Node *v = it.get_curr();
369 NODE_COOKIE(v) = nullptr;
372 }
373
374 size_t num_colors = 0;
375 while (not uncolored_nodes.is_empty())
376 {
377 Node *best = nullptr;
378 size_t best_sat = 0;
379 size_t best_deg = 0;
380
381 // Select best node: O(V)
382 for (auto it = uncolored_nodes.get_it(); it.has_curr(); it.next_ne())
383 {
384 Node *v = it.get_curr();
385 size_t sat = saturation_sets[v].size();
386 size_t deg = adj[v].size();
387
388 if (best == nullptr or sat > best_sat or (sat == best_sat and deg > best_deg))
389 {
390 best = v;
391 best_sat = sat;
392 best_deg = deg;
393 }
394 }
395
396 size_t c = smallest_available(saturation_sets[best]);
397 NODE_COOKIE(best) = encode_color(c);
398 colors.insert(best, c);
399 uncolored_nodes.remove(best);
400
401 if (c + 1 > num_colors)
402 num_colors = c + 1;
403
404 // Update neighbors: O(deg(best) log colors)
405 for (auto it = adj[best].get_it(); it.has_curr(); it.next_ne())
406 if (Node *w = it.get_curr(); not is_colored(NODE_COOKIE(w)))
407 saturation_sets[w].insert(c);
408 }
409
410 return num_colors;
411}
412
441template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
444{
445 using Node = typename GT::Node;
446
447 // Explicit per-node check: every graph node must have a color entry.
448 // A size match alone is insufficient — the map could be keyed with
449 // foreign pointers that coincidentally match the node count.
450 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
451 if (colors.search(it.get_curr()) == nullptr)
452 return false;
453
454 for (auto it = g.get_arc_it(); it.has_curr(); it.next_ne())
455 {
456 auto *arc = it.get_curr();
457 if (not SA()(arc))
458 continue;
459 Node *u = g.get_src_node(arc);
460 Node *v = g.get_tgt_node(arc);
461 if (u == v)
462 return false;
463 auto *pu = colors.search(u);
464 auto *pv = colors.search(v);
465 if (pu == nullptr or pv == nullptr)
466 return false;
467 if (pu->second == pv->second)
468 return false;
469 }
470
471 return true;
472}
473
507template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
509{
510 using Node = typename GT::Node;
511 using namespace graph_coloring_detail;
512
514 << "chromatic_number: graph has " << g.get_num_nodes() << " nodes (max 64)";
515
516 colors = {};
517 if (g.get_num_nodes() == 0)
518 return 0;
519
521
524
525 if (upper <= 2)
526 {
527 colors = std::move(best_colors);
528 return upper;
529 }
530
531 DynList<Node *> node_list;
532 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
533 node_list.append(it.get_curr());
534
535 const size_t n = node_list.size();
536 Array<Node *> nodes(n, nullptr);
537 size_t idx = 0;
538 for (auto it = node_list.get_it(); it.has_curr(); it.next_ne())
539 nodes[idx++] = it.get_curr();
540
542 {
543 Cookie_Saver<GT> saver(g, true, false);
544 for (size_t i = 0; i < n; ++i)
545 NODE_COOKIE(nodes[i]) = reinterpret_cast<void *>(static_cast<uintptr_t>(i));
546
547 for (auto it = g.get_arc_it(); it.has_curr(); it.next_ne())
548 {
549 auto *arc = it.get_curr();
550 if (not SA()(arc))
551 continue;
552 size_t i = reinterpret_cast<uintptr_t>(NODE_COOKIE(g.get_src_node(arc)));
553 size_t j = reinterpret_cast<uintptr_t>(NODE_COOKIE(g.get_tgt_node(arc)));
554 if (i != j)
555 {
556 adj_idx[i].append(j);
557 adj_idx[j].append(i);
558 }
559 }
560 }
561
562 Array<size_t> coloring(n, static_cast<size_t>(0));
563 auto reset_coloring = [&]()
564 {
565 for (size_t i = 0; i < n; ++i)
566 coloring[i] = 0;
567 };
568
569 auto try_k_coloring = [&](size_t k, auto &self, size_t node_idx) -> bool
570 {
571 if (node_idx == n)
572 return true;
573 for (size_t c = 0; c < k; ++c)
574 {
575 bool feasible = true;
576 for (auto jit = adj_idx[node_idx].get_it(); jit.has_curr(); jit.next_ne())
577 {
578 size_t j = jit.get_curr();
579 if (j < node_idx and coloring[j] == c)
580 {
581 feasible = false;
582 break;
583 }
584 }
585 if (feasible)
586 {
587 coloring[node_idx] = c;
588 if (self(k, self, node_idx + 1))
589 return true;
590 }
591 }
592 coloring[node_idx] = 0;
593 return false;
594 };
595
596 size_t lo = 2, hi = upper;
597 while (lo < hi)
598 {
599 size_t mid = (lo + hi) / 2;
602 hi = mid;
603 else
604 lo = mid + 1;
605 }
606
607 if (lo < upper)
608 {
611 colors = {};
612 for (size_t i = 0; i < n; ++i)
613 colors.insert(nodes[i], coloring[i]);
614 }
615 else
616 colors = std::move(best_colors);
617
618 return lo;
619}
620
633template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
635{
636public:
644 {
646 }
647};
648
656template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
658{
659public:
670};
671
679template <AlephGraph GT, ArcFilter<GT> SA = Dft_Show_Arc<GT>>
681{
682public:
690 {
692 }
693};
694
695} // end namespace Aleph
696
697#endif // GRAPH_COLORING_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.
WeightedDigraph::Node Node
long double w
Definition btreepic.C:153
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
RAII guard that saves and restores graph cookies.
Functor wrapper for dsatur_coloring.
size_t operator()(const GT &g, DynMapTree< typename GT::Node *, size_t > &colors) const
Execute DSatur coloring.
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
Generic key-value map implemented on top of a binary search tree.
Pair * insert(const Key &key, const Data &data)
Insert a key-value pair.
Dynamic set backed by balanced binary search trees with automatic memory management.
const size_t & size() const
Returns the cardinality of the set.
Key * insert(const Key &key)
Inserts a key into the dynamic set.
Functor wrapper for greedy_coloring.
size_t operator()(const GT &g, DynMapTree< typename GT::Node *, size_t > &colors) const
Execute greedy coloring.
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1065
Functor wrapper for welsh_powell_coloring.
size_t operator()(const GT &g, DynMapTree< typename GT::Node *, size_t > &colors) const
Execute Welsh-Powell coloring.
auto get_arc_it() const noexcept
Obtains an iterator to the arc of graph.
Definition graph-dry.H:2908
Node * get_src_node(Arc *arc) const noexcept
Return the source node of arc (only for directed graphs)
Definition graph-dry.H:779
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:737
auto get_node_it() const noexcept
Obtains an iterator to the nodes of graph.
Definition graph-dry.H:2886
Node * get_tgt_node(Arc *arc) const noexcept
Return the target node of arc (only for directed graphs)
Definition graph-dry.H:785
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:228
RAII guards for graph node/arc cookies.
DynArray< Graph::Node * > nodes
Definition graphpic.C:406
size_t dsatur_coloring(const GT &g, DynMapTree< typename GT::Node *, size_t > &colors)
DSatur graph coloring (saturation-degree heuristic).
bool is_valid_coloring(const GT &g, const DynMapTree< typename GT::Node *, size_t > &colors)
Validates a graph coloring.
size_t chromatic_number(const GT &g, DynMapTree< typename GT::Node *, size_t > &colors)
Computes the exact chromatic number of a small graph.
#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
size_t greedy_coloring(const GT &g, DynMapTree< typename GT::Node *, size_t > &colors)
Greedy graph coloring in iteration order.
size_t welsh_powell_coloring(const GT &g, DynMapTree< typename GT::Node *, size_t > &colors)
Welsh-Powell graph coloring.
size_t decode_color(void *cookie) noexcept
bool is_colored(void *cookie) noexcept
void build_undirected_adj(const GT &g, DynMapTree< typename GT::Node *, DynList< typename GT::Node * > > &adj)
Internal helper to pre-build undirected adjacency lists.
size_t smallest_available(const DynSetTree< size_t > &used)
void validate_no_self_loops(const GT &g)
void * encode_color(size_t c) noexcept
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
size_t size(Node *root) noexcept
and
Check uniqueness with explicit hash + equality functors.
void mergesort(T *a, const long l, const long r, Array< T > &buf, Compare cmp)
Sort an array using merge sort with a reusable buffer.
static int * k
Dynamic array container with automatic resizing.
Dynamic key-value map based on balanced binary search trees.
Dynamic set implementations based on balanced binary search trees.
Generic graph and digraph implementations.
Comprehensive sorting algorithms and search utilities for Aleph-w.