Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_ca_stochastic_rules.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
63#ifndef TPL_CA_STOCHASTIC_RULES_H
64#define TPL_CA_STOCHASTIC_RULES_H
65
66#include <cmath>
67#include <cstddef>
68#include <cstdint>
69#include <random>
70#include <type_traits>
71
72#include <ah-errors.H>
73
74#include <ca-rng.H>
75#include <ca-traits.H>
76
77namespace Aleph {
78namespace CA {
79
80// -----------------------------------------------------------------------
81// Forest fire rule (Drossel-Schwabl)
82// -----------------------------------------------------------------------
83
89enum class Forest_Cell : std::uint8_t
90{
91 EMPTY = 0,
92 TREE = 1,
93 BURNING = 2
94};
95
113template <typename Engine = std::mt19937_64>
115{
116 double p_growth_;
118 std::uint64_t master_seed_;
119
120public:
123
133 Forest_Fire_Rule(const double p_growth, const double p_lightning, std::uint64_t master_seed = 0)
135 {
137 << "Forest_Fire_Rule: p_growth=" << p_growth << " outside [0, 1]";
139 << "Forest_Fire_Rule: p_lightning=" << p_lightning << " outside [0, 1]";
140 }
141
144 {
145 return p_growth_;
146 }
147
150 {
151 return p_lightning_;
152 }
153
156 {
157 return master_seed_;
158 }
159
161 void set_master_seed(std::uint64_t s) noexcept
162 {
163 master_seed_ = s;
164 }
165
177 template <typename State, std::size_t Rank>
178 [[nodiscard]] State operator()(const State &current,
179 Neighbor_View<State> neighbours,
180 const Cell_Context<Rank> &ctx) const
181 {
182 const auto cur = static_cast<int>(current);
183
184 if (cur == static_cast<int>(Forest_Cell::BURNING))
185 return static_cast<State>(Forest_Cell::EMPTY);
186
187 if (cur == static_cast<int>(Forest_Cell::TREE))
188 {
189 for (const auto &n : neighbours)
190 if (static_cast<int>(n) == static_cast<int>(Forest_Cell::BURNING))
191 return static_cast<State>(Forest_Cell::BURNING);
192
193 if (p_lightning_ > 0.0)
194 {
195 Engine eng{static_cast<typename Engine::result_type>(cell_seed<Rank>(master_seed_, ctx))};
197 return static_cast<State>(Forest_Cell::BURNING);
198 }
199 return static_cast<State>(Forest_Cell::TREE);
200 }
201
202 // EMPTY
203 if (p_growth_ > 0.0)
204 {
205 Engine eng{static_cast<typename Engine::result_type>(cell_seed<Rank>(master_seed_, ctx))};
207 return static_cast<State>(Forest_Cell::TREE);
208 }
209 return static_cast<State>(Forest_Cell::EMPTY);
210 }
211};
212
213// -----------------------------------------------------------------------
214// SIR rule
215// -----------------------------------------------------------------------
216
218enum class SIR_Cell : std::uint8_t
219{
220 S = 0,
221 I = 1,
222 R = 2
223};
224
240template <typename Engine = std::mt19937_64>
242{
243 double beta_;
244 double gamma_;
245 std::uint64_t master_seed_;
246
247public:
249
259 SIR_Rule(double beta, double gamma, std::uint64_t master_seed = 0)
261 {
262 ah_domain_error_if(beta < 0.0 or beta > 1.0) << "SIR_Rule: beta=" << beta << " outside [0, 1]";
264 << "SIR_Rule: gamma=" << gamma << " outside [0, 1]";
265 }
266
269 {
270 return beta_;
271 }
272
275 {
276 return gamma_;
277 }
278
281 {
282 return master_seed_;
283 }
284
286 void set_master_seed(std::uint64_t s) noexcept
287 {
288 master_seed_ = s;
289 }
290
302 template <typename State, std::size_t Rank>
303 [[nodiscard]] State operator()(const State &current,
304 Neighbor_View<State> neighbours,
305 const Cell_Context<Rank> &ctx) const
306 {
307 const auto cur = static_cast<int>(current);
308 if (cur == static_cast<int>(SIR_Cell::R))
309 return current;
310
311 if (cur == static_cast<int>(SIR_Cell::I))
312 {
313 if (gamma_ <= 0.0)
314 return current;
315 Engine eng{static_cast<typename Engine::result_type>(cell_seed<Rank>(master_seed_, ctx))};
316 return uniform_unit(eng) < gamma_ ? static_cast<State>(SIR_Cell::R) : current;
317 }
318
319 // S
320 std::size_t infected = 0;
321 for (const auto &n : neighbours)
322 if (static_cast<int>(n) == static_cast<int>(SIR_Cell::I))
323 ++infected;
324
325 if (infected == 0 or beta_ <= 0.0)
326 return current;
327
328 const double survive = std::pow(1.0 - beta_, static_cast<double>(infected));
329 const double infect_prob = 1.0 - survive;
330
331 Engine eng{static_cast<typename Engine::result_type>(cell_seed<Rank>(master_seed_, ctx))};
332 return uniform_unit(eng) < infect_prob ? static_cast<State>(SIR_Cell::I) : current;
333 }
334};
335
336// -----------------------------------------------------------------------
337// Ising-style rules
338// -----------------------------------------------------------------------
339
340namespace ca_ising_detail {
341
345template <typename State>
346[[nodiscard]] inline int state_to_spin(const State &v) noexcept
347{
348 if constexpr (std::is_signed_v<State>)
349 return v >= State{0} ? +1 : -1;
350 else
351 return v != State{} ? +1 : -1;
352}
353
356template <typename State>
357[[nodiscard]] inline State spin_to_state(int spin) noexcept
358{
359 if constexpr (std::is_signed_v<State>)
360 return spin > 0 ? static_cast<State>(1) : static_cast<State>(-1);
361 else
362 return spin > 0 ? static_cast<State>(1) : static_cast<State>(0);
363}
364
366template <typename State>
367[[nodiscard]] inline double delta_energy(const State &current,
368 Neighbor_View<State> neighbours,
369 double J,
370 double H)
371{
372 const int s = state_to_spin(current);
373 long long sum = 0;
374 for (const auto &n : neighbours)
375 sum += state_to_spin(n);
376 return 2.0 * static_cast<double>(s) * (J * static_cast<double>(sum) + H);
377}
378
379} // namespace ca_ising_detail
380
398template <typename Engine = std::mt19937_64>
400{
401 double T_;
402 double J_;
403 double H_;
404 std::uint64_t master_seed_;
405
406public:
408
417 Ising_Glauber_Rule(const double T,
418 const double J = 1.0,
419 const double H = 0.0,
420 const std::uint64_t master_seed = 0)
421 : T_(T), J_(J), H_(H), master_seed_(master_seed)
422 {
423 ah_domain_error_if(T <= 0.0) << "Ising_Glauber_Rule: temperature must be positive, got " << T;
424 }
425
427 {
428 return T_;
429 }
430
432 {
433 return J_;
434 }
435
437 {
438 return H_;
439 }
440
442 {
443 return master_seed_;
444 }
445
446 void set_master_seed(std::uint64_t s) noexcept
447 {
448 master_seed_ = s;
449 }
450
460 template <typename State, std::size_t Rank>
461 [[nodiscard]] State operator()(const State &current,
462 Neighbor_View<State> neighbours,
463 const Cell_Context<Rank> &ctx) const
464 {
465 const double dE = ca_ising_detail::delta_energy(current, neighbours, J_, H_);
466 // Numerically stable Fermi function 1 / (1 + exp(dE / T)):
467 // for dE >= 0 we compute 1 / (1 + exp(dE/T));
468 // for dE < 0 we use exp(-dE/T) / (1 + exp(-dE/T))
469 const double x = dE / T_;
470 const double p_flip = x >= 0.0 ? 1.0 / (1.0 + std::exp(x)) : std::exp(-x) / (1.0 + std::exp(-x));
471
472 if (Engine eng{static_cast<typename Engine::result_type>(cell_seed<Rank>(master_seed_, ctx))};
474 return ca_ising_detail::spin_to_state<State>(-ca_ising_detail::state_to_spin(current));
475 return current;
476 }
477};
478
488template <typename Engine = std::mt19937_64>
490{
491 double T_;
492 double J_;
493 double H_;
494 std::uint64_t master_seed_;
495
496public:
498
508 const double J = 1.0,
509 const double H = 0.0,
510 const std::uint64_t master_seed = 0)
511 : T_(T), J_(J), H_(H), master_seed_(master_seed)
512 {
513 ah_domain_error_if(T <= 0.0) << "Ising_Metropolis_Rule: temperature must be positive, got " << T;
514 }
515
517 {
518 return T_;
519 }
520
522 {
523 return J_;
524 }
525
527 {
528 return H_;
529 }
530
532 {
533 return master_seed_;
534 }
535
536 void set_master_seed(std::uint64_t s) noexcept
537 {
538 master_seed_ = s;
539 }
540
550 template <typename State, std::size_t Rank>
551 [[nodiscard]] State operator()(const State &current,
552 Neighbor_View<State> neighbours,
553 const Cell_Context<Rank> &ctx) const
554 {
555 const double dE = ca_ising_detail::delta_energy(current, neighbours, J_, H_);
556 if (dE <= 0.0)
557 return ca_ising_detail::spin_to_state<State>(-ca_ising_detail::state_to_spin(current));
558
559 const double p_flip = std::exp(-dE / T_);
560 if (Engine eng{static_cast<typename Engine::result_type>(cell_seed<Rank>(master_seed_, ctx))};
562 return ca_ising_detail::spin_to_state<State>(-ca_ising_detail::state_to_spin(current));
563 return current;
564 }
565};
566
567// -----------------------------------------------------------------------
568// Schelling segregation rule
569// -----------------------------------------------------------------------
570
572enum class Schelling_Cell : std::uint8_t
573{
574 EMPTY = 0,
575 TYPE_A = 1,
576 TYPE_B = 2
577};
578
602template <typename Engine = std::mt19937_64>
604{
606 double p_move_;
607 double p_fill_;
608 std::uint64_t master_seed_;
609
610public:
612
626 const double p_move = 1.0,
627 const double p_fill = 1.0,
628 const std::uint64_t master_seed = 0)
630 {
632 << "Schelling_Rule: threshold=" << threshold << " outside [0, 1]";
634 << "Schelling_Rule: p_move=" << p_move << " outside [0, 1]";
636 << "Schelling_Rule: p_fill=" << p_fill << " outside [0, 1]";
637 }
638
640 {
641 return threshold_;
642 }
643
645 {
646 return p_move_;
647 }
648
650 {
651 return p_fill_;
652 }
653
655 {
656 return master_seed_;
657 }
658
659 void set_master_seed(std::uint64_t s) noexcept
660 {
661 master_seed_ = s;
662 }
663
668 template <typename State, std::size_t Rank>
669 [[nodiscard]] State operator()(const State &current,
670 Neighbor_View<State> neighbours,
671 const Cell_Context<Rank> &ctx) const
672 {
673 std::size_t a = 0, b = 0;
674 for (const auto &n : neighbours)
675 if (const auto x = static_cast<int>(n); x == static_cast<int>(Schelling_Cell::TYPE_A))
676 ++a;
677 else if (x == static_cast<int>(Schelling_Cell::TYPE_B))
678 ++b;
679
680 const auto cur = static_cast<int>(current);
681
682 if (cur == static_cast<int>(Schelling_Cell::EMPTY))
683 {
684 if (a == b or p_fill_ <= 0.0)
685 return current;
686 if (Engine eng{static_cast<typename Engine::result_type>(cell_seed<Rank>(master_seed_, ctx))};
688 return a > b ? static_cast<State>(Schelling_Cell::TYPE_A)
689 : static_cast<State>(Schelling_Cell::TYPE_B);
690 return current;
691 }
692
693 const std::size_t total = a + b;
694 if (total == 0)
695 return current; // Isolated agent: no peer pressure either way.
696
697 const std::size_t same = (cur == static_cast<int>(Schelling_Cell::TYPE_A)) ? a : b;
698
699 if (const double fraction = static_cast<double>(same) / static_cast<double>(total);
700 fraction >= threshold_ or p_move_ <= 0.0)
701 return current;
702
703 if (Engine eng{static_cast<typename Engine::result_type>(cell_seed<Rank>(master_seed_, ctx))};
705 return static_cast<State>(Schelling_Cell::EMPTY);
706 return current;
707 }
708};
709
710} // namespace CA
711} // namespace Aleph
712
713#endif // TPL_CA_STOCHASTIC_RULES_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
Reproducible random-number support for stochastic CA rules (Phase 8).
Common typedefs and tag types for the Cellular Automata module.
Forest-fire rule (Drossel & Schwabl, 1992).
std::uint64_t master_seed() const noexcept
void set_master_seed(std::uint64_t s) noexcept
Replace the master seed; takes effect on the next step.
Engine engine_type
Underlying RNG engine type.
Forest_Fire_Rule(const double p_growth, const double p_lightning, std::uint64_t master_seed=0)
Build a forest-fire rule with the given probabilities.
double p_lightning() const noexcept
State operator()(const State &current, Neighbor_View< State > neighbours, const Cell_Context< Rank > &ctx) const
Compute the next forest-fire state for cell current.
Ising rule with Glauber single-spin-flip dynamics.
Ising_Glauber_Rule(const double T, const double J=1.0, const double H=0.0, const std::uint64_t master_seed=0)
Build a Glauber Ising rule.
void set_master_seed(std::uint64_t s) noexcept
std::uint64_t master_seed() const noexcept
State operator()(const State &current, Neighbor_View< State > neighbours, const Cell_Context< Rank > &ctx) const
Compute the next Ising state for cell current.
Ising rule with Metropolis–Hastings single-spin-flip dynamics.
std::uint64_t master_seed() const noexcept
State operator()(const State &current, Neighbor_View< State > neighbours, const Cell_Context< Rank > &ctx) const
Compute the next Ising state for cell current (Metropolis dynamics).
Ising_Metropolis_Rule(const double T, const double J=1.0, const double H=0.0, const std::uint64_t master_seed=0)
Build a Metropolis Ising rule.
void set_master_seed(std::uint64_t s) noexcept
SIR epidemic transition rule.
std::uint64_t master_seed() const noexcept
void set_master_seed(std::uint64_t s) noexcept
Replace the master seed.
double gamma() const noexcept
SIR_Rule(double beta, double gamma, std::uint64_t master_seed=0)
Build an SIR rule with infection rate beta and recovery rate gamma.
State operator()(const State &current, Neighbor_View< State > neighbours, const Cell_Context< Rank > &ctx) const
Compute the next SIR state for cell current.
double beta() const noexcept
Local approximation of the Schelling segregation model.
double threshold() const noexcept
State operator()(const State &current, Neighbor_View< State > neighbours, const Cell_Context< Rank > &ctx) const
Compute the next Schelling state for cell current.
std::uint64_t master_seed() const noexcept
void set_master_seed(std::uint64_t s) noexcept
Schelling_Rule(const double threshold, const double p_move=1.0, const double p_fill=1.0, const std::uint64_t master_seed=0)
Build a Schelling rule.
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
double delta_energy(const State &current, Neighbor_View< State > neighbours, double J, double H)
Compute the local energy delta for flipping the centre spin.
State spin_to_state(int spin) noexcept
Inverse of state_to_spin.
int state_to_spin(const State &v) noexcept
Map any integral state to a spin in {-1, +1}.
Forest_Cell
Discrete states of the forest-fire automaton.
@ EMPTY
Empty ground cell.
@ TREE
Healthy tree.
@ BURNING
Tree currently on fire (lasts exactly one step).
SIR_Cell
Discrete states of the SIR automaton.
@ S
Susceptible.
@ I
Infected (and infectious).
@ R
Recovered (and immune).
std::span< const T > Neighbor_View
Read-only view over a contiguous range of neighbour values.
Definition ca-traits.H:90
Schelling_Cell
Discrete states of the Schelling automaton.
@ TYPE_A
Agent of type A.
@ TYPE_B
Agent of type B.
double uniform_unit(Engine &eng)
Map a 64-bit RNG output to a uniform value in [0, 1).
Definition ca-rng.H:206
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Per-cell context handed to rules that need to know "where" and "when" they are firing.
Definition ca-traits.H:106