51#include <gtest/gtest.h>
77 if (a.extents() != b.extents())
79 using coord_t =
typename L::coord_type;
80 if constexpr (L::rank == 1)
84 if (a.at(
coord_t{static_cast<ca_index_t>(i)})
88 else if constexpr (L::rank == 2)
106 std::size_t
total = 0;
107 using coord_t =
typename L::coord_type;
108 if constexpr (L::rank == 2)
114 if (
static_cast<int>(
lat.at(
coord_t{static_cast<ca_index_t>(i),
115 static_cast<ca_index_t>(j)}))
135 for (
const auto &x : v)
138 return a >= 3 ? 1 : 0;
142 std::array<int, 4>
nbuf{1, 1, 0, 1};
150 {
return static_cast<int>(
eng() & 0xff); };
155 std::array<int, 1>
nbuf{0};
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)};
181 template <
typename State>
184 return static_cast<State
>(-1);
186 template <
typename State, std::
size_t Rank>
190 return static_cast<State
>(ctx.
step);
198 template <
typename State>
201 return static_cast<State
>(v.size());
210 std::array<int, 1>
nbuf{0};
218 std::array<int, 4>
nbuf{};
231 const std::array<int, 8>
nbuf{0, 0, 0, 0, 0, 0, 0, 0};
233 const int next = rule(
static_cast<int>(Forest_Cell::BURNING),
241 std::array<int, 8>
nbuf{0, 0, 0,
static_cast<int>(Forest_Cell::BURNING),
244 EXPECT_EQ(rule(
static_cast<int>(Forest_Cell::TREE),
246 static_cast<int>(Forest_Cell::BURNING));
252 std::array<int, 8>
nbuf{};
254 EXPECT_EQ(rule(
static_cast<int>(Forest_Cell::EMPTY),
256 static_cast<int>(Forest_Cell::EMPTY));
262 std::array<int, 8>
nbuf{};
264 EXPECT_EQ(rule(
static_cast<int>(Forest_Cell::EMPTY),
266 static_cast<int>(Forest_Cell::TREE));
272 L lat({5, 5},
static_cast<int>(Forest_Cell::TREE));
275 lat.set({2, 2},
static_cast<int>(Forest_Cell::BURNING));
282 const auto &f =
engine.frame();
283 EXPECT_EQ(f.at({2, 2}),
static_cast<int>(Forest_Cell::EMPTY));
285 for (
int di = -1;
di <= 1; ++
di)
286 for (
int dj = -1;
dj <= 1; ++
dj)
289 static_cast<int>(Forest_Cell::BURNING));
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)};
304 EXPECT_EQ(rule(
static_cast<int>(SIR_Cell::R),
306 static_cast<int>(SIR_Cell::R));
312 std::array<int, 4>
nbuf{};
314 EXPECT_EQ(rule(
static_cast<int>(SIR_Cell::S),
316 static_cast<int>(SIR_Cell::S));
322 std::array<int, 4>
nbuf{};
324 EXPECT_EQ(rule(
static_cast<int>(SIR_Cell::I),
326 static_cast<int>(SIR_Cell::R));
335 L lat({32, 32},
static_cast<int>(SIR_Cell::S));
336 lat.set({16, 16},
static_cast<int>(SIR_Cell::I));
355 std::array<int, 4>
nbuf{1, -1, 1, -1};
358 const std::size_t
trials = 1024;
362 const int n = rule(
static_cast<int>(1),
378 std::array<int, 4>
nbuf{1, 1, 1, 1};
390 std::array<int, 4>
nbuf{1, 1, 1, 1};
391 for (std::size_t
k = 0;
k < 256; ++
k)
405 std::array<int, 4>
nbuf{};
407 EXPECT_EQ(rule(
static_cast<int>(Schelling_Cell::TYPE_A),
409 static_cast<int>(Schelling_Cell::TYPE_A));
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),
425 EXPECT_EQ(rule(
static_cast<int>(Schelling_Cell::TYPE_A),
427 static_cast<int>(Schelling_Cell::EMPTY));
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),
441 EXPECT_EQ(rule(
static_cast<int>(Schelling_Cell::TYPE_A),
443 static_cast<int>(Schelling_Cell::TYPE_A));
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),
456 EXPECT_EQ(rule(
static_cast<int>(Schelling_Cell::EMPTY),
458 static_cast<int>(Schelling_Cell::TYPE_A));
468template <
typename Lattice,
typename Rule>
474 cfg.min_parallel_cells = 0;
483 std::initializer_list<int> states,
484 const std::vector<double> &weights)
487 std::discrete_distribution<int> pick(weights.begin(), weights.end());
488 using coord_t =
typename L::coord_type;
491 std::vector<int> table(states.begin(), states.end());
494 lat.set(
coord_t{static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)},
505 {
static_cast<int>(Forest_Cell::EMPTY),
506 static_cast<int>(Forest_Cell::TREE),
507 static_cast<int>(Forest_Cell::BURNING)},
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));
541 std::mt19937
rng(0x4242u);
542 std::bernoulli_distribution
flip(0.5);
545 seed.set({static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)},
562 {
static_cast<int>(Schelling_Cell::EMPTY),
563 static_cast<int>(Schelling_Cell::TYPE_A),
564 static_cast<int>(Schelling_Cell::TYPE_B)},
585 {
static_cast<int>(Forest_Cell::EMPTY),
586 static_cast<int>(Forest_Cell::TREE),
587 static_cast<int>(Forest_Cell::BURNING)},
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.
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
std::span< const T > Neighbor_View
Read-only view over a contiguous range of neighbour values.
std::ptrdiff_t ca_index_t
Signed coordinate component used by lattices and neighborhoods.
std::array< ca_index_t, N > Coord_Vec
Default coordinate vector.
bool frames_equal(const Lattice &a, const Lattice &b)
ca_size_t count_state(const Lattice &lat, const typename Lattice::state_type &s)
std::size_t ca_size_t
Unsigned size component used for extents and counts.
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.
void next()
Advance all underlying iterators (bounds-checked).
Per-cell context handed to rules that need to know "where" and "when" they are firing.
std::size_t step
Index of the step that is currently being computed (0-based).
Coord_Vec< Rank > coord
Cell coordinate inside the current frame.
Configuration for Parallel_Synchronous_Engine.
std::size_t num_partitions
Number of partitions per step.
The lattice wraps around on every axis.
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).