Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
random_graph_example.C
Go to the documentation of this file.
1
171#include <iostream>
172#include <iomanip>
173#include <string>
174
175#include <tclap/CmdLine.h>
176
177#include <tpl_graph.H>
178#include <random_graph.H>
179#include <tpl_components.H>
180#include <eulerian.H>
181
182using namespace std;
183using namespace Aleph;
184
185// Graph types
190
191// =============================================================================
192// Helper functions
193// =============================================================================
194
195void print_section(const string& title)
196{
197 cout << "\n" << string(60, '=') << "\n";
198 cout << " " << title << "\n";
199 cout << string(60, '=') << "\n\n";
200}
201
202void print_subsection(const string& title)
203{
204 cout << "\n--- " << title << " ---\n";
205}
206
207template <typename G>
208void print_graph_stats(const string& label, G& g)
209{
210 cout << label << ":" << endl;
211 cout << " Vertices: " << g.get_num_nodes() << endl;
212 cout << " Edges: " << g.get_num_arcs() << endl;
213
214 // Calculate average degree
215 double total_degree = 0;
216 size_t min_deg = numeric_limits<size_t>::max();
217 size_t max_deg = 0;
218
219 for (auto it = g.get_node_it(); it.has_curr(); it.next())
220 {
221 size_t deg = 0;
222 for (Node_Arc_Iterator<G> ait(it.get_curr()); ait.has_curr(); ait.next())
223 deg++;
224 total_degree += deg;
227 }
228
229 double avg_deg = total_degree / g.get_num_nodes();
230 cout << " Avg degree: " << fixed << setprecision(2) << avg_deg << endl;
231 cout << " Min degree: " << min_deg << endl;
232 cout << " Max degree: " << max_deg << endl;
233}
234
235// =============================================================================
236// 1. Erdős–Rényi Random Graph
237// =============================================================================
238
240{
241 print_section("ERDŐS-RÉNYI RANDOM GRAPH G(n,m)");
242
243 cout << "Generate a graph with n vertices and m random edges.\n";
244 cout << "Edges are placed uniformly at random.\n\n";
245
246 size_t n = 20; // vertices
247 size_t m = 40; // edges
248
249 cout << "Parameters: n=" << n << " vertices, m=" << m << " edges\n";
250
251 // Create random graph generator
252 Random_Graph<UGraph> gen(time(nullptr));
253
254 // Generate graph
255 print_subsection("Generated graph");
256 UGraph g = gen(n, m, false);
257
258 print_graph_stats("G(" + to_string(n) + "," + to_string(m) + ")", g);
259
260 // Check connectivity
261 print_subsection("Connectivity analysis");
262
266
267 cout << "Number of connected components: " << subgraphs.size() << endl;
268
269 if (subgraphs.size() == 1)
270 cout << "Graph is CONNECTED\n";
271 else
272 {
273 cout << "Graph is DISCONNECTED\n";
274 cout << "Component sizes: ";
275 for (auto it = subgraphs.get_it(); it.has_curr(); it.next())
276 cout << it.get_curr().get_num_nodes() << " ";
277 cout << endl;
278 }
279
280 // Density
281 double density = 2.0 * m / (n * (n - 1));
282 cout << "\nGraph density: " << fixed << setprecision(4) << density << endl;
283 cout << "(1.0 = complete graph, 0.0 = no edges)\n";
284}
285
286// =============================================================================
287// 2. Connected Random Graph
288// =============================================================================
289
291{
292 print_section("CONNECTED RANDOM GRAPH");
293
294 cout << "Generate a random graph and then force connectivity (if needed).\n";
295 cout << "This demo requests a connected graph from the generator.\n\n";
296
297 size_t n = 20;
298 size_t m = n * 3; // Dense: 3 edges per vertex on average
299
300 cout << "Parameters: n=" << n << " vertices, m=" << m << " edges\n";
301 cout << "(Reference threshold for connectivity in G(n,m): ~n*ln(n)/2 = "
302 << (size_t)(n * log(n) / 2) << ")\n";
303
304 Random_Graph<UGraph> gen(time(nullptr));
305
306 // Generate dense graph
307 print_subsection("Generated dense graph");
308 UGraph g = gen(n, m, true);
309
310 print_graph_stats("Dense G", g);
311
312 // Verify connectivity
316
317 cout << "\nConnected components: " << subgraphs.size() << endl;
318 if (subgraphs.size() == 1)
319 cout << "Graph is CONNECTED (as expected for dense graphs)\n";
320 else
321 cout << "Graph is disconnected (rare for this density)\n";
322}
323
324// =============================================================================
325// 3. Eulerian Random Graph
326// =============================================================================
327
329{
330 print_section("EULERIAN RANDOM GRAPH");
331
332 cout << "Generate a random graph where all vertices have even degree.\n";
333 cout << "Such a graph has an Eulerian cycle.\n\n";
334
335 size_t n = 15;
336 size_t m = 30;
337
338 cout << "Parameters: n=" << n << " vertices, m=" << m << " edges\n";
339
340 Random_Graph<UGraph> gen(time(nullptr));
341
342 // Generate Eulerian graph
343 print_subsection("Generated Eulerian graph");
344 UGraph g = gen.eulerian(n, m);
345
346 print_graph_stats("Eulerian G", g);
347
348 // Check all degrees are even
349 print_subsection("Degree verification");
350
351 bool all_even = true;
352 cout << "Vertex degrees: ";
353 for (auto it = g.get_node_it(); it.has_curr(); it.next())
354 {
355 size_t deg = 0;
356 for (Node_Arc_Iterator<UGraph> ait(it.get_curr()); ait.has_curr(); ait.next())
357 deg++;
358
359 if (deg % 2 != 0) all_even = false;
360 }
361 cout << "(checking...)" << endl;
362
363 cout << "All degrees even? " << (all_even ? "YES" : "NO") << endl;
364
365 // Verify with Test_Eulerian
367 cout << "Is Eulerian (Test_Eulerian)? " << (test(g) ? "YES" : "NO") << endl;
368}
369
370// =============================================================================
371// 4. Random Digraph
372// =============================================================================
373
375{
376 print_section("RANDOM DIRECTED GRAPH");
377
378 cout << "Generate random directed graphs (digraphs).\n\n";
379
380 size_t n = 15;
381 size_t m = 40;
382
383 cout << "Parameters: n=" << n << " vertices, m=" << m << " arcs\n";
384
386
387 // Generate random digraph
388 print_subsection("Generated digraph");
389 DGraph g = gen(n, m, false);
390
391 cout << "Digraph statistics:" << endl;
392 cout << " Vertices: " << g.get_num_nodes() << endl;
393 cout << " Arcs: " << g.get_num_arcs() << endl;
394
395 // Analyze in/out degrees
396 print_subsection("Degree analysis");
397
398 size_t total_out = 0;
399 size_t max_out = 0;
400
401 for (auto it = g.get_node_it(); it.has_curr(); it.next())
402 {
403 size_t out_deg = 0;
404 for (Node_Arc_Iterator<DGraph> ait(it.get_curr()); ait.has_curr(); ait.next())
405 out_deg++;
408 }
409
410 cout << "Average out-degree: " << fixed << setprecision(2)
411 << (double)total_out / n << endl;
412 cout << "Max out-degree: " << max_out << endl;
413}
414
415// =============================================================================
416// 5. Eulerian Random Digraph
417// =============================================================================
418
420{
421 print_section("EULERIAN RANDOM DIGRAPH");
422
423 cout << "Generate a random digraph where in-degree = out-degree for all.\n";
424 cout << "(Has an Eulerian cycle)\n\n";
425
426 size_t n = 12;
427 size_t m = 30;
428
429 cout << "Parameters: n=" << n << " vertices, m=" << m << " arcs\n";
430
432
433 // Generate Eulerian digraph
434 print_subsection("Generated Eulerian digraph");
435 DGraph g = gen.eulerian(n, m);
436
437 cout << "Digraph statistics:" << endl;
438 cout << " Vertices: " << g.get_num_nodes() << endl;
439 cout << " Arcs: " << g.get_num_arcs() << endl;
440
441 // Verify Eulerian property
442 print_subsection("Verification (in-degree = out-degree)");
443
445 cout << "Is Eulerian (Test_Eulerian)? " << (test(g) ? "YES" : "NO") << endl;
446}
447
448// =============================================================================
449// 6. Parameter Study
450// =============================================================================
451
453{
454 print_section("PARAMETER STUDY");
455
456 cout << "How does edge count affect connectivity?\n\n";
457
458 size_t n = 20;
459 size_t trials = 10;
460
461 cout << "n = " << n << " vertices, " << trials << " trials each\n\n";
462
463 cout << setw(10) << "Edges" << setw(15) << "Density"
464 << setw(20) << "Avg Components" << setw(15) << "% Connected" << endl;
465 cout << string(60, '-') << endl;
466
467 Random_Graph<UGraph> gen(time(nullptr));
468
469 for (size_t m = n/2; m <= n*3; m += n/2)
470 {
471 size_t total_components = 0;
472 size_t connected_count = 0;
473
474 for (size_t t = 0; t < trials; t++)
475 {
476 UGraph g = gen(n, m, false);
477
480 ic(g, comps);
481
483 if (comps.size() == 1) connected_count++;
484 }
485
486 double density = 2.0 * m / (n * (n - 1));
488 double pct_connected = 100.0 * connected_count / trials;
489
490 cout << setw(10) << m
491 << setw(15) << fixed << setprecision(3) << density
492 << setw(20) << setprecision(1) << avg_comps
493 << setw(14) << setprecision(0) << pct_connected << "%" << endl;
494 }
495
496 cout << "\nNote: Connectivity threshold is around m ≈ n*ln(n)/2 ≈ "
497 << (size_t)(n * log(n) / 2) << " edges\n";
498}
499
500// =============================================================================
501// Main
502// =============================================================================
503
504int main(int argc, char* argv[])
505{
506 try
507 {
508 TCLAP::CmdLine cmd(
509 "Random graph generation example for Aleph-w.\n"
510 "Demonstrates various random graph models.",
511 ' ', "1.0"
512 );
513
514 TCLAP::ValueArg<string> sectionArg(
515 "s", "section",
516 "Run only specific section: erdos, connected, eulerian, digraph, "
517 "eulerian_dig, params, or 'all'",
518 false, "all", "section", cmd
519 );
520
521 cmd.parse(argc, argv);
522
523 string section = sectionArg.getValue();
524
525 cout << "\n";
526 cout << "============================================================\n";
527 cout << " ALEPH-W RANDOM GRAPH GENERATION EXAMPLE\n";
528 cout << "============================================================\n";
529
530 if (section == "all" or section == "erdos")
532
533 if (section == "all" or section == "connected")
535
536 if (section == "all" or section == "eulerian")
538
539 if (section == "all" or section == "digraph")
540 demo_digraph();
541
542 if (section == "all" or section == "eulerian_dig")
544
545 if (section == "all" or section == "params")
547
548 cout << "\n" << string(60, '=') << "\n";
549 cout << "Random graph generation demo completed!\n";
550 cout << string(60, '=') << "\n\n";
551
552 return 0;
553 }
554 catch (TCLAP::ArgException& e)
555 {
556 cerr << "Error: " << e.error() << " for argument " << e.argId() << endl;
557 return 1;
558 }
559 catch (exception& e)
560 {
561 cerr << "Error: " << e.what() << endl;
562 return 1;
563 }
564}
int main()
WeightedDigraph::Node Node
WeightedDigraph::Arc Arc
Generic directed graph (digraph) wrapper template.
Definition graph-dry.H:3848
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
Graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:428
Random directed graph (digraph) generator.
Random undirected graph generator.
Tests whether a graph or digraph is Eulerian.
Definition eulerian.H:171
Compute the connected components of a graph.
auto get_node_it() const noexcept
Obtains an iterator to the nodes of graph.
Definition graph-dry.H:2780
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:190
Eulerian graph detection and path/cycle finding.
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_max_function > > max(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4110
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_log_function > > log(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4063
__gmp_expr< typename __gmp_resolve_expr< T, V >::value_type, __gmp_binary_expr< __gmp_expr< T, U >, __gmp_expr< V, W >, __gmp_min_function > > min(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4111
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
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
DynList< T > maps(const C &c, Op op)
Classic map operation.
STL namespace.
Random graph generation utilities.
void print_subsection(const string &title)
void print_section(const string &title)
void demo_eulerian()
void demo_connected()
void demo_erdos_renyi()
void demo_parameters()
void demo_eulerian_digraph()
void print_graph_stats(const string &label, G &g)
void demo_digraph()
Arc of graph implemented with double-linked adjacency lists.
Definition tpl_graph.H:222
Node belonging to a graph implemented with a double linked adjacency list.
Definition tpl_graph.H:121
Filtered iterator of adjacent arcs of a node.
Definition tpl_graph.H:1119
void test(unsigned long n, gsl_rng *r)
Graph connectivity and connected components.
Generic graph and digraph implementations.