Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ca_predator_prey_multifield_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
34#include <charconv>
35#include <cstddef>
36#include <cstdint>
37#include <cstring>
38#include <iostream>
39#include <limits>
40#include <stdexcept>
41#include <string>
42#include <string_view>
43#include <system_error>
44#include <tuple>
45
46#include <ca-traits.H>
49#include <tpl_ca_neighborhood.H>
50
51using namespace Aleph;
52using namespace Aleph::CA;
53
54namespace
55{
56
58
59class Lotka_Volterra_Rule
60{
61 double alpha_, beta_, delta_, gamma_, dt_, diff_;
62
63public:
64 Lotka_Volterra_Rule(double alpha, double beta, double delta, double gamma,
65 double dt, double diffusion)
66 : alpha_(alpha), beta_(beta), delta_(delta), gamma_(gamma), dt_(dt),
67 diff_(diffusion)
68 {}
69
70 std::tuple<double, double>
71 operator()(const std::tuple<double, double> &cur,
72 const std::tuple<Neighbor_View<double>, Neighbor_View<double>> &nb) const
73 {
74 const double x = std::get<0>(cur);
75 const double y = std::get<1>(cur);
76 double lap_x = -static_cast<double>(std::get<0>(nb).size()) * x;
77 double lap_y = -static_cast<double>(std::get<1>(nb).size()) * y;
78 for (const auto &p : std::get<0>(nb)) lap_x += p;
79 for (const auto &p : std::get<1>(nb)) lap_y += p;
80 const double next_x = x + dt_ * (alpha_ * x - beta_ * x * y + diff_ * lap_x);
81 const double next_y = y + dt_ * (delta_ * x * y - gamma_ * y + diff_ * lap_y);
82 return {next_x < 0.0 ? 0.0 : next_x, next_y < 0.0 ? 0.0 : next_y};
83 }
84};
85
87{
88 // Homogeneous background with a 3×3 perturbation at the centre that
89 // breaks symmetry and seeds an oscillation.
90 lat.fill(std::tuple{1.0, 0.5});
91 const ca_size_t cr = lat.size(0) / 2;
92 const ca_size_t cc = lat.size(1) / 2;
93 for (ca_size_t i = cr - 1; i <= cr + 1; ++i)
94 for (ca_size_t j = cc - 1; j <= cc + 1; ++j)
95 {
96 const Coord_Vec<2> c{static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)};
97 lat.set<0>(c, 1.5);
98 lat.set<1>(c, 0.8);
99 }
100}
101
102char glyph_for(const double x, const double y)
103{
104 if (x > 1.5 and y < 0.4) return 'X'; // prey-rich, predators few
105 if (y > 0.7 and x < 0.6) return 'O'; // predator outbreak
106 if (x > 1.0 and y > 0.4) return '#'; // mixed
107 if (x < 0.3 and y < 0.3) return '.'; // depleted
108 return '+';
109}
110
111void render(const Lattice2 &lat, const std::size_t step, std::ostream &os)
112{
113 double x_total = 0.0, y_total = 0.0;
114 for (ca_size_t i = 0; i < lat.size(0); ++i)
115 {
116 for (ca_size_t j = 0; j < lat.size(1); ++j)
117 {
118 const Coord_Vec<2> c{static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)};
119 const double x = lat.at<0>(c);
120 const double y = lat.at<1>(c);
121 x_total += x;
122 y_total += y;
123 os << glyph_for(x, y);
124 }
125 os << '\n';
126 }
127 os << "step " << step << " Σprey=" << x_total << " Σpred=" << y_total << "\n";
128}
129
136bool parse_u64(const char *text, std::uint64_t &out) noexcept
137{
138 if (text == nullptr)
139 return false;
140 const std::string_view sv{text};
141 if (sv.empty())
142 return false;
143 // Reject signs and leading whitespace explicitly: from_chars already
144 // rejects '+'/'-' but not the empty string after such checks; spaces
145 // would be silently consumed only by stoul, not from_chars.
146 if (sv.front() == '+' or sv.front() == '-')
147 return false;
148 std::uint64_t value = 0;
149 const auto *first = sv.data();
150 const auto *last = first + sv.size();
151 const auto [ptr, ec] = std::from_chars(first, last, value, 10);
152 if (ec != std::errc{} or ptr != last)
153 return false;
154 out = value;
155 return true;
156}
157
158} // namespace
159
160int main(int argc, char **argv)
161{
162 std::size_t steps = 200;
163 ca_size_t side = 32;
164 std::uint64_t parsed = 0;
165 if (argc >= 2)
166 {
167 if (not parse_u64(argv[1], parsed))
168 {
169 std::cerr << "Invalid [steps]: expected a non-negative integer (got '" << argv[1]
170 << "')\n";
171 return 1;
172 }
173 if (parsed > std::numeric_limits<std::size_t>::max())
174 {
175 std::cerr << "[steps] out of range\n";
176 return 1;
177 }
178 steps = static_cast<std::size_t>(parsed);
179 }
180 if (argc >= 3)
181 {
182 if (not parse_u64(argv[2], parsed))
183 {
184 std::cerr << "Invalid [side]: expected a non-negative integer (got '" << argv[2]
185 << "')\n";
186 return 1;
187 }
188 if (parsed > std::numeric_limits<ca_size_t>::max())
189 {
190 std::cerr << "[side] out of range\n";
191 return 1;
192 }
193 side = static_cast<ca_size_t>(parsed);
194 }
195 if (side < 4)
196 {
197 std::cerr << "Invalid side: must be ≥ 4 (need a centre with surrounding cells)\n";
198 return 1;
199 }
200
201 Lattice2 lat({side, side});
203
204 std::cout << "Lotka–Volterra multi-field CA (SoA) — " << side << "×" << side
205 << ", " << steps << " steps\n";
206 std::cout << "Glyphs: '.' depleted '+' mixed '#' rich 'X' prey-rich 'O' predator surge\n\n";
207
209 std::move(lat),
210 Lotka_Volterra_Rule{/*alpha=*/1.0, /*beta=*/0.5, /*delta=*/0.4,
211 /*gamma=*/0.5, /*dt=*/0.05, /*diff=*/0.05},
213
214 std::cout << "Initial frame:\n";
215 render(eng.frame(), 0, std::cout);
216 std::cout << '\n';
217
218 const std::size_t snapshot_every = steps / 4 == 0 ? 1 : steps / 4;
219 for (std::size_t t = 0; t < steps; ++t)
220 {
221 eng.step();
222 if ((t + 1) % snapshot_every == 0 or t + 1 == steps)
223 {
224 std::cout << "\nSnapshot:\n";
225 render(eng.frame(), t + 1, std::cout);
226 }
227 }
228
229 return 0;
230}
int main()
size_t steps
Definition ca-c-api.h:126
size_t size_t int32_t value
Definition ca-c-api.h:116
size_t size_t int32_t * out
Definition ca-c-api.h:120
Common typedefs and tag types for the Cellular Automata module.
Synchronous double-buffered engine for multi-field lattices.
void step()
Apply the multi-field rule to every cell once and swap buffers.
Multi-field lattice with selectable storage layout.
Von Neumann (L1) neighborhood of radius R in N dimensions.
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_gamma_function > > gamma(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4103
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
static mpfr_t y
Definition mpfr_mul_d.c:3
constexpr std::uint32_t delta
File contains only the cells that changed relative to a baseline.
std::span< const T > Neighbor_View
Read-only view over a contiguous range of neighbour values.
Definition ca-traits.H:90
std::ptrdiff_t ca_index_t
Signed coordinate component used by lattices and neighborhoods.
Definition ca-traits.H:60
std::array< ca_index_t, N > Coord_Vec
Default coordinate vector.
Definition ca-traits.H:69
std::size_t ca_size_t
Unsigned size component used for extents and counts.
Definition ca-traits.H:63
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
STL namespace.
Phase 14 synchronous double-buffered engine for multi-field cellular automata.
Phase 14 multi-field cellular automata lattice (AoS / SoA).
Neighborhoods catalogue for Aleph::CA.