Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
percolation_example.C
Go to the documentation of this file.
1
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
204#include <iostream>
205#include <iomanip>
206#include <vector>
207#include <random>
208#include <chrono>
209#include <tpl_union.H>
210#include <tclap/CmdLine.h>
211
212using namespace std;
213using namespace Aleph;
214
222{
223private:
224 size_t n; // Grid size
225 vector<bool> open_sites; // true if site is open
226 Fixed_Relation uf; // Union-Find structure
227 size_t num_open; // Count of open sites
228
229 // Virtual nodes: top = n*n, bottom = n*n + 1
230 size_t virtual_top() const { return n * n; }
231 size_t virtual_bottom() const { return n * n + 1; }
232
233 // Convert (row, col) to linear index (0-based)
234 size_t index(size_t row, size_t col) const
235 {
236 return row * n + col;
237 }
238
239 // Check if (row, col) is valid
240 bool valid(size_t row, size_t col) const
241 {
242 return row < n && col < n;
243 }
244
245public:
250 : n(grid_size),
251 open_sites(n * n, false),
252 uf(n * n + 2), // n*n sites + 2 virtual nodes
253 num_open(0)
254 {
255 }
256
260 void open(size_t row, size_t col)
261 {
262 if (!valid(row, col) || is_open(row, col))
263 return;
264
265 size_t site = index(row, col);
266 open_sites[site] = true;
267 num_open++;
268
269 // Connect to adjacent open sites
270 const int dr[] = {-1, 1, 0, 0};
271 const int dc[] = {0, 0, -1, 1};
272
273 for (int i = 0; i < 4; i++)
274 {
275 size_t nr = row + dr[i];
276 size_t nc = col + dc[i];
277 if (valid(nr, nc) && is_open(nr, nc))
278 uf.join(site, index(nr, nc));
279 }
280
281 // Connect top row to virtual top
282 if (row == 0)
284
285 // Connect bottom row to virtual bottom
286 if (row == n - 1)
288 }
289
293 bool is_open(size_t row, size_t col) const
294 {
295 return valid(row, col) && open_sites[index(row, col)];
296 }
297
301 bool is_full(size_t row, size_t col)
302 {
303 if (!is_open(row, col))
304 return false;
305 return uf.are_connected(index(row, col), virtual_top());
306 }
307
312 {
314 }
315
319 size_t number_of_open_sites() const { return num_open; }
320
324 size_t size() const { return n; }
325
329 double open_fraction() const
330 {
331 return static_cast<double>(num_open) / (n * n);
332 }
333
339 void print() const
340 {
341 for (size_t row = 0; row < n; row++)
342 {
343 for (size_t col = 0; col < n; col++)
344 {
345 if (!is_open(row, col))
346 cout << "# ";
347 else if (const_cast<PercolationSystem*>(this)->is_full(row, col))
348 cout << "O ";
349 else
350 cout << ". ";
351 }
352 cout << endl;
353 }
354 }
355};
356
362double run_experiment(size_t n, mt19937& rng)
363{
365
366 // Create list of all sites and shuffle
368 for (size_t i = 0; i < n; i++)
369 for (size_t j = 0; j < n; j++)
370 sites.emplace_back(i, j);
371
373
374 // Open sites until percolation
375 for (const auto& [row, col] : sites)
376 {
377 perc.open(row, col);
378 if (perc.percolates())
379 break;
380 }
381
382 return perc.open_fraction();
383}
384
388void monte_carlo_simulation(size_t n, size_t trials, unsigned seed, bool verbose)
389{
390 cout << "\n=== Monte Carlo Percolation Threshold Estimation ===" << endl;
391 cout << "Grid size: " << n << "×" << n << endl;
392 cout << "Trials: " << trials << endl;
393 cout << "Seed: " << seed << endl;
394
395 mt19937 rng(seed);
396
397 vector<double> thresholds(trials);
398 double sum = 0, sum_sq = 0;
399
400 auto start = chrono::high_resolution_clock::now();
401
402 for (size_t t = 0; t < trials; t++)
403 {
404 double p = run_experiment(n, rng);
405 thresholds[t] = p;
406 sum += p;
407 sum_sq += p * p;
408
409 if (verbose && (t + 1) % (trials / 10) == 0)
410 cout << " Completed " << (t + 1) << "/" << trials << " trials..." << endl;
411 }
412
413 auto end = chrono::high_resolution_clock::now();
414 double ms = chrono::duration<double, milli>(end - start).count();
415
416 // Statistics
417 double mean = sum / trials;
418 double variance = (sum_sq - sum * sum / trials) / (trials - 1);
419 double stddev = sqrt(variance);
420 double confidence_95 = 1.96 * stddev / sqrt(trials);
421
422 cout << "\n--- Results ---" << endl;
423 cout << "Sample mean: " << fixed << setprecision(6) << mean << endl;
424 cout << "Sample standard deviation: " << stddev << endl;
425 cout << "95% confidence interval: ["
426 << (mean - confidence_95) << ", "
427 << (mean + confidence_95) << "]" << endl;
428 cout << "\nTheoretical p* ≈ 0.592746" << endl;
429 cout << "Difference from theory: " << abs(mean - 0.592746) << endl;
430 cout << "\nTime: " << setprecision(2) << ms << " ms" << endl;
431}
432
436void visual_demonstration(size_t n, unsigned seed)
437{
438 cout << "\n=== Visual Percolation Demo ===" << endl;
439 cout << "Grid size: " << n << "×" << n << endl;
440
442 mt19937 rng(seed);
443
444 // Shuffle sites
446 for (size_t i = 0; i < n; i++)
447 for (size_t j = 0; j < n; j++)
448 sites.emplace_back(i, j);
450
451 cout << "\nLegend: # = blocked, . = open (not full), O = full (connected to top)" << endl;
452
453 // Show progression
454 vector<double> checkpoints = {0.2, 0.4, 0.5, 0.55, 0.6, 0.65, 0.7};
455 size_t site_idx = 0;
456 size_t total_sites = n * n;
457
458 for (double target : checkpoints)
459 {
460 size_t target_open = static_cast<size_t>(target * total_sites);
461
462 while (perc.number_of_open_sites() < target_open && site_idx < sites.size())
463 {
464 auto [row, col] = sites[site_idx++];
465 perc.open(row, col);
466 }
467
468 cout << "\n--- " << fixed << setprecision(0) << (target * 100)
469 << "% sites open (" << perc.number_of_open_sites() << "/" << total_sites
470 << ") ---" << endl;
471 perc.print();
472
473 if (perc.percolates())
474 {
475 cout << "\n*** SYSTEM PERCOLATES at p = "
476 << setprecision(3) << perc.open_fraction() << " ***" << endl;
477 break;
478 }
479 else
480 {
481 cout << "(Does not percolate yet)" << endl;
482 }
483 }
484
485 // If not percolated yet, continue until it does
486 if (!perc.percolates())
487 {
488 while (!perc.percolates() && site_idx < sites.size())
489 {
490 auto [row, col] = sites[site_idx++];
491 perc.open(row, col);
492 }
493
494 cout << "\n--- Percolation achieved ---" << endl;
495 perc.print();
496 cout << "\n*** SYSTEM PERCOLATES at p = "
497 << setprecision(3) << perc.open_fraction() << " ***" << endl;
498 }
499}
500
505{
506 cout << "\n=== Union-Find Data Structure ===" << endl;
507
508 cout << "\nThe Union-Find (Disjoint Set Union) structure supports:" << endl;
509 cout << " - make_set(x): Create a new set containing only x" << endl;
510 cout << " - find(x): Return the representative of x's set" << endl;
511 cout << " - union(x, y): Merge the sets containing x and y" << endl;
512
513 cout << "\nOptimizations:" << endl;
514 cout << " - Path compression: During find(), make nodes point directly to root" << endl;
515 cout << " - Union by rank: Attach smaller tree under larger tree's root" << endl;
516
517 cout << "\nComplexity (with both optimizations):" << endl;
518 cout << " - Nearly O(1) per operation (amortized)" << endl;
519 cout << " - Formally: O(α(n)) where α is inverse Ackermann function" << endl;
520 cout << " - For all practical n: α(n) ≤ 4" << endl;
521
522 cout << "\nApplication in Percolation:" << endl;
523 cout << " - Each grid cell is an element" << endl;
524 cout << " - Opening a cell: union with adjacent open cells" << endl;
525 cout << " - Percolation test: are top and bottom connected?" << endl;
526 cout << " - Virtual nodes simplify: virtual_top connected to all top row sites" << endl;
527}
528
529int main(int argc, char* argv[])
530{
531 try
532 {
533 TCLAP::CmdLine cmd("Percolation Example with Union-Find", ' ', "1.0");
534
535 TCLAP::ValueArg<size_t> sizeArg("n", "size",
536 "Grid size", false, 20, "size_t");
537 TCLAP::ValueArg<size_t> trialsArg("t", "trials",
538 "Number of Monte Carlo trials", false, 100, "size_t");
539 TCLAP::ValueArg<unsigned> seedArg("s", "seed",
540 "Random seed", false, 42, "unsigned");
541 TCLAP::SwitchArg visualArg("i", "visual",
542 "Show visual demonstration", false);
543 TCLAP::SwitchArg monteArg("m", "monte-carlo",
544 "Run Monte Carlo simulation", false);
545 TCLAP::SwitchArg explainArg("e", "explain",
546 "Explain Union-Find", false);
547 TCLAP::SwitchArg allArg("a", "all",
548 "Run all demos", false);
549 TCLAP::SwitchArg verboseArg("v", "verbose",
550 "Show detailed output", false);
551
552 cmd.add(sizeArg);
553 cmd.add(trialsArg);
554 cmd.add(seedArg);
555 cmd.add(visualArg);
556 cmd.add(monteArg);
557 cmd.add(explainArg);
558 cmd.add(allArg);
559 cmd.add(verboseArg);
560
561 cmd.parse(argc, argv);
562
563 size_t n = sizeArg.getValue();
564 size_t trials = trialsArg.getValue();
565 unsigned seed = seedArg.getValue();
566 bool visual = visualArg.getValue();
567 bool monte = monteArg.getValue();
568 bool explain = explainArg.getValue();
569 bool all = allArg.getValue();
570 bool verbose = verboseArg.getValue();
571
572 // Default: show visual and explain
573 if (!visual && !monte && !explain)
574 all = true;
575
576 cout << "=== Percolation: A Union-Find Application ===" << endl;
577
578 if (all || explain)
580
581 if (all || visual)
582 {
583 // Use smaller grid for visual demo
584 size_t visual_size = min(n, (size_t)15);
586 }
587
588 if (all || monte)
590
591 cout << "\n=== Summary ===" << endl;
592 cout << "Percolation threshold for 2D square lattice:" << endl;
593 cout << " Theoretical: p* ≈ 0.592746" << endl;
594 cout << " (Critical probability at which infinite cluster appears)" << endl;
595 cout << "\nUnion-Find enables efficient connectivity queries:" << endl;
596 cout << " O(α(n)) per operation ≈ O(1) in practice" << endl;
597
598 return 0;
599 }
600 catch (TCLAP::ArgException& e)
601 {
602 cerr << "Error: " << e.error() << " for arg " << e.argId() << endl;
603 return 1;
604 }
605}
606
int main()
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
Binary relation between a set of integers.
Definition tpl_union.H:82
void join(size_t i, size_t j)
Insert the pair '(i,j)' in the relation.
Definition tpl_union.H:198
bool are_connected(size_t i, size_t j)
Return true if item i is related to item j.
Definition tpl_union.H:187
Percolation system using Union-Find.
PercolationSystem(size_t grid_size)
Create an n×n percolation system with all sites blocked.
size_t index(size_t row, size_t col) const
double open_fraction() const
Get fraction of open sites.
bool is_open(size_t row, size_t col) const
Check if site at (row, col) is open.
void open(size_t row, size_t col)
Open a site at (row, col) and connect to adjacent open sites.
void print() const
Print the grid (for small grids)
bool is_full(size_t row, size_t col)
Check if site at (row, col) is connected to top (is "full")
vector< bool > open_sites
size_t virtual_bottom() const
size_t size() const
Get grid size.
size_t number_of_open_sites() const
Get number of open sites.
size_t virtual_top() const
bool valid(size_t row, size_t col) const
bool percolates()
Check if system percolates (top connected to bottom)
iterator end() noexcept
Return an STL-compatible end iterator.
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
static mt19937 rng
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_sqrt_function > > sqrt(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4058
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_abs_function > > abs(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4051
__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
bool all(Container &container, Operation &operation)
Return true if all elements satisfy a predicate.
auto variance(const Container &data, bool population=false) -> std::decay_t< decltype(*std::begin(data))>
Compute variance using Welford's numerically stable algorithm.
Definition stat_utils.H:215
auto stddev(const Container &data, bool population=false) -> std::decay_t< decltype(*std::begin(data))>
Compute standard deviation.
Definition stat_utils.H:257
auto mean(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute the arithmetic mean.
Definition stat_utils.H:183
auto shuffle(const C< T > &c)
Randomly shuffle a sequence.
bool verbose
Flag enabling verbose output.
Definition ahDefs.C:45
DynList< T > maps(const C &c, Op op)
Classic map operation.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
STL namespace.
void monte_carlo_simulation(size_t n, size_t trials, unsigned seed, bool verbose)
Monte Carlo estimation of percolation threshold.
double run_experiment(size_t n, mt19937 &rng)
Run a single percolation experiment.
void explain_union_find()
Explain Union-Find operations.
void visual_demonstration(size_t n, unsigned seed)
Interactive demonstration with visualization.
Union-Find (Disjoint Set Union) data structure.