Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_ca_neighborhood.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
71#ifndef TPL_CA_NEIGHBORHOOD_H
72#define TPL_CA_NEIGHBORHOOD_H
73
74#include <array>
75#include <cstddef>
76#include <span>
77#include <utility>
78
79#include <ah-errors.H>
80#include <ca-traits.H>
81#include <tpl_ca_concepts.H>
82
83namespace Aleph {
84namespace CA {
85
86namespace ca_neighborhood_detail {
88constexpr std::size_t static_pow(std::size_t base, std::size_t exp) noexcept
89{
90 std::size_t r = 1;
91 for (std::size_t i = 0; i < exp; ++i)
92 r *= base;
93 return r;
94}
95
98template <std::size_t N, std::size_t R>
99constexpr std::size_t von_neumann_count() noexcept
100{
101 const std::size_t total = static_pow(2 * R + 1, N);
102 const ca_index_t Ri = static_cast<ca_index_t>(R);
103
104 // Iterate over the Moore box and count points whose L1 norm lies
105 // in [1, R]. Compile-time only; tiny N and R in practice.
106 std::size_t cnt = 0;
107 // current offset, initialised to (-R, -R, ..., -R).
108 std::array<std::size_t, N> cur_buf{};
109 for (std::size_t d = 0; d < N; ++d)
110 cur_buf[d] = 0; // we'll bias by -R when reading
111
112 for (std::size_t i = 0; i < total; ++i)
113 {
114 // Convert cur_buf (in [0, 2R]) into signed offset in [-R, R].
115 std::size_t l1 = 0;
116 for (std::size_t d = 0; d < N; ++d)
117 {
118 const ca_index_t v = static_cast<ca_index_t>(cur_buf[d]) - Ri;
119 l1 += static_cast<std::size_t>(v < 0 ? -v : v);
120 }
121 if (l1 != 0 and l1 <= R)
122 ++cnt;
123
124 // Increment cur_buf as a (2R+1)-base counter (last axis fastest).
125 for (std::size_t d = N; d-- > 0;)
126 {
127 if (cur_buf[d] + 1 < 2 * R + 1)
128 {
129 ++cur_buf[d];
130 break;
131 }
132 cur_buf[d] = 0;
133 }
134 }
135 return cnt;
136}
137
139template <std::size_t N, std::size_t R>
141{
142 constexpr std::size_t total = static_pow(2 * R + 1, N);
143 constexpr std::size_t out_n = total - 1;
144 std::array<Offset_Vec<N>, out_n> result{};
145
147 for (std::size_t d = 0; d < N; ++d)
148 cur[d] = -static_cast<ca_index_t>(R);
149
150 std::size_t idx = 0;
151 for (std::size_t i = 0; i < total; ++i)
152 {
153 bool zero = true;
154 for (std::size_t d = 0; d < N; ++d)
155 if (cur[d] != 0)
156 {
157 zero = false;
158 break;
159 }
160 if (not zero)
161 {
162 result[idx] = cur;
163 ++idx;
164 }
165 // Increment lex order (last axis fastest).
166 for (std::size_t d = N; d-- > 0;)
167 {
168 if (cur[d] < static_cast<ca_index_t>(R))
169 {
170 ++cur[d];
171 break;
172 }
173 cur[d] = -static_cast<ca_index_t>(R);
174 }
175 }
176 return result;
177}
178
181template <std::size_t N, std::size_t R>
183{
184 constexpr std::size_t total = static_pow(2 * R + 1, N);
185 constexpr std::size_t out_n = von_neumann_count<N, R>();
186 std::array<Offset_Vec<N>, out_n> result{};
187
189 for (std::size_t d = 0; d < N; ++d)
190 cur[d] = -static_cast<ca_index_t>(R);
191
192 std::size_t idx = 0;
193 for (std::size_t i = 0; i < total; ++i)
194 {
195 std::size_t l1 = 0;
196 for (std::size_t d = 0; d < N; ++d)
197 l1 += static_cast<std::size_t>(cur[d] < 0 ? -cur[d] : cur[d]);
198 if (l1 != 0 and l1 <= R)
199 {
200 result[idx] = cur;
201 ++idx;
202 }
203 for (std::size_t d = N; d-- > 0;)
204 {
205 if (cur[d] < static_cast<ca_index_t>(R))
206 {
207 ++cur[d];
208 break;
209 }
210 cur[d] = -static_cast<ca_index_t>(R);
211 }
212 }
213 return result;
214}
215} // namespace ca_neighborhood_detail
216
217// -----------------------------------------------------------------------
218// Moore neighborhood
219// -----------------------------------------------------------------------
220
227template <std::size_t N, std::size_t R = 1>
228class Moore
229{
230 static_assert(N >= 1, "Moore requires N >= 1");
231 static_assert(R >= 1, "Moore requires R >= 1");
232
233public:
235 static constexpr std::size_t rank_v = N;
237 static constexpr std::size_t radius_v = R;
239 static constexpr std::size_t size_v = ca_neighborhood_detail::static_pow(2 * R + 1, N) - 1;
242
247 static constexpr std::array<Offset_Vec<N>, size_v> offsets
248 = ca_neighborhood_detail::compute_moore_offsets<N, R>();
249
253 [[nodiscard]] static constexpr std::size_t radius() noexcept
254 {
255 return R;
256 }
257
261 [[nodiscard]] constexpr std::size_t size() const noexcept
262 {
263 return size_v;
264 }
265
271 template <typename F>
272 constexpr void for_each_offset(const Coord_Vec<N> & center, F &&f) const
273 {
274 (void)center;
275 for (std::size_t i = 0; i < size_v; ++i)
276 f(offsets[i]);
277 }
278};
279
280// -----------------------------------------------------------------------
281// Von Neumann neighborhood
282// -----------------------------------------------------------------------
283
289template <std::size_t N, std::size_t R = 1>
291{
292 static_assert(N >= 1, "Von_Neumann requires N >= 1");
293 static_assert(R >= 1, "Von_Neumann requires R >= 1");
294
295public:
297 static constexpr std::size_t rank_v = N;
299 static constexpr std::size_t radius_v = R;
301 static constexpr std::size_t size_v = ca_neighborhood_detail::von_neumann_count<N, R>();
304
309 static constexpr std::array<Offset_Vec<N>, size_v> offsets
310 = ca_neighborhood_detail::compute_von_neumann_offsets<N, R>();
311
315 [[nodiscard]] static constexpr std::size_t radius() noexcept
316 {
317 return R;
318 }
319
323 [[nodiscard]] static constexpr std::size_t size() noexcept
324 {
325 return size_v;
326 }
327
333 template <typename F>
334 constexpr void for_each_offset(const Coord_Vec<N> & center, F &&f) const
335 {
336 (void)center;
337 for (std::size_t i = 0; i < size_v; ++i)
338 f(offsets[i]);
339 }
340};
341
342// -----------------------------------------------------------------------
343// Hexagonal neighborhood (axial coordinates)
344// -----------------------------------------------------------------------
345
358{
359public:
361 static constexpr std::size_t rank_v = 2;
363 static constexpr std::size_t radius_v = 1;
365 static constexpr std::size_t size_v = 6;
368
370 static constexpr std::array<Offset_Vec<2>, 6> offsets
371 = {{{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, -1}, {-1, 1}}};
372
376 [[nodiscard]] static constexpr std::size_t radius() noexcept
377 {
378 return 1;
379 }
380
384 [[nodiscard]] static constexpr std::size_t size() noexcept
385 {
386 return 6;
387 }
388
394 template <typename F>
395 static constexpr void for_each_offset(const Coord_Vec<2> & center, F &&f)
396 {
397 (void)center;
398 for (const auto &o : offsets)
399 f(o);
400 }
401};
402
403// -----------------------------------------------------------------------
404// Triangular neighborhood
405// -----------------------------------------------------------------------
406
417{
418public:
420 static constexpr std::size_t rank_v = 2;
422 static constexpr std::size_t radius_v = 1;
424 static constexpr std::size_t size_v = 3;
427
431 [[nodiscard]] static constexpr std::size_t radius() noexcept
432 {
433 return 1;
434 }
435
439 [[nodiscard]] static constexpr std::size_t size() noexcept
440 {
441 return 3;
442 }
443
450 template <typename F>
451 static constexpr void for_each_offset(const Coord_Vec<2> &center, F &&f)
452 {
453 // Two parity-independent edge-neighbours along the j axis.
454 f(Offset_Vec<2>{0, -1});
455 f(Offset_Vec<2>{0, 1});
456 // Third edge-neighbour points up or down depending on parity.
457 const ca_index_t parity = (center[0] + center[1]) & 1;
458 f(parity == 0 ? Offset_Vec<2>{1, 0} : Offset_Vec<2>{-1, 0});
459 }
460};
461
462// -----------------------------------------------------------------------
463// Custom neighborhood
464// -----------------------------------------------------------------------
465
473template <std::size_t N, std::size_t K, std::size_t Radius = 0>
475{
476 static_assert(N >= 1, "Custom_Neighborhood requires N >= 1");
477 static_assert(K >= 1, "Custom_Neighborhood requires K >= 1");
478
479 std::array<Offset_Vec<N>, K> offs_;
480
481public:
483 static constexpr std::size_t rank_v = N;
485 static constexpr std::size_t size_v = K;
487 static constexpr std::size_t radius_v = Radius;
490
495 constexpr explicit Custom_Neighborhood(std::array<Offset_Vec<N>, K> os) : offs_(os) {}
496
505 constexpr explicit Custom_Neighborhood(const Offset_Vec<N> (&os)[K])
506 {
507 for (std::size_t i = 0; i < K; ++i)
508 offs_[i] = os[i];
509 }
510
512 [[nodiscard]] constexpr std::size_t radius() const noexcept
513 {
514 std::size_t r = 0;
515 for (std::size_t k = 0; k < K; ++k)
516 for (std::size_t d = 0; d < N; ++d)
517 {
518 const auto v = offs_[k][d];
519 const std::size_t a = static_cast<std::size_t>(v < 0 ? -v : v);
520 if (a > r)
521 r = a;
522 }
523 return r;
524 }
525
527 [[nodiscard]] constexpr std::size_t size() const noexcept
528 {
529 return K;
530 }
531
533 [[nodiscard]] constexpr const std::array<Offset_Vec<N>, K> &offsets() const noexcept
534 {
535 return offs_;
536 }
537
543 template <typename F>
544 constexpr void for_each_offset(const Coord_Vec<N> & center, F &&f) const
545 {
546 (void)center;
547 for (const auto &o : offs_)
548 f(o);
549 }
550};
551
552// -----------------------------------------------------------------------
553// gather_neighbors: fills a caller-supplied buffer using at_safe.
554// -----------------------------------------------------------------------
555
568template <typename Nbh, typename L, typename T>
569inline void gather_neighbors(const Nbh &nh,
570 const L &lat,
571 const typename L::coord_type &center,
572 std::span<T> out)
573{
574 ah_length_error_if(out.size() < nh.size()) << "gather_neighbors: output span has size "
575 << out.size() << ", expected at least " << nh.size();
576 using Coord = typename L::coord_type;
577 std::size_t i = 0;
578 nh.for_each_offset(center,
579 [&](const auto &off)
580 {
581 Coord c = center;
582 for (std::size_t d = 0; d < L::rank; ++d)
583 c[d] = static_cast<ca_index_t>(c[d] + off[d]);
584 out[i] = static_cast<T>(lat.at_safe(c));
585 ++i;
586 });
587}
588
589} // namespace CA
590} // namespace Aleph
591
592#endif // TPL_CA_NEIGHBORHOOD_H
Exception handling system with formatted messages for Aleph-w.
#define ah_length_error_if(C)
Throws std::length_error if condition holds.
Definition ah-errors.H:703
size_t size_t int32_t * out
Definition ca-c-api.h:120
Common typedefs and tag types for the Cellular Automata module.
User-supplied list of offsets for arbitrary connectivity.
constexpr std::size_t radius() const noexcept
constexpr Custom_Neighborhood(std::array< Offset_Vec< N >, K > os)
Build a custom neighborhood from an std::array of offsets.
static constexpr std::size_t radius_v
Compile-time radius (0 if unknown).
static constexpr std::size_t rank_v
Lattice dimension.
constexpr Custom_Neighborhood(const Offset_Vec< N >(&os)[K])
Build a custom neighborhood from a braced offset list.
static constexpr std::size_t size_v
Number of neighbours.
constexpr void for_each_offset(const Coord_Vec< N > &center, F &&f) const
Apply a functor to each offset in the neighborhood.
std::array< Offset_Vec< N >, K > offs_
constexpr const std::array< Offset_Vec< N >, K > & offsets() const noexcept
Coord_Vec< N > coord_type
Coordinate type accepted by for_each_offset.
constexpr std::size_t size() const noexcept
Six-neighbour hex pattern in axial coordinates over a 2D lattice.
static constexpr void for_each_offset(const Coord_Vec< 2 > &center, F &&f)
Apply a functor to each of the six hex offsets.
Coord_Vec< 2 > coord_type
Coordinate type accepted by for_each_offset.
static constexpr std::size_t radius_v
Chebyshev radius (always 1 for hex grids).
static constexpr std::size_t rank_v
Lattice dimension.
static constexpr std::array< Offset_Vec< 2 >, 6 > offsets
The six axial-coordinate offsets of the hex neighborhood.
static constexpr std::size_t size() noexcept
Return the number of neighbours (always 6).
static constexpr std::size_t radius() noexcept
Return the radius of the neighborhood (always 1).
static constexpr std::size_t size_v
Number of neighbours (always 6).
Moore (Chebyshev) neighborhood of radius R in N dimensions.
constexpr std::size_t size() const noexcept
Return the number of neighbours in the neighborhood.
constexpr void for_each_offset(const Coord_Vec< N > &center, F &&f) const
Apply a functor to each offset in the neighborhood.
static constexpr std::size_t radius() noexcept
Return the Chebyshev radius of the neighborhood.
Coord_Vec< N > coord_type
Coordinate type accepted by for_each_offset.
static constexpr std::size_t size_v
Number of neighbours (excluding center).
static constexpr std::size_t radius_v
Chebyshev radius.
static constexpr std::size_t rank_v
Lattice dimension.
static constexpr std::array< Offset_Vec< N >, size_v > offsets
Compile-time, canonical-ordered offsets array.
Three edge-neighbours over a 2D lattice with parity coupling.
static constexpr std::size_t radius() noexcept
Return the radius of the neighborhood (always 1).
Coord_Vec< 2 > coord_type
Coordinate type accepted by for_each_offset.
static constexpr std::size_t radius_v
Chebyshev radius (always 1).
static constexpr std::size_t rank_v
Lattice dimension.
static constexpr std::size_t size_v
Number of neighbours (always 3).
static constexpr std::size_t size() noexcept
Return the number of neighbours (always 3).
static constexpr void for_each_offset(const Coord_Vec< 2 > &center, F &&f)
Apply a functor to the three parity-dependent triangle offsets.
Von Neumann (L1) neighborhood of radius R in N dimensions.
static constexpr std::array< Offset_Vec< N >, size_v > offsets
Compile-time, canonical-ordered offsets array.
constexpr void for_each_offset(const Coord_Vec< N > &center, F &&f) const
Apply a functor to each offset in the neighborhood.
static constexpr std::size_t rank_v
Lattice dimension.
static constexpr std::size_t size() noexcept
Return the number of neighbours in the neighborhood.
static constexpr std::size_t size_v
Number of neighbours (excluding center).
static constexpr std::size_t radius() noexcept
Return the L1 radius of the neighborhood.
static constexpr std::size_t radius_v
L1 radius.
Coord_Vec< N > coord_type
Coordinate type accepted by for_each_offset.
A coordinate type with N integral components.
#define N
Definition fib.C:294
__gmp_expr< T, __gmp_unary_expr< __gmp_expr< T, U >, __gmp_exp_function > > exp(const __gmp_expr< T, U > &expr)
Definition gmpfrxx.h:4077
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
constexpr std::size_t von_neumann_count() noexcept
Number of integer points in the L1 ball of radius R in N dimensions, excluding the origin.
constexpr std::size_t static_pow(std::size_t base, std::size_t exp) noexcept
Compile-time integer power.
constexpr auto compute_moore_offsets() noexcept
Generate the canonical-ordered list of Moore offsets for N/R.
constexpr auto compute_von_neumann_offsets() noexcept
Generate the canonical-ordered list of Von Neumann offsets for N/R (L1 radius).
@ R
Recovered (and immune).
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
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.
Coord_Vec< N > Offset_Vec
Default offset vector (aliases Coord_Vec).
Definition ca-traits.H:79
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
DynList< int > l1
static int * k
gsl_rng * r
C++20 concepts for the Cellular Automata module.