Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_ca_multi_field_lattice.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
64#ifndef TPL_CA_MULTI_FIELD_LATTICE_H
65#define TPL_CA_MULTI_FIELD_LATTICE_H
66
67#include <array>
68#include <concepts>
69#include <cstddef>
70#include <tuple>
71#include <type_traits>
72#include <utility>
73
74#include <ah-errors.H>
75
76#include <ca-traits.H>
77#include <tpl_ca_concepts.H>
78#include <tpl_ca_lattice.H>
79#include <tpl_ca_storage.H>
80
81namespace Aleph {
82namespace CA {
83
87{
88};
89
94{
95};
96
97namespace ca_mf_detail {
98
100template <std::size_t... I>
101using index_seq = std::index_sequence<I...>;
102
104template <std::size_t Rank, typename Boundary, typename... Fields>
105using soa_storages = std::tuple<Lattice<Dense_Cell_Storage<Fields, Rank>, Boundary>...>;
106
108template <typename... Fields>
109using aos_cell = std::tuple<Fields...>;
110
112template <std::size_t Rank, typename Boundary, typename... Fields>
114
115} // namespace ca_mf_detail
116
127template <typename Layout, typename Boundary, std::size_t Rank, typename... Fields>
129{
130 static_assert(sizeof...(Fields) >= 1, "Multi_Field_Lattice requires at least one field");
131 static_assert((CellState<Fields> and ...), "Every field type must satisfy CellState");
132 static_assert(std::is_same_v<Layout, Layout_AoS> or std::is_same_v<Layout, Layout_SoA>,
133 "Layout must be Layout_AoS or Layout_SoA");
134
135public:
139 using boundary_type = Boundary;
143 using extents_type = std::array<ca_size_t, Rank>;
145 static constexpr std::size_t field_count = sizeof...(Fields);
147 static constexpr std::size_t rank = Rank;
149 using field_types = std::tuple<Fields...>;
150
152 template <std::size_t I>
153 using field_type = std::tuple_element_t<I, field_types>;
154
155private:
156 // Pick the underlying representation based on the layout tag.
159
161 = std::conditional_t<std::is_same_v<Layout, Layout_SoA>, soa_storage_type, aos_lattice_type>;
162
165
166 // ---------------------------------------------------------------------
167 // SoA construction helpers
168 // ---------------------------------------------------------------------
169 template <std::size_t... I>
174
175 template <std::size_t... I>
177 const std::tuple<Fields...> &init,
179 {
180 return soa_storage_type{
181 Lattice<Dense_Cell_Storage<Fields, Rank>, Boundary>(ext, std::get<I>(init))...};
182 }
183
184public:
187
196 {
197 if constexpr (std::is_same_v<Layout, Layout_SoA>)
198 store_ = make_soa(ext, std::index_sequence_for<Fields...>{});
199 else
201 }
202
211 Multi_Field_Lattice(const extents_type &ext, const std::tuple<Fields...> &init) : extents_(ext)
212 {
213 if constexpr (std::is_same_v<Layout, Layout_SoA>)
214 store_ = make_soa_init(ext, init, std::index_sequence_for<Fields...>{});
215 else
217 }
218
219 // ---------------------------------------------------------------------
220 // Geometry
221 // ---------------------------------------------------------------------
222
223 [[nodiscard]] static constexpr std::size_t dimension() noexcept
224 {
225 return Rank;
226 }
227
230 {
231 ca_size_t n = 1;
232 for (std::size_t d = 0; d < Rank; ++d)
233 n *= extents_[d];
234 return n;
235 }
236
238 [[nodiscard]] ca_size_t size(const std::size_t d) const
239 {
240 ah_out_of_range_error_if(d >= Rank) << "Multi_Field_Lattice::size: axis " << d << " out of range";
241 return extents_[d];
242 }
243
246 {
247 return extents_;
248 }
249
250 // ---------------------------------------------------------------------
251 // Per-field access (uniform across layouts)
252 // ---------------------------------------------------------------------
253
260 template <std::size_t I>
262 {
263 static_assert(I < field_count, "field index out of range");
264 if constexpr (std::is_same_v<Layout, Layout_SoA>)
265 return std::get<I>(store_).at(c);
266 else
267 return std::get<I>(store_.at(c));
268 }
269
275 template <std::size_t I>
277 {
278 static_assert(I < field_count, "field index out of range");
279 if constexpr (std::is_same_v<Layout, Layout_SoA>)
280 return std::get<I>(store_).at_safe(c);
281 else
282 return std::get<I>(store_.at_safe(c));
283 }
284
291 template <std::size_t I, typename V>
292 void set(const coord_type &c, const V &v)
293 {
294 static_assert(I < field_count, "field index out of range");
295 if constexpr (std::is_same_v<Layout, Layout_SoA>)
296 {
297 std::get<I>(store_).set(c, static_cast<field_type<I>>(v));
298 }
299 else
300 {
302 std::get<I>(cell) = static_cast<field_type<I>>(v);
303 store_.set(c, cell);
304 }
305 }
306
312 void set_cell(const coord_type &c, const std::tuple<Fields...> &cell)
313 {
314 if constexpr (std::is_same_v<Layout, Layout_SoA>)
315 set_cell_impl(c, cell, std::index_sequence_for<Fields...>{});
316 else
317 store_.set(c, cell);
318 }
319
325 [[nodiscard]] std::tuple<Fields...> at_cell(const coord_type &c) const
326 {
327 if constexpr (std::is_same_v<Layout, Layout_SoA>)
328 return at_cell_impl(c, std::index_sequence_for<Fields...>{});
329 else
330 return store_.at(c);
331 }
332
333 // ---------------------------------------------------------------------
334 // SoA-only: hand a single-field Lattice<> to the legacy mono-field
335 // engines.
336 // ---------------------------------------------------------------------
337
348 template <std::size_t I>
349 [[nodiscard]] auto &field()
350 requires std::is_same_v<Layout, Layout_SoA>
351 {
352 static_assert(I < field_count, "field index out of range");
353 return std::get<I>(store_);
354 }
355
360 template <std::size_t I>
361 [[nodiscard]] const auto &field() const
363 {
364 static_assert(I < field_count, "field index out of range");
365 return std::get<I>(store_);
366 }
367
368 // ---------------------------------------------------------------------
369 // Bulk operations
370 // ---------------------------------------------------------------------
371
375 void fill(const std::tuple<Fields...> &init)
376 {
377 if constexpr (std::is_same_v<Layout, Layout_SoA>)
378 fill_impl(init, std::index_sequence_for<Fields...>{});
379 else
380 store_.fill(init);
381 }
382
385 {
386 using std::swap;
387 swap(store_, other.store_);
388 swap(extents_, other.extents_);
389 }
390
399 template <std::size_t I>
401 requires std::is_same_v<Layout, Layout_SoA>
402 {
403 static_assert(I < field_count, "field index out of range");
404 using std::swap;
405 swap(std::get<I>(store_), std::get<I>(other.store_));
406 }
407
408private:
409 // SoA helpers ---------------------------------------------------------
410 template <std::size_t... I>
412 const std::tuple<Fields...> &cell,
414 {
415 ((std::get<I>(store_).set(c, std::get<I>(cell))), ...);
416 }
417
418 template <std::size_t... I>
420 {
421 return std::tuple<Fields...>{std::get<I>(store_).at(c)...};
422 }
423
424 template <std::size_t... I>
425 void fill_impl(const std::tuple<Fields...> &init, ca_mf_detail::index_seq<I...>)
426 {
427 ((std::get<I>(store_).fill(std::get<I>(init))), ...);
428 }
429};
430
432template <typename Layout, typename Boundary, std::size_t Rank, typename... Fields>
438
447template <typename L>
448concept MultiFieldLatticeLike = requires {
449 typename L::coord_type;
450 typename L::extents_type;
451 { L::field_count } -> std::convertible_to<std::size_t>;
452 { L::rank } -> std::convertible_to<std::size_t>;
453} and requires(const L &l, std::size_t d) {
454 { l.dimension() } -> std::convertible_to<std::size_t>;
455 { l.size(d) } -> std::convertible_to<std::size_t>;
456};
457
458} // namespace CA
459} // namespace Aleph
460
461#endif // TPL_CA_MULTI_FIELD_LATTICE_H
Exception handling system with formatted messages for Aleph-w.
#define ah_out_of_range_error_if(C)
Throws std::out_of_range if condition holds.
Definition ah-errors.H:584
static int cell(const aleph_ca_engine_t *e, size_t r, size_t c)
Definition c_abi_smoke.c:53
Common typedefs and tag types for the Cellular Automata module.
Row-major dense storage for N-dimensional cellular automata.
Lattice that adds boundary-aware access on top of a storage.
Multi-field lattice with selectable storage layout.
std::tuple< Fields... > field_types
Compile-time tuple of field types.
ca_size_t size(const std::size_t d) const
Extent along axis d (d < Rank).
Coord_Vec< Rank > coord_type
Coordinate type.
static soa_storage_type make_soa(const extents_type &ext, ca_mf_detail::index_seq< I... >)
ca_mf_detail::soa_storages< Rank, Boundary, Fields... > soa_storage_type
void swap_field(Multi_Field_Lattice &other)
Swap a single field's buffer with another lattice.
void set_cell_impl(const coord_type &c, const std::tuple< Fields... > &cell, ca_mf_detail::index_seq< I... >)
field_type< I > at(const coord_type &c) const
Strict read access to field I.
void fill(const std::tuple< Fields... > &init)
Set every cell to the supplied per-field values.
std::tuple< Fields... > at_cell_impl(const coord_type &c, ca_mf_detail::index_seq< I... >) const
Multi_Field_Lattice(const extents_type &ext)
Build a multi-field lattice with the given extents.
field_type< I > at_safe(const coord_type &c) const
Boundary-aware read access to field I.
std::tuple_element_t< I, field_types > field_type
Field type at index I.
Multi_Field_Lattice(const extents_type &ext, const std::tuple< Fields... > &init)
Build a multi-field lattice with the given extents and per-field initial values.
const auto & field() const
Const reference to the underlying single-field lattice for field I (SoA only).
auto & field()
Mutable reference to the underlying single-field lattice for field I.
void swap(Multi_Field_Lattice &other) noexcept
O(1) swap with another lattice of the same type.
std::array< ca_size_t, Rank > extents_type
Per-axis extents type.
static constexpr std::size_t field_count
Number of fields.
static soa_storage_type make_soa_init(const extents_type &ext, const std::tuple< Fields... > &init, ca_mf_detail::index_seq< I... >)
Multi_Field_Lattice()=default
Build an empty multi-field lattice.
void set_cell(const coord_type &c, const std::tuple< Fields... > &cell)
Strict write of every field at coordinate c.
Layout layout_type
Layout tag (Layout_AoS or Layout_SoA).
ca_size_t size() const noexcept
Total cell count (product of extents).
const extents_type & extents() const noexcept
Per-axis extents.
std::tuple< Fields... > at_cell(const coord_type &c) const
Read every field at coordinate c as a tuple.
void set(const coord_type &c, const V &v)
Strict write access to field I.
static constexpr std::size_t dimension() noexcept
static constexpr std::size_t rank
Lattice dimension.
std::conditional_t< std::is_same_v< Layout, Layout_SoA >, soa_storage_type, aos_lattice_type > storage_type
void fill_impl(const std::tuple< Fields... > &init, ca_mf_detail::index_seq< I... >)
ca_mf_detail::aos_lattice< Rank, Boundary, Fields... > aos_lattice_type
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1065
A type usable as the value stored inside a cell.
Concept: a lattice that exposes the multi-field interface.
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::index_sequence< I... > index_seq
Index sequence helper.
std::tuple< Lattice< Dense_Cell_Storage< Fields, Rank >, Boundary >... > soa_storages
Per-field SoA storage tuple type.
std::tuple< Fields... > aos_cell
AoS cell type.
@ I
Infected (and infectious).
std::array< ca_index_t, N > Coord_Vec
Default coordinate vector.
Definition ca-traits.H:69
void swap(Bit_Cell_Storage< N > &a, Bit_Cell_Storage< N > &b) noexcept
Free-function swap so the storage plays nicely with std::swap.
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.
static std::atomic< bool > init
Definition hash-fct.C:54
STL namespace.
Layout tag: each cell is a std::tuple<Fields...> inside a single contiguous storage.
Layout tag: one contiguous storage per field.
size_t V
C++20 concepts for the Cellular Automata module.
Cellular automata lattice with pluggable boundary policies.
Dense, contiguous storage for cellular automata cells (1D/2D/3D).
DynList< int > l