Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
graph_coloring_example.cc
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
31
84# include <iostream>
85# include <iomanip>
86# include <string>
87# include <cstdio>
88
89# include <Graph_Coloring.H>
90# include <tpl_graph.H>
91
92using namespace Aleph;
93using namespace std;
94
95// ============================================================================
96// Graph type used throughout this example
97// ============================================================================
98
100using Node = G::Node;
102
103// ============================================================================
104// Display helpers
105// ============================================================================
106
107static const char * color_names[] = {
108 "Red", "Blue", "Green", "Yellow", "Orange",
109 "Purple", "Cyan", "Magenta", "Brown", "Gray"
110};
111
112static const char * color_name(size_t c)
113{
114 constexpr size_t N = sizeof(color_names) / sizeof(color_names[0]);
115 if (c < N) return color_names[c];
116 static char buf[32];
117 std::snprintf(buf, sizeof(buf), "Color%zu", c);
118 return buf;
119}
120
121static void print_coloring(const G & g, const ColorMap & colors,
122 size_t num_colors)
123{
124 cout << " Colors used: " << num_colors << "\n";
125 cout << " Assignment:\n";
126 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
127 {
128 Node *v = it.get_curr();
129 size_t c = colors.find(v);
130 cout << " " << left << setw(20) << v->get_info()
131 << " -> " << color_name(c) << " (" << c << ")\n";
132 }
133 cout << " Valid: " << (is_valid_coloring(g, colors) ? "YES" : "NO") << "\n";
134}
135
136static void separator(const string & title)
137{
138 cout << "\n";
139 cout << "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
140 cout << title << "\n";
141 cout << "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
142}
143
144// ============================================================================
145// Part 1: Map coloring — South America
146// ============================================================================
147
154static void demo_map_coloring()
155{
156 separator("Part 1: Map Coloring — South America");
157
158 cout << "Each node is a country; edges represent shared borders.\n";
159 cout << "Goal: color the map so no two adjacent countries share a color.\n";
160 cout << "The Four Color Theorem guarantees χ(G) ≤ 4 for any planar map.\n\n";
161
162 G g;
163 auto *br = g.insert_node("Brazil");
164 auto *ar = g.insert_node("Argentina");
165 auto *uy = g.insert_node("Uruguay");
166 auto *py = g.insert_node("Paraguay");
167 auto *bo = g.insert_node("Bolivia");
168 auto *pe = g.insert_node("Peru");
169 auto *cl = g.insert_node("Chile");
170 auto *ec = g.insert_node("Ecuador");
171 auto *co = g.insert_node("Colombia");
172 auto *ve = g.insert_node("Venezuela");
173 auto *gy = g.insert_node("Guyana");
174 auto *sr = g.insert_node("Suriname");
175 auto *gf = g.insert_node("Fr. Guiana");
176
177 // Borders (undirected)
178 g.insert_arc(br, uy); g.insert_arc(br, ar);
179 g.insert_arc(br, py); g.insert_arc(br, bo);
180 g.insert_arc(br, pe); g.insert_arc(br, co);
181 g.insert_arc(br, ve); g.insert_arc(br, gy);
182 g.insert_arc(br, sr); g.insert_arc(br, gf);
183 g.insert_arc(ar, uy); g.insert_arc(ar, py);
184 g.insert_arc(ar, bo); g.insert_arc(ar, cl);
185 g.insert_arc(py, bo); g.insert_arc(bo, pe);
186 g.insert_arc(bo, cl); g.insert_arc(pe, cl);
187 g.insert_arc(pe, ec); g.insert_arc(pe, co);
188 g.insert_arc(ec, co); g.insert_arc(co, ve);
189 g.insert_arc(ve, gy); g.insert_arc(gy, sr);
190 g.insert_arc(sr, gf);
191
192 cout << "Graph: " << g.get_num_nodes() << " countries, "
193 << g.get_num_arcs() << " borders.\n\n";
194
196
197 cout << "▶ DSatur (best heuristic):\n";
198 size_t k = dsatur_coloring(g, colors);
200}
201
202// ============================================================================
203// Part 2: Exam scheduling
204// ============================================================================
205
217{
218 separator("Part 2: Exam Scheduling");
219
220 cout << "Courses that share students cannot be scheduled at the same time.\n";
221 cout << "Each color represents an exam time slot.\n\n";
222
223 G g;
224 auto *math = g.insert_node("Mathematics");
225 auto *phys = g.insert_node("Physics");
226 auto *cs = g.insert_node("Comp. Science");
227 auto *chem = g.insert_node("Chemistry");
228 auto *bio = g.insert_node("Biology");
229 auto *eng = g.insert_node("English");
230 auto *hist = g.insert_node("History");
231 auto *econ = g.insert_node("Economics");
232
233 // Conflicts (shared students)
234 g.insert_arc(math, phys); // Math & Physics share students
235 g.insert_arc(math, cs); // Math & CS share students
236 g.insert_arc(math, econ);
237 g.insert_arc(phys, cs); // Physics & CS share students
238 g.insert_arc(phys, chem);
239 g.insert_arc(cs, econ);
240 g.insert_arc(chem, bio);
241 g.insert_arc(bio, eng);
242 g.insert_arc(eng, hist);
243 g.insert_arc(hist, econ);
244
245 cout << "Courses: " << g.get_num_nodes()
246 << ", Conflicts: " << g.get_num_arcs() << "\n\n";
247
249
250 cout << "▶ Greedy (fast, may not be optimal):\n";
251 size_t k1 = greedy_coloring(g, colors);
253
254 cout << "\n▶ Welsh-Powell (sort by degree first):\n";
255 size_t k2 = welsh_powell_coloring(g, colors);
257
258 cout << "\n▶ DSatur (adaptive, usually optimal):\n";
259 size_t k3 = dsatur_coloring(g, colors);
261
262 cout << "\n▶ Exact chromatic number:\n";
263 size_t chi = chromatic_number(g, colors);
264 cout << " χ(G) = " << chi << " time slot(s) minimum\n";
266}
267
268// ============================================================================
269// Part 3: Register allocation
270// ============================================================================
271
283{
284 separator("Part 3: Register Allocation (Compiler Optimization)");
285
286 cout << "Variables that are simultaneously live cannot share a register.\n";
287 cout << "Colors represent CPU registers (R0, R1, R2, ...).\n\n";
288
289 // Simulate interference graph from a small function body
290 //
291 // a = ...
292 // b = a + 1 (a and b live simultaneously)
293 // c = a * 2 (a, b, c live simultaneously)
294 // d = b + c (b, c, d live simultaneously)
295 // e = d - 1 (d, e live simultaneously)
296 // return e
297 //
298 G g;
299 auto *a = g.insert_node("a");
300 auto *b = g.insert_node("b");
301 auto *c = g.insert_node("c");
302 auto *d = g.insert_node("d");
303 auto *e = g.insert_node("e");
304
305 // Interference edges (simultaneously live)
306 g.insert_arc(a, b); // a and b overlap
307 g.insert_arc(a, c); // a and c overlap
308 g.insert_arc(b, c); // b and c overlap
309 g.insert_arc(b, d); // b and d overlap
310 g.insert_arc(c, d); // c and d overlap
311 g.insert_arc(d, e); // d and e overlap
312
313 cout << "Variables: " << g.get_num_nodes()
314 << ", Interferences: " << g.get_num_arcs() << "\n\n";
315
317
318 cout << "▶ DSatur coloring (minimum registers):\n";
319 size_t k = dsatur_coloring(g, colors);
320 cout << " Registers needed: " << k << "\n";
321 cout << " Assignment:\n";
322 for (auto it = g.get_node_it(); it.has_curr(); it.next_ne())
323 {
324 Node *v = it.get_curr();
325 cout << " " << left << setw(4) << v->get_info()
326 << " -> R" << colors.find(v) << "\n";
327 }
328 cout << " Valid (no interference): "
329 << (is_valid_coloring(g, colors) ? "YES" : "NO") << "\n";
330
331 cout << "\n▶ Exact chromatic number:\n";
332 size_t chi = chromatic_number(g, colors);
333 cout << " Minimum registers needed: " << chi << "\n";
334
335 if (chi <= 3)
336 cout << " ✓ Fits in 3 registers — no spilling required!\n";
337 else
338 cout << " ✗ Needs more than 3 registers — some variables must be spilled.\n";
339}
340
341// ============================================================================
342// Part 4: Algorithm comparison on the Petersen graph
343// ============================================================================
344
353{
354 separator("Part 4: Algorithm Comparison — Petersen Graph");
355
356 cout << "The Petersen graph is 3-regular and has χ(G) = 3.\n";
357 cout << "It is a well-known benchmark for coloring heuristics.\n\n";
358
359 G g;
360 // Outer ring: 0..4, inner pentagram: 5..9
361 Node *nodes[10];
362 for (int i = 0; i < 10; ++i)
363 nodes[i] = g.insert_node("v" + to_string(i));
364
365 // Outer cycle: 0-1-2-3-4-0
366 for (int i = 0; i < 5; ++i)
367 g.insert_arc(nodes[i], nodes[(i + 1) % 5]);
368
369 // Inner pentagram (5-connected skipping one): 5-7-9-6-8-5
370 g.insert_arc(nodes[5], nodes[7]);
371 g.insert_arc(nodes[7], nodes[9]);
372 g.insert_arc(nodes[9], nodes[6]);
373 g.insert_arc(nodes[6], nodes[8]);
374 g.insert_arc(nodes[8], nodes[5]);
375
376 // Spokes: i -- i+5
377 for (int i = 0; i < 5; ++i)
378 g.insert_arc(nodes[i], nodes[i + 5]);
379
380 cout << "Graph: " << g.get_num_nodes() << " nodes, "
381 << g.get_num_arcs() << " edges (3-regular).\n\n";
382
384
385 cout << "▶ Greedy (order-dependent):\n";
386 size_t k1 = greedy_coloring(g, colors);
387 cout << " Colors: " << k1 << " Valid: "
388 << (is_valid_coloring(g, colors) ? "yes" : "no") << "\n";
389
390 cout << "\n▶ Welsh-Powell (decreasing degree):\n";
391 size_t k2 = welsh_powell_coloring(g, colors);
392 cout << " Colors: " << k2 << " Valid: "
393 << (is_valid_coloring(g, colors) ? "yes" : "no") << "\n";
394
395 cout << "\n▶ DSatur (adaptive saturation):\n";
396 size_t k3 = dsatur_coloring(g, colors);
397 cout << " Colors: " << k3 << " Valid: "
398 << (is_valid_coloring(g, colors) ? "yes" : "no") << "\n";
400
401 cout << "\n▶ Exact chromatic number (branch-and-bound):\n";
402 size_t chi = chromatic_number(g, colors);
403 cout << " χ(Petersen) = " << chi << "\n";
404 cout << " Valid: " << (is_valid_coloring(g, colors) ? "yes" : "no") << "\n";
405
406 cout << "\n Summary:\n";
407 cout << " Greedy: " << k1 << " color(s)\n";
408 cout << " Welsh-Powell: " << k2 << " color(s)\n";
409 cout << " DSatur: " << k3 << " color(s)\n";
410 cout << " Exact (χ): " << chi << " color(s) ← optimal\n";
411}
412
413// ============================================================================
414// Part 5: State safety demonstration
415// ============================================================================
416
422{
423 separator("Part 5: State Safety — Cookies Are Restored on Completion");
424
425 cout << "This implementation temporarily reuses NODE_COOKIE for coloring state,\n";
426 cout << "but restores any pre-existing cookie values when it finishes.\n";
427 cout << "It is not thread-safe, reentrant, or safe for nested/concurrent\n";
428 cout << "cookie users without external synchronization.\n\n";
429
430 G g;
431 auto *a = g.insert_node("a");
432 auto *b = g.insert_node("b");
433 auto *c = g.insert_node("c");
434 g.insert_arc(a, b);
435 g.insert_arc(b, c);
436 g.insert_arc(c, a);
437
438 // Store sentinel values in cookies (simulating another algorithm's data)
439 int sentinel_a = 100, sentinel_b = 200, sentinel_c = 300;
443
444 cout << "Before coloring:\n";
445 cout << " cookie(a) = " << NODE_COOKIE(a) << " (expected " << &sentinel_a << ")\n";
446 cout << " cookie(b) = " << NODE_COOKIE(b) << " (expected " << &sentinel_b << ")\n";
447 cout << " cookie(c) = " << NODE_COOKIE(c) << " (expected " << &sentinel_c << ")\n\n";
448
450 size_t k = dsatur_coloring(g, colors);
451 cout << "After dsatur_coloring (" << k << " colors):\n";
452 cout << " cookie(a) = " << NODE_COOKIE(a)
453 << (NODE_COOKIE(a) == &sentinel_a ? " ✓ preserved" : " ✗ corrupted!") << "\n";
454 cout << " cookie(b) = " << NODE_COOKIE(b)
455 << (NODE_COOKIE(b) == &sentinel_b ? " ✓ preserved" : " ✗ corrupted!") << "\n";
456 cout << " cookie(c) = " << NODE_COOKIE(c)
457 << (NODE_COOKIE(c) == &sentinel_c ? " ✓ preserved" : " ✗ corrupted!") << "\n";
458 cout << " Coloring valid: " << (is_valid_coloring(g, colors) ? "yes" : "no") << "\n";
459}
460
461// ============================================================================
462// Main
463// ============================================================================
464
465int main()
466{
467 cout << "╔══════════════════════════════════════════════════════════════════╗\n";
468 cout << "║ Graph Coloring Algorithms — Aleph-w Example ║\n";
469 cout << "╚══════════════════════════════════════════════════════════════════╝\n";
470
476
477 cout << "\n";
478 cout << "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
479 cout << "Summary of algorithms in Graph_Coloring.H\n";
480 cout << "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n";
481 cout << "┌─────────────────────────┬──────────────────────┬─────────────────┐\n";
482 cout << "│ Function │ Complexity │ Quality │\n";
483 cout << "├─────────────────────────┼──────────────────────┼─────────────────┤\n";
484 cout << "│ greedy_coloring │ O((V+E) log V) │ ≤ Δ+1 colors │\n";
485 cout << "│ welsh_powell_coloring │ O((V+E) log V) │ Often better │\n";
486 cout << "│ dsatur_coloring │ O(V^2 + E log V) │ Near-optimal │\n";
487 cout << "│ is_valid_coloring │ O(E log V) │ Validation │\n";
488 cout << "│ chromatic_number │ Exponential (≤64 V) │ Exact χ(G) │\n";
489 cout << "└─────────────────────────┴──────────────────────┴─────────────────┘\n\n";
490 cout << "All algorithms:\n";
491 cout << " • Return colors as DynMapTree<Node*, size_t> (0-based indices)\n";
492 cout << " • Temporarily reuse NODE_COOKIE, then restore prior values on completion\n";
493 cout << " • Are not thread-safe/reentrant for concurrent or nested cookie users\n";
494 cout << " • Work on List_Graph, List_SGraph, Array_Graph and digraph variants\n";
495 cout << " • Accept any arc filter via template parameter SA\n\n";
496
497 return 0;
498}
Graph coloring algorithms and heuristics.
WeightedDigraph::Node Node
Graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:428
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Definition tpl_graph.H:524
_Graph_Node Node
The graph type.
Definition tpl_graph.H:432
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Definition tpl_graph.H:604
constexpr size_t get_num_nodes() const noexcept
Return the total of nodes of graph.
Definition graph-dry.H:695
constexpr size_t get_num_arcs() const noexcept
Definition graph-dry.H:784
auto get_node_it() const noexcept
Obtains an iterator to the nodes of graph.
Definition graph-dry.H:2786
#define N
Definition fib.C:294
static void demo_exam_scheduling()
Models exam scheduling as a graph coloring problem.
static void demo_algorithm_comparison()
The Petersen graph is a well-known benchmark in graph theory.
static void separator(const string &title)
static const char * color_name(size_t c)
static const char * color_names[]
static void print_coloring(const G &g, const ColorMap &colors, size_t num_colors)
static void demo_cookie_safety()
Shows that running one coloring algorithm does not alter cookies that were set previously by user cod...
static void demo_map_coloring()
Demonstrates graph coloring as a map-coloring problem.
static void demo_register_allocation()
Models register allocation as graph coloring.
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 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.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
std::string to_string(const time_t t, const std::string &format)
Format a time_t value into a string using format.
Definition ah-date.H:140
STL namespace.
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
static int * k
Generic graph and digraph implementations.