157#include <tclap/CmdLine.h>
163using namespace Aleph;
177 cout <<
"\n" << string(60,
'=') <<
"\n";
179 cout << string(60,
'=') <<
"\n\n";
191 cout <<
" Nodes: " << g.get_num_nodes() <<
endl;
192 cout <<
" Arcs: " << g.get_num_arcs() <<
endl;
195 for (
auto it = g.get_node_it(); it.has_curr(); it.next())
197 auto node = it.get_curr();
198 cout <<
" " << node->get_info();
205 cout <<
" (degree=" << degree <<
")" <<
endl;
209 for (
auto it = g.get_arc_it(); it.has_curr(); it.next())
211 auto arc = it.get_curr();
212 cout <<
" " << g.get_src_node(arc)->get_info()
213 <<
" -- " << g.get_tgt_node(arc)->get_info() <<
endl;
225 cout <<
"An Eulerian CYCLE visits every edge exactly once and returns to start.\n";
226 cout <<
"Condition (undirected): ALL vertices must have EVEN degree.\n\n";
240 cout <<
"\nAll vertices have degree 2 (even)." <<
endl;
243 cout <<
"Is Eulerian? " << (
test1(triangle) ?
"YES" :
"NO") <<
endl;
244 cout <<
"Eulerian cycle: A -> B -> C -> A" <<
endl;
264 cout <<
"\nAll vertices have degree 4 (even)." <<
endl;
267 cout <<
"Is Eulerian? " << (
test2(square) ?
"YES" :
"NO") <<
endl;
280 cout <<
"\nX has degree 1 (odd), Z has degree 1 (odd)." <<
endl;
283 cout <<
"Is Eulerian? " << (
test3(path) ?
"YES" :
"NO") <<
endl;
284 cout <<
"Cannot return to start without reusing edges." <<
endl;
295 cout <<
"The famous problem that started graph theory (Euler, 1736).\n\n";
296 cout <<
"Can you cross all 7 bridges exactly once and return to start?\n\n";
298 cout <<
"The city of Königsberg (now Kaliningrad) had:\n";
299 cout <<
" - 4 land masses (A, B, C, D)\n";
300 cout <<
" - 7 bridges connecting them\n\n";
329 cout <<
"Graph representation:" <<
endl;
330 cout <<
" Vertices (land masses): A, B, C, D" <<
endl;
331 cout <<
" Edges (bridges): 7" <<
endl;
333 cout <<
" A: degree 5 (ODD)" <<
endl;
334 cout <<
" B: degree 3 (ODD)" <<
endl;
335 cout <<
" C: degree 3 (ODD)" <<
endl;
336 cout <<
" D: degree 3 (ODD)" <<
endl;
341 cout <<
"\nEuler proved: With 4 odd-degree vertices, it's IMPOSSIBLE!\n";
342 cout <<
"For an Eulerian cycle, ALL vertices must have even degree.\n";
343 cout <<
"For an Eulerian path, exactly 0 or 2 vertices can have odd degree.\n";
354 cout <<
"For directed graphs, degree balance alone is not enough for an Eulerian cycle.\n";
355 cout <<
"Aleph-w checks in-degree/out-degree balance and also performs a reachability\n";
356 cout <<
"check among non-isolated vertices for cycle classification.\n\n";
362 auto d1 =
dcycle.insert_node(
"1");
363 auto d2 =
dcycle.insert_node(
"2");
364 auto d3 =
dcycle.insert_node(
"3");
365 dcycle.insert_arc(d1, d2, 1);
366 dcycle.insert_arc(d2, d3, 1);
367 dcycle.insert_arc(d3, d1, 1);
369 cout <<
"Directed cycle: 1 -> 2 -> 3 -> 1" <<
endl;
370 cout <<
" Node 1: in=1, out=1" <<
endl;
371 cout <<
" Node 2: in=1, out=1" <<
endl;
372 cout <<
" Node 3: in=1, out=1" <<
endl;
387 cout <<
"Directed path: A -> B -> C" <<
endl;
388 cout <<
" Node A: in=0, out=1 (UNBALANCED)" <<
endl;
389 cout <<
" Node B: in=1, out=1" <<
endl;
390 cout <<
" Node C: in=1, out=0 (UNBALANCED)" <<
endl;
399 auto f1 =
fig8.insert_node(
"Center");
400 auto f2 =
fig8.insert_node(
"Top");
401 auto f3 =
fig8.insert_node(
"Bottom");
403 fig8.insert_arc(f1,
f2, 1);
404 fig8.insert_arc(
f2, f1, 1);
406 fig8.insert_arc(f1,
f3, 1);
407 fig8.insert_arc(
f3, f1, 1);
410 cout <<
" Center: in=2, out=2" <<
endl;
411 cout <<
" Top: in=1, out=1" <<
endl;
412 cout <<
" Bottom: in=1, out=1" <<
endl;
429 cout <<
"A mail carrier wants to visit every street exactly once.\n";
430 cout <<
"This is the Eulerian path/cycle problem!\n\n";
453 cout <<
"\nPerfect! The mail carrier can visit every street exactly once\n"
454 <<
"and return to the post office!\n";
456 cout <<
"\nSome streets must be visited more than once.\n";
461 cout <<
"Draw all connections without lifting the pen?\n";
462 cout <<
"This is an Eulerian path problem!\n\n";
477 cout <<
"Circuit with 5 connections:" <<
endl;
478 cout <<
" Pin1-Pin2, Pin2-Pin3, Pin3-Pin4, Pin4-Pin1, Pin1-Pin3" <<
endl;
482 for (
auto it =
circuit.get_node_it(); it.has_curr(); it.next())
493 cout <<
"Can draw all connections returning to start (Eulerian cycle)!\n";
495 cout <<
"Can draw all connections but not return to start (Eulerian path).\n";
497 cout <<
"Cannot draw without lifting pen - need " << (
odd_count/2) <<
" extra strokes.\n";
506 print_section(
"HIERHOLZER'S ALGORITHM: Finding Eulerian Paths");
508 cout <<
"Hierholzer's algorithm constructs an Eulerian path/cycle in O(E) time.\n";
509 cout <<
"Instead of just testing existence, it finds the actual path!\n\n";
525 cout <<
"Triangle graph: A-B-C\n";
526 cout <<
"Classification: ";
528 case Eulerian_Type::Cycle:
cout <<
"EULERIAN CYCLE\n";
break;
529 case Eulerian_Type::Path:
cout <<
"EULERIAN PATH\n";
break;
530 case Eulerian_Type::None:
cout <<
"NOT EULERIAN\n";
break;
537 for (
auto node :
nodes1) {
538 if (!first)
cout <<
" -> ";
539 cout << node->get_info();
559 cout <<
"Linear path: 1-2-3-4\n";
560 cout <<
"Classification: ";
562 case Eulerian_Type::Cycle:
cout <<
"EULERIAN CYCLE\n";
break;
563 case Eulerian_Type::Path:
cout <<
"EULERIAN PATH\n";
break;
564 case Eulerian_Type::None:
cout <<
"NOT EULERIAN\n";
break;
567 if (
result2.type != Eulerian_Type::None) {
571 for (
auto node :
nodes2) {
572 if (!first)
cout <<
" -> ";
573 cout << node->get_info();
580 print_subsection(
"Example 3: Bow-tie graph (two triangles sharing a vertex)");
583 auto center =
bowtie.insert_node(
"Center");
601 cout <<
"Bow-tie: Two triangles sharing 'Center'\n";
602 cout <<
" Center has degree 4 (even)\n";
603 cout <<
" All others have degree 2 (even)\n";
604 cout <<
"Classification: ";
606 case Eulerian_Type::Cycle:
cout <<
"EULERIAN CYCLE\n";
break;
607 case Eulerian_Type::Path:
cout <<
"EULERIAN PATH\n";
break;
608 case Eulerian_Type::None:
cout <<
"NOT EULERIAN\n";
break;
614 for (
auto node :
nodes3) {
615 if (!first)
cout <<
" -> ";
616 cout << node->get_info();
621 cout <<
"\nHierholzer's algorithm visits both triangles, returning to start!\n";
632 cout <<
"The compute() method returns detailed classification:\n";
633 cout <<
" - Eulerian_Type::Cycle - Has Eulerian cycle\n";
634 cout <<
" - Eulerian_Type::Path - Has Eulerian path but not cycle\n";
635 cout <<
" - Eulerian_Type::None - Not Eulerian\n\n";
647 TestCase t1{
"Triangle", {}, {{
"A",
"B"},{
"B",
"C"},{
"C",
"A"}}};
649 TestCase t2{
"Path 1-2-3", {}, {{
"1",
"2"},{
"2",
"3"}}};
651 TestCase t3{
"Star", {}, {{
"C",
"1"},{
"C",
"2"},{
"C",
"3"},{
"C",
"4"}}};
657 cout <<
setw(20) <<
"Graph" <<
setw(15) <<
"Result" <<
setw(20) <<
"has_eulerian_path()" <<
endl;
663 for (
auto& [u, v] :
tc.edges) {
664 if (node_map.find(u) == node_map.end())
665 node_map[u] =
tc.g.insert_node(u);
666 if (node_map.find(v) == node_map.end())
667 node_map[v] =
tc.g.insert_node(v);
668 tc.g.insert_arc(node_map[u], node_map[v], 1);
676 case Eulerian_Type::Cycle:
result_str =
"CYCLE";
break;
677 case Eulerian_Type::Path:
result_str =
"PATH";
break;
678 case Eulerian_Type::None:
result_str =
"NONE";
break;
696 "Eulerian graph example for Aleph-w.\n"
697 "Demonstrates Eulerian path and cycle detection.",
703 "Run specific section: cycle, konigsberg, directed, practical, hierholzer, types, or 'all'",
704 false,
"all",
"section",
cmd
712 cout <<
"============================================================\n";
713 cout <<
" ALEPH-W EULERIAN GRAPHS EXAMPLE\n";
714 cout <<
"============================================================\n";
734 cout <<
"\n" << string(60,
'=') <<
"\n";
735 cout <<
"Eulerian graphs demo completed!\n";
736 cout << string(60,
'=') <<
"\n\n";
740 catch (TCLAP::ArgException& e)
742 cerr <<
"Error: " << e.error() <<
" for argument " << e.argId() <<
endl;
747 cerr <<
"Error: " << e.what() <<
endl;
Generic directed graph (digraph) wrapper template.
Finds and constructs an Eulerian path or cycle using Hierholzer's algorithm.
size_t size() const noexcept
Count the number of elements of the list.
Graph implemented with double-linked adjacency lists.
virtual Node * insert_node(Node *node) noexcept
Insertion of a node already allocated.
Arc * insert_arc(Node *src_node, Node *tgt_node, void *a)
Tests whether a graph or digraph is Eulerian.
Eulerian graph detection and path/cycle finding.
void print_subsection(const string &title)
void demo_eulerian_type()
void print_section(const string &title)
void print_graph(const string &label, G &g)
void demo_eulerian_cycle()
Main namespace for Aleph-w library functions.
DynList< T > maps(const C &c, Op op)
Classic map operation.
Arc of graph implemented with double-linked adjacency lists.
Node belonging to a graph implemented with a double linked adjacency list.
Filtered iterator of adjacent arcs of a node.
void test(unsigned long n, gsl_rng *r)
Generic graph and digraph implementations.