Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_ca_stochastic_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 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
45#include <algorithm>
46#include <array>
47#include <cstdint>
48#include <random>
49#include <vector>
50
51#include <gtest/gtest.h>
52
53#include <ca-rng.H>
54#include <ca-traits.H>
55#include <tpl_ca_concepts.H>
56#include <tpl_ca_engine.H>
57#include <tpl_ca_lattice.H>
58#include <tpl_ca_neighborhood.H>
60#include <tpl_ca_rule.H>
62#include <tpl_ca_storage.H>
63
64using namespace Aleph;
65using namespace Aleph::CA;
66
67// ---------------------------------------------------------------------------
68// Common helpers.
69// ---------------------------------------------------------------------------
70
71namespace
72{
73
74template <typename L>
75bool frames_equal(const L &a, const L &b)
76{
77 if (a.extents() != b.extents())
78 return false;
79 using coord_t = typename L::coord_type;
80 if constexpr (L::rank == 1)
81 {
82 const ca_size_t n0 = a.size(0);
83 for (ca_size_t i = 0; i < n0; ++i)
84 if (a.at(coord_t{static_cast<ca_index_t>(i)})
85 != b.at(coord_t{static_cast<ca_index_t>(i)}))
86 return false;
87 }
88 else if constexpr (L::rank == 2)
89 {
90 const ca_size_t n0 = a.size(0);
91 const ca_size_t n1 = a.size(1);
92 for (ca_size_t i = 0; i < n0; ++i)
93 for (ca_size_t j = 0; j < n1; ++j)
94 if (a.at(coord_t{static_cast<ca_index_t>(i),
95 static_cast<ca_index_t>(j)})
96 != b.at(coord_t{static_cast<ca_index_t>(i),
97 static_cast<ca_index_t>(j)}))
98 return false;
99 }
100 return true;
101}
102
103template <typename L>
104std::size_t count_state(const L &lat, int target)
105{
106 std::size_t total = 0;
107 using coord_t = typename L::coord_type;
108 if constexpr (L::rank == 2)
109 {
110 const ca_size_t n0 = lat.size(0);
111 const ca_size_t n1 = lat.size(1);
112 for (ca_size_t i = 0; i < n0; ++i)
113 for (ca_size_t j = 0; j < n1; ++j)
114 if (static_cast<int>(lat.at(coord_t{static_cast<ca_index_t>(i),
115 static_cast<ca_index_t>(j)}))
116 == target)
117 ++total;
118 }
119 return total;
120}
121
122} // namespace
123
124// ---------------------------------------------------------------------------
125// Probabilistic_Rule: legacy and reproducible dispatch.
126// ---------------------------------------------------------------------------
127
129{
130 // A pure 2-arg functor: counts neighbours, returns 1 iff there are at
131 // least 3 alive ones (toy GoL-ish rule). No randomness involved.
132 auto counter = [](const int &, Neighbor_View<int> v) -> int
133 {
134 std::size_t a = 0;
135 for (const auto &x : v)
136 if (x != 0)
137 ++a;
138 return a >= 3 ? 1 : 0;
139 };
141
142 std::array<int, 4> nbuf{1, 1, 0, 1};
143 EXPECT_EQ(rule(0, Neighbor_View<int>(nbuf.data(), nbuf.size())), 1);
144}
145
147{
148 // Functor that uses the engine reference and burns one draw.
149 auto burn = [](const int &, Neighbor_View<int>, std::mt19937_64 &eng) -> int
150 { return static_cast<int>(eng() & 0xff); };
151
152 Probabilistic_Rule<decltype(burn), std::mt19937_64> rule(burn, 0xC0FFEE);
153
154 Cell_Context<2> ctx{3, Coord_Vec<2>{4, 7}};
155 std::array<int, 1> nbuf{0};
156 const int a = rule(0, Neighbor_View<int>(nbuf.data(), 1), ctx);
157 const int b = rule(0, Neighbor_View<int>(nbuf.data(), 1), ctx);
158 EXPECT_EQ(a, b);
159
160 // Different context -> deterministically different seed and first draw.
162 const std::uint64_t seed1 = cell_seed<2>(rule.master_seed(), ctx);
163 const std::uint64_t seed2 = cell_seed<2>(rule.master_seed(), ctx2);
165 std::mt19937_64 eng1{static_cast<std::mt19937_64::result_type>(seed1)};
166 std::mt19937_64 eng2{static_cast<std::mt19937_64::result_type>(seed2)};
167 EXPECT_NE(eng1(), eng2());
168}
169
170// ---------------------------------------------------------------------------
171// apply_rule: forwards the contextual call when supported.
172// ---------------------------------------------------------------------------
173
174namespace
175{
176
179struct Step_Reporter
180{
181 template <typename State>
182 State operator()(const State &, Neighbor_View<State>) const
183 {
184 return static_cast<State>(-1);
185 }
186 template <typename State, std::size_t Rank>
187 State operator()(const State &, Neighbor_View<State>,
188 const Cell_Context<Rank> &ctx) const
189 {
190 return static_cast<State>(ctx.step);
191 }
192};
193
196struct View_Size_Rule
197{
198 template <typename State>
199 State operator()(const State &, Neighbor_View<State> v) const
200 {
201 return static_cast<State>(v.size());
202 }
203};
204
205} // namespace
206
208{
209 Step_Reporter r;
210 std::array<int, 1> nbuf{0};
211 Cell_Context<2> ctx{42, Coord_Vec<2>{0, 0}};
212 EXPECT_EQ(apply_rule(r, 0, Neighbor_View<int>(nbuf.data(), 1), ctx), 42);
213}
214
216{
217 View_Size_Rule r;
218 std::array<int, 4> nbuf{};
219 Cell_Context<2> ctx{0, Coord_Vec<2>{0, 0}};
220 EXPECT_EQ(apply_rule(r, 0, Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx),
221 4);
222}
223
224// ---------------------------------------------------------------------------
225// Forest fire: canonical transitions.
226// ---------------------------------------------------------------------------
227
229{
230 Forest_Fire_Rule<> rule(0.05, 0.001, /*seed=*/0x1u);
231 const std::array<int, 8> nbuf{0, 0, 0, 0, 0, 0, 0, 0};
232 Cell_Context<2> ctx{0, Coord_Vec<2>{0, 0}};
233 const int next = rule(static_cast<int>(Forest_Cell::BURNING),
234 Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx);
235 EXPECT_EQ(next, static_cast<int>(Forest_Cell::EMPTY));
236}
237
239{
240 Forest_Fire_Rule<> rule(0.0, 0.0, /*seed=*/0x1u);
241 std::array<int, 8> nbuf{0, 0, 0, static_cast<int>(Forest_Cell::BURNING),
242 0, 0, 0, 0};
243 Cell_Context<2> ctx{0, Coord_Vec<2>{1, 1}};
244 EXPECT_EQ(rule(static_cast<int>(Forest_Cell::TREE),
245 Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx),
246 static_cast<int>(Forest_Cell::BURNING));
247}
248
250{
251 Forest_Fire_Rule<> rule(0.0, 0.0, /*seed=*/0x1u);
252 std::array<int, 8> nbuf{};
253 Cell_Context<2> ctx{0, Coord_Vec<2>{0, 0}};
254 EXPECT_EQ(rule(static_cast<int>(Forest_Cell::EMPTY),
255 Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx),
256 static_cast<int>(Forest_Cell::EMPTY));
257}
258
260{
261 Forest_Fire_Rule<> rule(1.0, 0.0, /*seed=*/0x1u);
262 std::array<int, 8> nbuf{};
263 Cell_Context<2> ctx{0, Coord_Vec<2>{0, 0}};
264 EXPECT_EQ(rule(static_cast<int>(Forest_Cell::EMPTY),
265 Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx),
266 static_cast<int>(Forest_Cell::TREE));
267}
268
270{
272 L lat({5, 5}, static_cast<int>(Forest_Cell::TREE));
273 // Light a fire at (2, 2). With p_growth = 0 and p_lightning = 0 the
274 // dynamics are deterministic: the fire spreads outwards over time.
275 lat.set({2, 2}, static_cast<int>(Forest_Cell::BURNING));
276
278 lat, Forest_Fire_Rule<>(0.0, 0.0, 0xABCDu), Moore<2, 1>{});
279
280 engine.step();
281
282 const auto &f = engine.frame();
283 EXPECT_EQ(f.at({2, 2}), static_cast<int>(Forest_Cell::EMPTY));
284 // All immediate Moore neighbours of (2, 2) are now burning.
285 for (int di = -1; di <= 1; ++di)
286 for (int dj = -1; dj <= 1; ++dj)
287 if (di != 0 or dj != 0)
288 EXPECT_EQ(f.at({2 + di, 2 + dj}),
289 static_cast<int>(Forest_Cell::BURNING));
290}
291
292// ---------------------------------------------------------------------------
293// SIR: extinction with R0 < 1.
294// ---------------------------------------------------------------------------
295
297{
298 SIR_Rule<> rule(0.5, 0.5, 0x1u);
299 std::array<int, 4> nbuf{static_cast<int>(SIR_Cell::I),
300 static_cast<int>(SIR_Cell::I),
301 static_cast<int>(SIR_Cell::I),
302 static_cast<int>(SIR_Cell::I)};
303 Cell_Context<2> ctx{0, Coord_Vec<2>{0, 0}};
304 EXPECT_EQ(rule(static_cast<int>(SIR_Cell::R),
305 Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx),
306 static_cast<int>(SIR_Cell::R));
307}
308
310{
311 SIR_Rule<> rule(1.0, 0.5, 0x1u);
312 std::array<int, 4> nbuf{};
313 Cell_Context<2> ctx{0, Coord_Vec<2>{0, 0}};
314 EXPECT_EQ(rule(static_cast<int>(SIR_Cell::S),
315 Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx),
316 static_cast<int>(SIR_Cell::S));
317}
318
320{
321 SIR_Rule<> rule(0.5, 1.0, 0x1u);
322 std::array<int, 4> nbuf{};
323 Cell_Context<2> ctx{0, Coord_Vec<2>{0, 0}};
324 EXPECT_EQ(rule(static_cast<int>(SIR_Cell::I),
325 Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx),
326 static_cast<int>(SIR_Cell::R));
327}
328
330{
331 // beta=0.05, gamma=0.5, Moore radius 1 ⇒ R0 ≈ 0.05*8/0.5 = 0.8 < 1.
332 // Start with a single infected cell on a 32×32 toroidal lattice.
333 // After 200 steps the epidemic should be extinct.
335 L lat({32, 32}, static_cast<int>(SIR_Cell::S));
336 lat.set({16, 16}, static_cast<int>(SIR_Cell::I));
337
338 SIR_Rule<> rule(0.05, 0.5, 0xACE0FBAFFu);
340 engine.run(200);
341
342 EXPECT_EQ(count_state(engine.frame(), static_cast<int>(SIR_Cell::I)), 0u);
343}
344
345// ---------------------------------------------------------------------------
346// Ising rules: limit cases.
347// ---------------------------------------------------------------------------
348
350{
351 // With s=+1, J=1, H=0 and an equal number of +1 / -1 neighbours,
352 // dE = 0 ⇒ p_flip = 1/2. Average over many cells should be ≈ 0.5.
353 Ising_Glauber_Rule<> rule(/*T=*/2.0, 1.0, 0.0, /*seed=*/0x42u);
354
355 std::array<int, 4> nbuf{1, -1, 1, -1};
356 Cell_Context<2> ctx{0, Coord_Vec<2>{0, 0}};
357 std::size_t flipped = 0;
358 const std::size_t trials = 1024;
359 for (std::size_t k = 0; k < trials; ++k)
360 {
361 ctx.coord[0] = static_cast<ca_index_t>(k);
362 const int n = rule(static_cast<int>(1),
363 Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx);
364 if (n != 1)
365 ++flipped;
366 }
367 // Expect close to 50% flipped — be generous to absorb fluctuations.
368 EXPECT_GT(flipped, trials * 35u / 100u);
369 EXPECT_LT(flipped, trials * 65u / 100u);
370}
371
373{
374 // s=+1 surrounded by all +1 neighbours and J=-1 (anti-ferromagnetic).
375 // dE = 2 * 1 * (-1 * 4 + 0) = -8 < 0 ⇒ Metropolis always flips.
376 Ising_Metropolis_Rule<> rule(/*T=*/0.5, /*J=*/-1.0, /*H=*/0.0, 0xCAFEu);
377
378 std::array<int, 4> nbuf{1, 1, 1, 1};
379 Cell_Context<2> ctx{0, Coord_Vec<2>{0, 0}};
380 EXPECT_EQ(rule(1, Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx), -1);
381}
382
384{
385 // s=+1, J=1, all +1 neighbours, low T. Flip would raise energy by
386 // dE = 2 * 1 * (1 * 4) = 8. p_flip = exp(-8 / 0.05) ≈ 1.27e-70.
387 // 256 trials should never observe a flip.
388 Ising_Metropolis_Rule<> rule(/*T=*/0.05, /*J=*/1.0, 0.0, 0xCAFEu);
389
390 std::array<int, 4> nbuf{1, 1, 1, 1};
391 for (std::size_t k = 0; k < 256; ++k)
392 {
393 Cell_Context<2> ctx{k, Coord_Vec<2>{static_cast<ca_index_t>(k), 0}};
394 EXPECT_EQ(rule(1, Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx), 1);
395 }
396}
397
398// ---------------------------------------------------------------------------
399// Schelling.
400// ---------------------------------------------------------------------------
401
403{
404 Schelling_Rule<> rule(0.5, 1.0, 1.0, 0xCAFEu);
405 std::array<int, 4> nbuf{}; // all empty
406 Cell_Context<2> ctx{0, Coord_Vec<2>{0, 0}};
407 EXPECT_EQ(rule(static_cast<int>(Schelling_Cell::TYPE_A),
408 Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx),
409 static_cast<int>(Schelling_Cell::TYPE_A));
410}
411
413{
414 Schelling_Rule<> rule(/*threshold=*/0.6, /*p_move=*/1.0, /*p_fill=*/0.0,
415 0x1234u);
416 // Type A surrounded by 4 type B occupied + 0 type A occupied.
417 // fraction = 0/4 = 0 < 0.6 ⇒ unhappy ⇒ moves out (becomes EMPTY).
418 std::array<int, 4> nbuf{
419 static_cast<int>(Schelling_Cell::TYPE_B),
420 static_cast<int>(Schelling_Cell::TYPE_B),
421 static_cast<int>(Schelling_Cell::TYPE_B),
422 static_cast<int>(Schelling_Cell::TYPE_B),
423 };
424 Cell_Context<2> ctx{0, Coord_Vec<2>{0, 0}};
425 EXPECT_EQ(rule(static_cast<int>(Schelling_Cell::TYPE_A),
426 Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx),
427 static_cast<int>(Schelling_Cell::EMPTY));
428}
429
431{
432 Schelling_Rule<> rule(/*threshold=*/0.4, 1.0, 0.0, 0x1234u);
433 // 3 same / 1 other ⇒ fraction = 0.75 ≥ 0.4 ⇒ happy.
434 std::array<int, 4> nbuf{
435 static_cast<int>(Schelling_Cell::TYPE_A),
436 static_cast<int>(Schelling_Cell::TYPE_A),
437 static_cast<int>(Schelling_Cell::TYPE_A),
438 static_cast<int>(Schelling_Cell::TYPE_B),
439 };
440 Cell_Context<2> ctx{0, Coord_Vec<2>{0, 0}};
441 EXPECT_EQ(rule(static_cast<int>(Schelling_Cell::TYPE_A),
442 Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx),
443 static_cast<int>(Schelling_Cell::TYPE_A));
444}
445
447{
448 Schelling_Rule<> rule(0.5, 0.0, 1.0, 0x55u);
449 std::array<int, 4> nbuf{
450 static_cast<int>(Schelling_Cell::TYPE_A),
451 static_cast<int>(Schelling_Cell::TYPE_A),
452 static_cast<int>(Schelling_Cell::TYPE_B),
453 static_cast<int>(Schelling_Cell::EMPTY),
454 };
455 Cell_Context<2> ctx{0, Coord_Vec<2>{0, 0}};
456 EXPECT_EQ(rule(static_cast<int>(Schelling_Cell::EMPTY),
457 Neighbor_View<int>(nbuf.data(), nbuf.size()), ctx),
458 static_cast<int>(Schelling_Cell::TYPE_A));
459}
460
461// ---------------------------------------------------------------------------
462// Cross-thread bit-for-bit reproducibility.
463// ---------------------------------------------------------------------------
464
465namespace
466{
467
468template <typename Lattice, typename Rule>
469Lattice run_parallel(const Lattice &seed, Rule rule, std::size_t steps,
470 std::size_t parts)
471{
474 cfg.min_parallel_cells = 0; // force the parallel path even for tiny grids
476 seed, std::move(rule), Moore<2, 1>{}, cfg);
478 return engine.frame();
479}
480
481template <typename L>
482void seed_random_states(L &lat, std::uint32_t seed,
483 std::initializer_list<int> states,
484 const std::vector<double> &weights)
485{
486 std::mt19937 rng(seed);
487 std::discrete_distribution<int> pick(weights.begin(), weights.end());
488 using coord_t = typename L::coord_type;
489 const ca_size_t n0 = lat.size(0);
490 const ca_size_t n1 = lat.size(1);
491 std::vector<int> table(states.begin(), states.end());
492 for (ca_size_t i = 0; i < n0; ++i)
493 for (ca_size_t j = 0; j < n1; ++j)
494 lat.set(coord_t{static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)},
495 table[pick(rng)]);
496}
497
498} // namespace
499
501{
503 L seed({16, 16});
504 seed_random_states(seed, 0xABCDu,
505 {static_cast<int>(Forest_Cell::EMPTY),
506 static_cast<int>(Forest_Cell::TREE),
507 static_cast<int>(Forest_Cell::BURNING)},
508 {0.4, 0.55, 0.05});
509
510 Forest_Fire_Rule<> rule(0.05, 0.001, /*seed=*/0xCC11u);
511 L f1 = run_parallel(seed, rule, 50, /*parts=*/1);
512 L f2 = run_parallel(seed, rule, 50, /*parts=*/2);
513 L f4 = run_parallel(seed, rule, 50, /*parts=*/4);
514 L f8 = run_parallel(seed, rule, 50, /*parts=*/8);
515
516 EXPECT_TRUE(frames_equal(f1, f2));
519}
520
522{
524 L seed({20, 20}, static_cast<int>(SIR_Cell::S));
525 seed.set({10, 10}, static_cast<int>(SIR_Cell::I));
526 seed.set({4, 5}, static_cast<int>(SIR_Cell::I));
527
528 SIR_Rule<> rule(0.2, 0.1, /*seed=*/0xDD22u);
529 L f1 = run_parallel(seed, rule, 80, /*parts=*/1);
530 L f3 = run_parallel(seed, rule, 80, /*parts=*/3);
531 L f8 = run_parallel(seed, rule, 80, /*parts=*/8);
532
533 EXPECT_TRUE(frames_equal(f1, f3));
535}
536
538{
540 L seed({16, 16});
541 std::mt19937 rng(0x4242u);
542 std::bernoulli_distribution flip(0.5);
543 for (ca_size_t i = 0; i < seed.size(0); ++i)
544 for (ca_size_t j = 0; j < seed.size(1); ++j)
545 seed.set({static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)},
546 flip(rng) ? 1 : -1);
547
548 Ising_Glauber_Rule<> rule(/*T=*/2.5, 1.0, 0.0, /*seed=*/0xEE33u);
549 L f1 = run_parallel(seed, rule, 80, /*parts=*/1);
550 L f4 = run_parallel(seed, rule, 80, /*parts=*/4);
551 L f8 = run_parallel(seed, rule, 80, /*parts=*/8);
552
555}
556
558{
560 L seed({16, 16});
561 seed_random_states(seed, 0xBEEFu,
562 {static_cast<int>(Schelling_Cell::EMPTY),
563 static_cast<int>(Schelling_Cell::TYPE_A),
564 static_cast<int>(Schelling_Cell::TYPE_B)},
565 {0.1, 0.45, 0.45});
566
567 Schelling_Rule<> rule(0.5, 0.7, 0.7, /*seed=*/0xFE33u);
568 L f1 = run_parallel(seed, rule, 60, /*parts=*/1);
569 L f2 = run_parallel(seed, rule, 60, /*parts=*/2);
570 L f8 = run_parallel(seed, rule, 60, /*parts=*/8);
571
572 EXPECT_TRUE(frames_equal(f1, f2));
574}
575
576// ---------------------------------------------------------------------------
577// Sequential vs parallel equivalence: same seed must yield same trajectory.
578// ---------------------------------------------------------------------------
579
581{
583 L seed({24, 24});
584 seed_random_states(seed, 0xF1F1u,
585 {static_cast<int>(Forest_Cell::EMPTY),
586 static_cast<int>(Forest_Cell::TREE),
587 static_cast<int>(Forest_Cell::BURNING)},
588 {0.3, 0.6, 0.1});
589
590 Forest_Fire_Rule<> rule(0.02, 0.001, /*seed=*/0xC1u);
591
593 seq.run(40);
594
595 L par = run_parallel(seed, rule, 40, /*parts=*/4);
596 EXPECT_TRUE(frames_equal(seq.frame(), par));
597}
size_t steps
Definition ca-c-api.h:126
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).
Ising rule with Glauber single-spin-flip dynamics.
Ising rule with Metropolis–Hastings single-spin-flip dynamics.
Lattice that adds boundary-aware access on top of a storage.
Moore (Chebyshev) neighborhood of radius R in N dimensions.
Parallel synchronous double-buffered engine.
void run(const std::size_t steps)
Run several synchronous steps.
Reproducible stochastic rule wrapper (Phase 8).
SIR epidemic transition rule.
Local approximation of the Schelling segregation model.
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)
static mt19937 rng
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
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
ca_size_t count_state(const Lattice &lat, const typename Lattice::state_type &s)
Definition ca-metrics.H:175
std::size_t ca_size_t
Unsigned size component used for extents and counts.
Definition ca-traits.H:63
State apply_rule(const Rule &r, const State &s, Neighbor_View< State > v, const Cell_Context< Rank > &ctx)
Invoke a rule, optionally forwarding the per-cell context.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:171
Per-cell context handed to rules that need to know "where" and "when" they are firing.
Definition ca-traits.H:106
std::size_t step
Index of the step that is currently being computed (0-based).
Definition ca-traits.H:108
Coord_Vec< Rank > coord
Cell coordinate inside the current frame.
Definition ca-traits.H:110
Configuration for Parallel_Synchronous_Engine.
std::size_t num_partitions
Number of partitions per step.
The lattice wraps around on every axis.
Definition ca-traits.H:124
static long counter
Definition test-splice.C:40
ValueArg< size_t > seed
Definition testHash.C:53
static int * k
static mt19937 engine
gsl_rng * r
C++20 concepts for the Cellular Automata module.
Synchronous double-buffered engine for cellular automata.
Cellular automata lattice with pluggable boundary policies.
Neighborhoods catalogue for Aleph::CA.
Parallel synchronous engine for cellular automata (Phase 5).
Rule mechanisms for Aleph::CA.
Reproducible stochastic CA rules (Phase 8).
Dense, contiguous storage for cellular automata cells (1D/2D/3D).