Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_ca_continuous_rules_test.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
25#include <array>
26#include <cmath>
27#include <cstdint>
28#include <stdexcept>
29
30#include <gtest/gtest.h>
31
32#include <ca-kernels.H>
33#include <ca-rng.H>
34#include <ca-traits.H>
36#include <tpl_ca_engine.H>
37#include <tpl_ca_lattice.H>
38#include <tpl_ca_neighborhood.H>
39#include <tpl_ca_storage.H>
40
41using namespace Aleph;
42using namespace Aleph::CA;
43
44namespace
45{
46
47constexpr double eps = 1e-12;
48
51
52double seeded_noise(const std::uint64_t master, const Coord_Vec<2> &coord)
53{
54 const std::uint64_t h = cell_seed<2>(master, 0, coord);
55 const double unit = static_cast<double>(h >> 11)
56 * (1.0 / 9007199254740992.0);
57 return unit - 0.5;
58}
59
61 const std::uint64_t master)
62{
63 RD_Lattice lat({n, n}, RD_Cell{1.0, 0.0});
64 const ca_size_t lo = n / 2 - n / 10;
65 const ca_size_t hi = n / 2 + n / 10;
66 for (ca_size_t i = lo; i <= hi; ++i)
67 for (ca_size_t j = lo; j <= hi; ++j)
68 {
69 const Coord_Vec<2> c{static_cast<ca_index_t>(i),
70 static_cast<ca_index_t>(j)};
71 const double z = 0.02 * seeded_noise(master, c);
72 lat.set(c, RD_Cell{0.50 + z, 0.25 - z});
73 }
74 return lat;
75}
76
77struct VStats
78{
79 double mean = 0.0;
80 double variance = 0.0;
81 double max_value = 0.0;
82 std::size_t peaks = 0;
83};
84
85VStats stats_for_v(const RD_Lattice &lat)
86{
87 const double total = static_cast<double>(lat.size(0) * lat.size(1));
88 double sum = 0.0;
89 double sum2 = 0.0;
90 double max_v = 0.0;
91 std::size_t peaks = 0;
92
93 for (ca_size_t i = 0; i < lat.size(0); ++i)
94 for (ca_size_t j = 0; j < lat.size(1); ++j)
95 {
96 const RD_Cell cell = lat.at({static_cast<ca_index_t>(i),
97 static_cast<ca_index_t>(j)});
98 sum += cell.v;
99 sum2 += cell.v * cell.v;
100 if (cell.v > max_v)
101 max_v = cell.v;
102 if (cell.v > 0.10)
103 ++peaks;
104 }
105
106 const double mean = sum / total;
107 return {mean, sum2 / total - mean * mean, max_v, peaks};
108}
109
110bool frames_equal(const RD_Lattice &a, const RD_Lattice &b)
111{
112 if (a.extents() != b.extents())
113 return false;
114 for (ca_size_t i = 0; i < a.size(0); ++i)
115 for (ca_size_t j = 0; j < a.size(1); ++j)
116 if (a.at({static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)})
117 != b.at({static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)}))
118 return false;
119 return true;
120}
121
122} // namespace
123
125{
126 const auto rule = make_continuous_rule(
127 [](double current, double conv, double dt)
128 {
129 return current + dt * (conv - current);
130 },
132 /*dt=*/0.5,
133 /*min=*/0.0,
134 /*max=*/10.0);
135
136 const std::array<double, 8> neighbours{1.0, 1.0, 1.0, 1.0,
137 1.0, 1.0, 1.0, 1.0};
138 EXPECT_NEAR(rule(3.0, Neighbor_View<double>(neighbours.data(),
139 neighbours.size())),
140 19.0 / 9.0, eps);
141}
142
144{
146 [](double, double, double) { return 0.0; },
148 /*dt=*/0.0),
149 std::domain_error);
150
151 const auto rule = make_continuous_rule(
152 [](double, double, double) { return 2.0; },
154 /*dt=*/1.0,
155 /*min=*/0.0,
156 /*max=*/1.0);
157 const std::array<double, 8> neighbours{};
158 EXPECT_THROW(rule(0.0, Neighbor_View<double>(neighbours.data(),
159 neighbours.size())),
160 std::runtime_error);
161
162 const auto ok_rule = make_continuous_rule(
163 [](double, double conv) { return conv; },
165 const std::array<double, 2> too_short{};
167 too_short.size())),
168 std::length_error);
169}
170
172{
173 EXPECT_THROW((Gray_Scott_Rule<double>(-0.01, 0.06, 0.16, 0.08)),
174 std::domain_error);
175 EXPECT_THROW((Gray_Scott_Rule<double>(0.04, 1.01, 0.16, 0.08)),
176 std::domain_error);
177 EXPECT_THROW((Gray_Scott_Rule<double>(0.04, 0.06, -0.1, 0.08)),
178 std::domain_error);
179 EXPECT_THROW((Gray_Scott_Rule<double>(0.04, 0.06, 0.16, 0.08, 1.01)),
180 std::domain_error);
181}
182
184{
185 Gray_Scott_Rule<double> rule(0.04, 0.06, 0.16, 0.08);
186 const std::array<RD_Cell, 8> neighbours{RD_Cell{1.0, 0.0},
187 RD_Cell{1.0, 0.0},
188 RD_Cell{1.0, 0.0},
189 RD_Cell{1.0, 0.0},
190 RD_Cell{1.0, 0.0},
191 RD_Cell{1.0, 0.0},
192 RD_Cell{1.0, 0.0},
193 RD_Cell{1.0, 0.0}};
194
195 const RD_Cell next = rule(RD_Cell{1.0, 0.0},
196 Neighbor_View<RD_Cell>(neighbours.data(),
197 neighbours.size()));
198 EXPECT_DOUBLE_EQ(next.u, 1.0);
199 EXPECT_DOUBLE_EQ(next.v, 0.0);
200}
201
203{
204 Gray_Scott_Rule<double> rule(0.04, 0.06, 0.16, 0.08);
205 const std::array<RD_Cell, 8> neighbours{RD_Cell{1.0, 0.0},
206 RD_Cell{1.0, 0.0},
207 RD_Cell{1.0, 0.0},
208 RD_Cell{1.0, 0.0},
209 RD_Cell{1.0, 0.0},
210 RD_Cell{1.0, 0.0},
211 RD_Cell{1.0, 0.0},
212 RD_Cell{1.0, 0.0}};
213
214 const RD_Cell next = rule(RD_Cell{0.5, 0.25},
215 Neighbor_View<RD_Cell>(neighbours.data(),
216 neighbours.size()));
217 EXPECT_NEAR(next.u, 0.80875, eps);
218 EXPECT_NEAR(next.v, 0.17625, eps);
219}
220
222{
223 constexpr ca_size_t n = 48;
224 constexpr std::uint64_t master = 0x9E3779B97F4A7C15ull;
225 constexpr std::size_t steps = 360;
226
227 Gray_Scott_Rule<double> rule(0.0367, 0.0649, 0.16, 0.08);
229 a(make_gray_scott_seed(n, master), rule);
231 b(make_gray_scott_seed(n, master), rule);
232
233 a.run(steps);
234 b.run(steps);
235
237
238 const VStats stats = stats_for_v(a.frame());
239 EXPECT_GT(stats.max_value, 0.18);
240 EXPECT_GT(stats.variance, 1e-4);
241 EXPECT_GT(stats.peaks, 8u);
242 EXPECT_LT(stats.peaks, static_cast<std::size_t>(n * n / 2));
243}
244
246{
247 FitzHugh_Nagumo_Rule<double> rule(/*a=*/0.7,
248 /*b=*/0.8,
249 /*epsilon=*/0.08,
250 /*Du=*/1.0,
251 /*Dv=*/0.0,
252 /*dt=*/0.01);
253 const std::array<RD_Cell, 8> neighbours{};
254 const RD_Cell next = rule(RD_Cell{0.0, 0.0},
255 Neighbor_View<RD_Cell>(neighbours.data(),
256 neighbours.size()));
257
258 EXPECT_NEAR(next.u, 0.0, eps);
259 EXPECT_NEAR(next.v, 0.00056, eps);
260}
261
263{
264 EXPECT_THROW((FitzHugh_Nagumo_Rule<double>(0.7, 0.0, 0.08, 1.0, 0.0)),
265 std::domain_error);
266 EXPECT_THROW((FitzHugh_Nagumo_Rule<double>(0.7, 0.8, 0.08, 1.0, 0.0, 0.50)),
267 std::domain_error);
268
269 FitzHugh_Nagumo_Rule<double> rule(0.7, 0.8, 0.08, 1.0, 0.0, 0.01);
270 const std::array<RD_Cell, 8> neighbours{};
271 EXPECT_THROW(rule(RD_Cell{1000.0, 0.0},
272 Neighbor_View<RD_Cell>(neighbours.data(),
273 neighbours.size())),
274 std::runtime_error);
275}
276
278{
280 EXPECT_EQ(h.current(), 1);
281 EXPECT_EQ(h.previous(1), 1);
282
283 h.push(2);
284 EXPECT_EQ(h.current(), 2);
285 EXPECT_EQ(h.previous(1), 1);
286 EXPECT_EQ(h.previous(2), 1);
287
288 h.push(3);
289 h.push(5);
290 EXPECT_EQ(h.current(), 5);
291 EXPECT_EQ(h.previous(1), 3);
292 EXPECT_EQ(h.previous(2), 2);
293 EXPECT_THROW(h.previous(3), std::out_of_range);
294}
295
297{
298 using Cell = History_Cell<int, 3>;
299 const auto rule = make_history_rule<3>(
300 [](const Cell &current, Neighbor_View<Cell> neighbours) -> int
301 {
302 int sum = current.current() + current.previous(1);
303 for (const auto &n : neighbours)
304 sum += n.current();
305 return sum;
306 });
307
308 const Cell current(2);
309 const std::array<Cell, 2> neighbours{Cell(3), Cell(5)};
310 const Cell next = rule(current, Neighbor_View<Cell>(neighbours.data(),
311 neighbours.size()));
312 EXPECT_EQ(next.current(), 12);
313 EXPECT_EQ(next.previous(1), 2);
314}
315
317{
318 using Cell = History_Cell<int, 3>;
320
321 Hist_Lattice lat({4}, Cell(1));
322 const auto fib_like = make_history_rule<3>(
323 [](int current, int previous) -> int
324 {
325 return current + previous;
326 });
327
330
331 engine.step();
332 EXPECT_EQ(engine.frame().at({0}).current(), 2);
333 EXPECT_EQ(engine.frame().at({0}).previous(1), 1);
334
335 engine.step();
336 EXPECT_EQ(engine.frame().at({0}).current(), 3);
337 EXPECT_EQ(engine.frame().at({0}).previous(1), 2);
338
339 engine.step();
340 EXPECT_EQ(engine.frame().at({0}).current(), 5);
341 EXPECT_EQ(engine.frame().at({0}).previous(1), 3);
342}
long double h
Definition btreepic.C:154
static int cell(const aleph_ca_engine_t *e, size_t r, size_t c)
Definition c_abi_smoke.c:53
size_t steps
Definition ca-c-api.h:126
Fixed 2-D convolution kernels for continuous cellular automata.
Reproducible random-number support for stochastic CA rules (Phase 8).
Common typedefs and tag types for the Cellular Automata module.
FitzHugh-Nagumo excitable-media rule.
Gray-Scott reaction-diffusion rule.
Cell state carrying a fixed-depth ring buffer of past values.
Lattice that adds boundary-aware access on top of a storage.
Moore (Chebyshev) neighborhood of radius R in N dimensions.
Synchronous double-buffered engine.
void run(const std::size_t steps)
Run several synchronous steps.
const Lattice & frame() const noexcept
Return the current frame.
#define TEST(name)
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
Gray_Scott_Lattice make_gray_scott_seed(const ca_size_t side, const std::uint64_t master_seed)
Build the deterministic finite-amplitude Gray-Scott perturbation.
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
bool frames_equal(const Lattice &a, const Lattice &b)
Definition ca-metrics.H:323
Continuous_Rule< F, Kernel > make_continuous_rule(F f, Kernel k, typename Kernel::value_type dt=typename Kernel::value_type{1}, typename Kernel::value_type min_value=-std::numeric_limits< typename Kernel::value_type >::infinity(), typename Kernel::value_type max_value=std::numeric_limits< typename Kernel::value_type >::infinity())
Helper factory for Continuous_Rule.
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
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:220
auto mean(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute the arithmetic mean.
Definition stat_utils.H:190
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:171
auto max_value(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute maximum value.
Definition stat_utils.H:294
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Zero-gradient (Neumann) boundary.
Definition ca-traits.H:152
Two-field state for reaction-diffusion cellular automata.
The lattice wraps around on every axis.
Definition ca-traits.H:124
static mt19937 engine
Continuous and memory-bearing CA rules (Phase 9).
Synchronous double-buffered engine for cellular automata.
Cellular automata lattice with pluggable boundary policies.
Neighborhoods catalogue for Aleph::CA.
Dense, contiguous storage for cellular automata cells (1D/2D/3D).