Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ca-metrics.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
67#ifndef CA_METRICS_H
68#define CA_METRICS_H
69
70#include <cmath>
71#include <cstddef>
72#include <cstdint>
73#include <type_traits>
74
75#include <ah-errors.H>
76#include <tpl_array.H>
77
78#include <ca-traits.H>
79#include <tpl_ca_concepts.H>
80
81namespace Aleph {
82namespace CA {
83
84namespace ca_metrics_detail {
85
87inline constexpr std::uint64_t fnv_basis = 14695981039346656037ull;
88inline constexpr std::uint64_t fnv_prime = 1099511628211ull;
89
91inline constexpr std::uint64_t fnv1a_step(std::uint64_t h, const std::uint8_t b) noexcept
92{
93 h ^= static_cast<std::uint64_t>(b);
94 h *= fnv_prime;
95 return h;
96}
97
99template <typename T>
100inline std::uint64_t fnv1a_mix(std::uint64_t h, const T &value) noexcept
101{
102 static_assert(std::is_trivially_copyable_v<T>,
103 "frame_hash requires trivially copyable cell states");
104 std::uint8_t buf[sizeof(T)];
105 // Defensive memcpy avoids strict-aliasing pitfalls.
106 __builtin_memcpy(buf, &value, sizeof(T));
107 for (std::size_t i = 0; i < sizeof(T); ++i)
108 h = fnv1a_step(h, buf[i]);
109 return h;
110}
111
113template <typename L>
114concept HasAtNode = requires(const L &l) { l.at_node(std::size_t{}); };
115
116} // namespace ca_metrics_detail
117
132template <typename Lattice, typename F>
133inline void for_each_cell(const Lattice &lat, F &&f)
134{
135 using coord_t = typename Lattice::coord_type;
137 {
138 const ca_size_t n = lat.size();
139 for (ca_size_t i = 0; i < n; ++i)
140 f(lat.at_node(i));
141 }
142 else if constexpr (Lattice::rank == 1)
143 {
144 const ca_size_t n0 = lat.size(0);
145 for (ca_size_t i = 0; i < n0; ++i)
146 f(lat.at(coord_t{static_cast<ca_index_t>(i)}));
147 }
148 else if constexpr (Lattice::rank == 2)
149 {
150 const ca_size_t n0 = lat.size(0);
151 const ca_size_t n1 = lat.size(1);
152 for (ca_size_t i = 0; i < n0; ++i)
153 for (ca_size_t j = 0; j < n1; ++j)
154 f(lat.at(coord_t{static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)}));
155 }
156 else if constexpr (Lattice::rank == 3)
157 {
158 const ca_size_t n0 = lat.size(0);
159 const ca_size_t n1 = lat.size(1);
160 const ca_size_t n2 = lat.size(2);
161 for (ca_size_t i = 0; i < n0; ++i)
162 for (ca_size_t j = 0; j < n1; ++j)
163 for (ca_size_t k = 0; k < n2; ++k)
164 f(lat.at(coord_t{static_cast<ca_index_t>(i), static_cast<ca_index_t>(j),
165 static_cast<ca_index_t>(k)}));
166 }
167 else
168 {
169 static_assert(Lattice::rank <= 3, "for_each_cell currently supports rank <= 3");
170 }
171}
172
174template <typename Lattice>
175[[nodiscard]] inline ca_size_t count_state(const Lattice &lat, const typename Lattice::state_type &s)
176{
177 ca_size_t cnt = 0;
178 for_each_cell(lat, [&](const auto &v)
179 {
180 if (v == s)
181 ++cnt;
182 });
183 return cnt;
184}
185
187template <typename Lattice>
189{
190 using state_t = typename Lattice::state_type;
191 const state_t dead{};
192 ca_size_t cnt = 0;
193 for_each_cell(lat, [&](const auto &v)
194 {
195 if (v != dead)
196 ++cnt;
197 });
198 return cnt;
199}
200
203template <typename Lattice>
204[[nodiscard]] inline ca_size_t total_cells(const Lattice &lat) noexcept
205{
206 return lat.size();
207}
208
211template <typename Lattice>
212[[nodiscard]] inline double density(const Lattice &lat, const typename Lattice::state_type &s)
213{
215 if (total == 0)
216 return 0.0;
217 return static_cast<double>(count_state(lat, s)) / static_cast<double>(total);
218}
219
222template <typename Lattice>
223[[nodiscard]] inline double alive_density(const Lattice &lat)
224{
226 if (total == 0)
227 return 0.0;
228 return static_cast<double>(count_alive(lat)) / static_cast<double>(total);
229}
230
240template <typename Lattice>
242{
244 for_each_cell(lat, [&](const auto &v)
245 {
246 using S = typename Lattice::state_type;
247 if constexpr (std::is_integral_v<S> or std::is_enum_v<S>)
248 {
249 const long long iv = static_cast<long long>(v);
250 if (iv >= 0 and iv < static_cast<long long>(max_state))
251 ++hist[static_cast<std::size_t>(iv)];
252 }
253 else
254 {
255 // Non-integral states are not classifiable into
256 // a small histogram; the caller should provide a
257 // bespoke metric. Suppress the unused parameter
258 // warning while keeping the signature uniform.
259 (void) v;
260 }
261 });
262 return hist;
263}
264
275template <typename Lattice>
276[[nodiscard]] inline double shannon_entropy(const Lattice &lat, std::size_t max_state)
277{
278 const auto hist = state_histogram(lat, max_state);
279 ca_size_t total = 0;
280 for (auto c : hist)
281 total += c;
282 if (total == 0)
283 return 0.0;
284 double h = 0.0;
285 const double inv = 1.0 / static_cast<double>(total);
286 for (auto c : hist)
287 if (c != 0)
288 {
289 const double p = static_cast<double>(c) * inv;
290 h -= p * std::log(p);
291 }
292 return h;
293}
294
310template <typename Lattice>
311[[nodiscard]] inline std::uint64_t frame_hash(const Lattice &lat)
312{
313 std::uint64_t h = ca_metrics_detail::fnv_basis;
314 for_each_cell(lat, [&](const auto &v)
315 {
316 h = ca_metrics_detail::fnv1a_mix(h, v);
317 });
318 return h;
319}
320
322template <typename Lattice>
323[[nodiscard]] inline bool frames_equal(const Lattice &a, const Lattice &b)
324{
325 if (a.extents() != b.extents())
326 return false;
327 using coord_t = typename Lattice::coord_type;
329 {
330 const ca_size_t n = a.size();
331 for (ca_size_t i = 0; i < n; ++i)
332 if (a.at_node(i) != b.at_node(i))
333 return false;
334 return true;
335 }
336 else if constexpr (Lattice::rank == 1)
337 {
338 const ca_size_t n0 = a.size(0);
339 for (ca_size_t i = 0; i < n0; ++i)
340 {
341 const coord_t c{static_cast<ca_index_t>(i)};
342 if (a.at(c) != b.at(c))
343 return false;
344 }
345 return true;
346 }
347 else if constexpr (Lattice::rank == 2)
348 {
349 const ca_size_t n0 = a.size(0);
350 const ca_size_t n1 = a.size(1);
351 for (ca_size_t i = 0; i < n0; ++i)
352 for (ca_size_t j = 0; j < n1; ++j)
353 {
354 const coord_t c{static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)};
355 if (a.at(c) != b.at(c))
356 return false;
357 }
358 return true;
359 }
360 else if constexpr (Lattice::rank == 3)
361 {
362 const ca_size_t n0 = a.size(0);
363 const ca_size_t n1 = a.size(1);
364 const ca_size_t n2 = a.size(2);
365 for (ca_size_t i = 0; i < n0; ++i)
366 for (ca_size_t j = 0; j < n1; ++j)
367 for (ca_size_t k = 0; k < n2; ++k)
368 {
369 const coord_t c{static_cast<ca_index_t>(i), static_cast<ca_index_t>(j),
370 static_cast<ca_index_t>(k)};
371 if (a.at(c) != b.at(c))
372 return false;
373 }
374 return true;
375 }
376 else
377 {
378 static_assert(Lattice::rank <= 3, "frames_equal currently supports rank <= 3");
379 return false;
380 }
381}
382
385template <typename Lattice>
386[[nodiscard]] inline ca_size_t cell_diff_count(const Lattice &a, const Lattice &b)
387{
389 << "cell_diff_count: lattices have different extents";
390
391 using coord_t = typename Lattice::coord_type;
392 ca_size_t diff = 0;
394 {
395 const ca_size_t n = a.size();
396 for (ca_size_t i = 0; i < n; ++i)
397 if (a.at_node(i) != b.at_node(i))
398 ++diff;
399 }
400 else if constexpr (Lattice::rank == 1)
401 {
402 const ca_size_t n0 = a.size(0);
403 for (ca_size_t i = 0; i < n0; ++i)
404 {
405 const coord_t c{static_cast<ca_index_t>(i)};
406 if (a.at(c) != b.at(c))
407 ++diff;
408 }
409 }
410 else if constexpr (Lattice::rank == 2)
411 {
412 const ca_size_t n0 = a.size(0);
413 const ca_size_t n1 = a.size(1);
414 for (ca_size_t i = 0; i < n0; ++i)
415 for (ca_size_t j = 0; j < n1; ++j)
416 {
417 const coord_t c{static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)};
418 if (a.at(c) != b.at(c))
419 ++diff;
420 }
421 }
422 else if constexpr (Lattice::rank == 3)
423 {
424 const ca_size_t n0 = a.size(0);
425 const ca_size_t n1 = a.size(1);
426 const ca_size_t n2 = a.size(2);
427 for (ca_size_t i = 0; i < n0; ++i)
428 for (ca_size_t j = 0; j < n1; ++j)
429 for (ca_size_t k = 0; k < n2; ++k)
430 {
431 const coord_t c{static_cast<ca_index_t>(i), static_cast<ca_index_t>(j),
432 static_cast<ca_index_t>(k)};
433 if (a.at(c) != b.at(c))
434 ++diff;
435 }
436 }
437 else
438 {
439 static_assert(Lattice::rank <= 3, "cell_diff_count currently supports rank <= 3");
440 }
441 return diff;
442}
443
444} // namespace CA
445} // namespace Aleph
446
447#endif // CA_METRICS_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
long double h
Definition btreepic.C:154
size_t size_t int32_t value
Definition ca-c-api.h:116
Common typedefs and tag types for the Cellular Automata module.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
Lattice that adds boundary-aware access on top of a storage.
typename Storage::state_type state_type
const extents_type & extents() const noexcept
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.
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1065
Detect whether L exposes a graph-style at_node(size_t) accessor.
Definition ca-metrics.H:114
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::uint64_t fnv1a_mix(std::uint64_t h, const T &value) noexcept
Mix every byte of value (in little-endian order) into an FNV-1a hash.
Definition ca-metrics.H:100
constexpr std::uint64_t fnv_basis
FNV-1a 64-bit basis and prime constants.
Definition ca-metrics.H:87
constexpr std::uint64_t fnv_prime
Definition ca-metrics.H:88
constexpr std::uint64_t fnv1a_step(std::uint64_t h, const std::uint8_t b) noexcept
Mix one byte into an FNV-1a hash.
Definition ca-metrics.H:91
double shannon_entropy(const Lattice &lat, std::size_t max_state)
Shannon entropy in nats of the [0, max_state) distribution.
Definition ca-metrics.H:276
@ S
Susceptible.
Array< ca_size_t > state_histogram(const Lattice &lat, std::size_t max_state)
Count occurrences of every integer state in [0, max_state).
Definition ca-metrics.H:241
std::ptrdiff_t ca_index_t
Signed coordinate component used by lattices and neighborhoods.
Definition ca-traits.H:60
ca_size_t total_cells(const Lattice &lat) noexcept
Definition ca-metrics.H:204
std::uint64_t frame_hash(const Lattice &lat)
Deterministic 64-bit FNV-1a hash of the lattice cells.
Definition ca-metrics.H:311
void for_each_cell(const Lattice &lat, F &&f)
Visit every cell of a lattice in canonical row-major order.
Definition ca-metrics.H:133
double density(const Lattice &lat, const typename Lattice::state_type &s)
Definition ca-metrics.H:212
ca_size_t count_state(const Lattice &lat, const typename Lattice::state_type &s)
Definition ca-metrics.H:175
ca_size_t count_alive(const Lattice &lat)
Definition ca-metrics.H:188
double alive_density(const Lattice &lat)
Definition ca-metrics.H:223
std::size_t ca_size_t
Unsigned size component used for extents and counts.
Definition ca-traits.H:63
ca_size_t cell_diff_count(const Lattice &a, const Lattice &b)
Definition ca-metrics.H:386
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
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
static int * k
Dynamic array container with automatic resizing.
C++20 concepts for the Cellular Automata module.
static bool frames_equal(const L &a, const L &b)
DynList< int > l