Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_ca_engine.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
55#ifndef TPL_CA_ENGINE_H
56#define TPL_CA_ENGINE_H
57
58#include <array>
59#include <concepts>
60#include <cstddef>
61#include <functional>
62#include <span>
63#include <type_traits>
64#include <utility>
65
66#include <ca-traits.H>
67#include <tpl_ca_concepts.H>
68#include <tpl_ca_neighborhood.H>
69
70namespace Aleph {
71namespace CA {
72
73namespace ca_engine_detail {
75template <typename O>
76struct is_tile : std::false_type
77{
78};
79
80template <std::size_t W, std::size_t H>
81struct is_tile<Tile<W, H>> : std::true_type
82{
83};
84
85template <typename O>
86inline constexpr bool is_tile_v = is_tile<O>::value;
87
89template <typename Coord, typename F>
90inline void iterate_1d(ca_size_t n0, F &&f)
91{
92 Coord c{};
93 for (ca_index_t i = 0; i < static_cast<ca_index_t>(n0); ++i)
94 {
95 c[0] = i;
96 f(c);
97 }
98}
99
101template <typename Coord, typename F>
103{
104 Coord c{};
105 for (ca_index_t i = 0; i < static_cast<ca_index_t>(n0); ++i)
106 for (ca_index_t j = 0; j < static_cast<ca_index_t>(n1); ++j)
107 {
108 c[0] = i;
109 c[1] = j;
110 f(c);
111 }
112}
113
115template <typename Coord, typename F>
117{
118 Coord c{};
119 for (ca_index_t j = 0; j < static_cast<ca_index_t>(n1); ++j)
120 for (ca_index_t i = 0; i < static_cast<ca_index_t>(n0); ++i)
121 {
122 c[0] = i;
123 c[1] = j;
124 f(c);
125 }
126}
127
130template <std::size_t W, std::size_t H, typename Coord, typename F>
131inline void iterate_2d_tile(const ca_size_t n0, const ca_size_t n1, F &&f)
132{
133 Coord c{};
134 for (ca_size_t ti = 0; ti < n0; ti += H)
135 for (ca_size_t tj = 0; tj < n1; tj += W)
136 {
137 const ca_size_t i_end = ti + H < n0 ? ti + H : n0;
138 const ca_size_t j_end = tj + W < n1 ? tj + W : n1;
139 for (ca_size_t i = ti; i < i_end; ++i)
140 for (ca_size_t j = tj; j < j_end; ++j)
141 {
142 c[0] = static_cast<ca_index_t>(i);
143 c[1] = static_cast<ca_index_t>(j);
144 f(c);
145 }
146 }
147}
148
150template <typename Coord, typename F>
151inline void iterate_3d_row_major(const ca_size_t n0, const ca_size_t n1, const ca_size_t n2, F &&f)
152{
153 Coord c{};
154 for (ca_index_t i = 0; i < static_cast<ca_index_t>(n0); ++i)
155 for (ca_index_t j = 0; j < static_cast<ca_index_t>(n1); ++j)
156 for (ca_index_t k = 0; k < static_cast<ca_index_t>(n2); ++k)
157 {
158 c[0] = i;
159 c[1] = j;
160 c[2] = k;
161 f(c);
162 }
163}
164} // namespace ca_engine_detail
165
182template <typename Lattice, typename Rule, typename Neighborhood, typename Order = RowMajor>
184{
185 static_assert(LatticeLike<Lattice>, "Synchronous_Engine requires a LatticeLike lattice");
186 static_assert(NeighborhoodLike<Neighborhood>,
187 "Synchronous_Engine requires a NeighborhoodLike neighborhood");
188 static_assert(RuleLike<Rule, Lattice>, "Synchronous_Engine requires a RuleLike rule");
189 static_assert(Neighborhood::rank_v == Lattice::rank, "Neighborhood rank must match lattice rank");
190
191public:
195 using rule_type = Rule;
199 using order_type = Order;
200
207
209 static constexpr std::size_t rank = Lattice::rank;
211 static constexpr std::size_t neighbour_count = Neighborhood::size_v;
212
214 using hook_type = std::function<void(std::size_t, const Lattice &)>;
215
216private:
219 Rule rule_;
223 std::size_t step_count_ = 0;
224
225public:
241 : cur_buf_(std::move(initial)), nxt_buf_(cur_buf_.extents()), rule_(std::move(r)), nh_(std::move(n))
242 {}
243
258 requires std::default_initializable<Neighborhood>
259 : Synchronous_Engine(std::move(initial), std::move(r), Neighborhood{})
260 {}
261
267 {
268 return cur_buf_;
269 }
270
276 {
277 return step_count_;
278 }
279
285 {
286 return cur_buf_.extents();
287 }
288
292 [[nodiscard]] const Rule &rule() const noexcept
293 {
294 return rule_;
295 }
296
302 {
303 return rule_;
304 }
305
315 {
316 return cur_buf_;
317 }
318
326 void set_step_count(const std::size_t s) noexcept
327 {
328 step_count_ = s;
329 }
330
335 template <typename F>
336 void on_pre_step(F &&f)
337 {
338 pre_hook_ = std::forward<F>(f);
339 }
340
346 template <typename F>
347 void on_post_step(F &&f)
348 {
349 post_hook_ = std::forward<F>(f);
350 }
351
363 void step()
364 {
365 using namespace ca_engine_detail;
366
367 // Refresh the ghost layer, if the lattice has one. This is what
368 // allows Phase 4 lattices to keep the boundary logic out of the
369 // inner loop: by the time `gather_neighbors` runs, every cell
370 // inside the halo already carries the correct policy value.
371 if constexpr (HasRefreshHalo<Lattice>)
372 cur_buf_.refresh_halo();
373
374 if (pre_hook_)
376
377 // Stack buffer for the gathered neighbour values. Size is fixed
378 // by the neighbourhood at compile time, so no heap involvement.
379 std::array<state_type, neighbour_count> nbuf{};
380
381 auto compute_one = [&](const coord_type &c)
382 {
383 const std::size_t neigh_sz = std::min(nh_.size(), nbuf.size());
384 gather_neighbors(nh_, cur_buf_, c, std::span<state_type>(nbuf.data(), neigh_sz));
385 const Cell_Context<rank> ctx{step_count_, c};
386 nxt_buf_.set(c,
388 cur_buf_.at(c),
390 ctx));
391 };
392
393 if constexpr (rank == 1)
394 {
396 }
397 else if constexpr (rank == 2)
398 {
399 if constexpr (is_tile_v<Order>)
401 cur_buf_.size(1),
403 else if constexpr (std::is_same_v<Order, ColumnMajor>)
405 else
407 }
408 else if constexpr (rank == 3)
409 {
411 }
412 else
413 static_assert(rank <= 3, "Synchronous_Engine currently supports rank <= 3");
414
416 ++step_count_;
417
418 if (post_hook_)
420 }
421
432 void run(const std::size_t steps)
433 {
434 for (std::size_t i = 0; i < steps; ++i)
435 step();
436 }
437};
438
439} // namespace CA
440} // namespace Aleph
441
442#endif // TPL_CA_ENGINE_H
size_t steps
Definition ca-c-api.h:126
Common typedefs and tag types for the Cellular Automata module.
Lattice that adds boundary-aware access on top of a storage.
void set(const coord_type &c, const state_type &v)
Strict write: throws if c is out of range.
typename Storage::state_type state_type
typename Storage::extents_type extents_type
const extents_type & extents() const noexcept
void swap(Lattice &other) noexcept(noexcept(store_.swap(other.store_)))
O(1) swap.
typename Storage::coord_type coord_type
static constexpr std::size_t rank
ca_size_t size() const noexcept
state_type at(const coord_type &c) const
Strict access: throws if c is out of range.
Synchronous double-buffered engine.
const extents_type & extents() const noexcept
Return the frame extents.
static constexpr std::size_t rank
Lattice dimension.
static constexpr std::size_t neighbour_count
Number of neighbours.
void run(const std::size_t steps)
Run several synchronous steps.
std::function< void(std::size_t, const Lattice &)> hook_type
Hook signature: (step_index_just_completed, frame).
typename Lattice::extents_type extents_type
Extents type.
const Rule & rule() const noexcept
Read-only access to the rule (used by checkpointing).
Rule & rule() noexcept
Mutable access to the rule (used by checkpointing to restore the master RNG seed of stochastic rules)...
Lattice & write_lattice() noexcept
Mutable access to the current lattice buffer.
void on_post_step(F &&f)
Register a hook fired after every step().
std::size_t steps_run() const noexcept
Return the number of completed steps.
Neighborhood neighborhood_type
Neighborhood type.
typename Lattice::coord_type coord_type
Coordinate type.
void step()
Apply the rule to every cell once and swap buffers.
Synchronous_Engine(Lattice initial, Rule r, Neighborhood n)
Build an engine on top of an existing initial lattice.
void on_pre_step(F &&f)
Register a hook fired before every step().
Order order_type
Iteration order.
const Lattice & frame() const noexcept
Return the current frame.
Synchronous_Engine(Lattice initial, Rule r)
Build an engine with a default-constructed neighbourhood.
typename Lattice::state_type state_type
Cell state type.
void set_step_count(const std::size_t s) noexcept
Override the completed-step counter.
Shape (per-axis sizes) of an mdspan, mixing compile-time and run-time extents.
Definition ah-mdspan.H:303
A coordinate type with N integral components.
Detect whether a lattice exposes a refresh_halo() method (the hallmark of a Ghost_Lattice or any othe...
Storage + topology that carries the cell values.
Connectivity pattern around a coordinate.
Local transition function (any supported signature).
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
void iterate_3d_row_major(const ca_size_t n0, const ca_size_t n1, const ca_size_t n2, F &&f)
3D row-major iteration.
void iterate_1d(ca_size_t n0, F &&f)
1D row-major iteration callback f(coord).
void iterate_2d_column_major(ca_size_t n0, ca_size_t n1, F &&f)
2D column-major iteration.
void iterate_2d_tile(const ca_size_t n0, const ca_size_t n1, F &&f)
2D tiled iteration with tile size H along axis 0 and W along axis 1.
void iterate_2d_row_major(ca_size_t n0, ca_size_t n1, F &&f)
2D row-major iteration.
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
void gather_neighbors(const Nbh &nh, const L &lat, const typename L::coord_type &center, std::span< T > out)
Populate out[0..nh.size()) with neighbour values of center.
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
STL namespace.
Per-cell context handed to rules that need to know "where" and "when" they are firing.
Definition ca-traits.H:106
Iterate a 2D lattice in W x H tiles.
Definition ca-traits.H:200
Detect whether O is a Tile<W, H> instantiation.
static int * k
gsl_rng * r
C++20 concepts for the Cellular Automata module.
Neighborhoods catalogue for Aleph::CA.