Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ca_reproduction_support.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
40#ifndef CA_REPRODUCTION_SUPPORT_H
41#define CA_REPRODUCTION_SUPPORT_H
42
43#include <algorithm>
44#include <array>
45#include <cmath>
46#include <cstddef>
47#include <cstdint>
48#include <filesystem>
49#include <fstream>
50#include <istream>
51#include <iterator>
52#include <map>
53#include <ostream>
54#include <random>
55#include <string>
56#include <utility>
57#include <vector>
58
59#include <ah-errors.H>
60
61#include <ca-png.H>
62#include <ca-rng.H>
63#include <ca-traits.H>
65#include <tpl_ca_engine.H>
66#include <tpl_ca_lattice.H>
67#include <tpl_ca_neighborhood.H>
68#include <tpl_ca_storage.H>
70
71namespace Aleph {
72namespace CA {
73namespace Reproductions {
74
80{
81 double slope = 0.0;
82 double intercept = 0.0;
83 double r_squared = 0.0;
84 std::size_t points = 0;
85};
86
107inline Linear_Fit fit_log_log_histogram(const std::vector<std::size_t> &samples,
108 const std::size_t min_value,
109 const std::size_t max_value,
110 const std::size_t bins,
111 const double sample_weight_power = 0.0)
112{
115 << "fit_log_log_histogram: invalid range or bin count";
116
117 const double lo = std::log(static_cast<double>(min_value));
118 const double hi = std::log(static_cast<double>(max_value) + 1.0);
119 const double width = (hi - lo) / static_cast<double>(bins);
120 std::vector<double> counts(bins, 0.0);
121 for (const std::size_t sample : samples)
122 if (sample >= min_value and sample <= max_value)
123 {
124 const double offset = (std::log(static_cast<double>(sample)) - lo) / width;
125 const std::size_t bin = (std::min) (bins - 1, static_cast<std::size_t>(offset));
126 counts[bin] += std::pow(static_cast<double>(sample), -sample_weight_power);
127 }
128
129 std::vector<std::pair<double, double>> points;
130 points.reserve(bins);
131 for (std::size_t i = 0; i < bins; ++i)
132 if (counts[i] != 0.0)
133 {
134 const double edge_lo = std::exp(lo + static_cast<double>(i) * width);
135 const double edge_hi = std::exp(lo + static_cast<double>(i + 1) * width);
136 const double x = std::sqrt(edge_lo * edge_hi);
137 const double density = static_cast<double>(counts[i]) / (edge_hi - edge_lo);
138 points.emplace_back(std::log(x), std::log(density));
139 }
140
141 ah_runtime_error_if(points.size() < 2)
142 << "fit_log_log_histogram: fewer than two populated bins";
143
144 double mean_x = 0.0;
145 double mean_y = 0.0;
146 for (const auto &[x, y] : points)
147 {
148 mean_x += x;
149 mean_y += y;
150 }
151 mean_x /= static_cast<double>(points.size());
152 mean_y /= static_cast<double>(points.size());
153
154 double xx = 0.0;
155 double xy = 0.0;
156 double yy = 0.0;
157 for (const auto &[x, y] : points)
158 {
159 const double dx = x - mean_x;
160 const double dy = y - mean_y;
161 xx += dx * dx;
162 xy += dx * dy;
163 yy += dy * dy;
164 }
165 ah_runtime_error_if(xx == 0.0) << "fit_log_log_histogram: degenerate x range";
166
167 Linear_Fit fit;
168 fit.slope = xy / xx;
169 fit.intercept = mean_y - fit.slope * mean_x;
170 fit.r_squared = yy == 0.0 ? 1.0 : (xy * xy) / (xx * yy);
171 fit.points = points.size();
172 return fit;
173}
174
184inline void write_histogram_csv(const std::filesystem::path &path,
185 const std::vector<std::size_t> &samples)
186{
187 if (const auto parent = path.parent_path(); not parent.empty())
188 std::filesystem::create_directories(parent);
189 std::map<std::size_t, std::size_t> histogram;
190 for (const std::size_t sample : samples)
191 ++histogram[sample];
192
193 std::ofstream out(path);
194 ah_runtime_error_if(not out) << "write_histogram_csv: cannot open '" << path.string() << "'";
195 out << "size,count\n";
196 for (const auto &[size, count] : histogram)
197 out << size << ',' << count << '\n';
198 ah_runtime_error_if(not out) << "write_histogram_csv: write failed for '" << path.string() << "'";
199}
200
217template <typename Lattice>
218[[nodiscard]] double morans_i_binary(const Lattice &frame,
219 const typename Lattice::state_type empty_state,
220 const typename Lattice::state_type type_a,
221 const typename Lattice::state_type type_b)
222{
223 static_assert(Lattice::rank == 2, "morans_i_binary requires a rank-2 lattice");
224 using Coord = typename Lattice::coord_type;
225
226 const ca_size_t rows = frame.size(0);
227 const ca_size_t cols = frame.size(1);
228 if (rows == 0 or cols == 0)
229 return 0.0;
230 std::size_t occupied = 0;
231 double sum = 0.0;
232 for (ca_size_t r = 0; r < rows; ++r)
233 for (ca_size_t c = 0; c < cols; ++c)
234 {
235 const auto value = frame.at(Coord{static_cast<ca_index_t>(r),
236 static_cast<ca_index_t>(c)});
237 if (value == type_a)
238 {
239 ++occupied;
240 sum += 1.0;
241 }
242 else if (value == type_b)
243 {
244 ++occupied;
245 sum -= 1.0;
246 }
247 else if (value != empty_state)
248 {
249 return 0.0;
250 }
251 }
252 if (occupied < 2)
253 return 0.0;
254
255 const double mean = sum / static_cast<double>(occupied);
256 auto centered = [=](const auto value)
257 {
258 if (value == type_a)
259 return 1.0 - mean;
260 if (value == type_b)
261 return -1.0 - mean;
262 return 0.0;
263 };
264
265 double denominator = 0.0;
266 double numerator = 0.0;
267 std::size_t weight = 0;
268 constexpr ca_index_t dr[] = {-1, 0, 1, 0};
269 constexpr ca_index_t dc[] = {0, 1, 0, -1};
270 for (ca_size_t r = 0; r < rows; ++r)
271 for (ca_size_t c = 0; c < cols; ++c)
272 {
273 const Coord here{static_cast<ca_index_t>(r), static_cast<ca_index_t>(c)};
274 const auto value = frame.at(here);
275 if (value == empty_state)
276 continue;
277 const double x = centered(value);
278 denominator += x * x;
279 for (std::size_t k = 0; k < 4; ++k)
280 {
281 const Coord there{
282 static_cast<ca_index_t>((r + rows + static_cast<ca_size_t>(dr[k] + 1) - 1) % rows),
283 static_cast<ca_index_t>((c + cols + static_cast<ca_size_t>(dc[k] + 1) - 1) % cols)};
284 const auto neighbour = frame.at(there);
285 if (neighbour == empty_state)
286 continue;
287 numerator += x * centered(neighbour);
288 ++weight;
289 }
290 }
291
292 if (weight == 0 or denominator == 0.0)
293 return 0.0;
294 return (static_cast<double>(occupied) / static_cast<double>(weight))
295 * (numerator / denominator);
296}
297
300{
301 std::size_t size = 0;
302 std::size_t duration = 0;
303};
304
313{
314public:
317
323 explicit BTW_Sandpile(const ca_size_t side, const std::uint64_t seed = 0)
324 : grid_({side, side}, 0), rng_(seed)
325 {
326 ah_domain_error_if(side == 0) << "BTW_Sandpile: side must be positive";
327 }
328
333 {
334 std::uniform_int_distribution<ca_size_t> pick(0, grid_.size(0) - 1);
335 return drop_at(pick(rng_), pick(rng_));
336 }
337
345 {
346 ah_domain_error_if(row >= grid_.size(0) or column >= grid_.size(1))
347 << "BTW_Sandpile::drop_at: coordinate out of range";
348 const Coord_Vec<2> drop{static_cast<ca_index_t>(row),
349 static_cast<ca_index_t>(column)};
350 grid_.set(drop, grid_.at(drop) + 1);
351
352 Avalanche avalanche;
353 while (true)
354 {
355 std::size_t sweep_topplings = 0;
356 for (ca_size_t r = 0; r < grid_.size(0); ++r)
357 for (ca_size_t c = 0; c < grid_.size(1); ++c)
358 {
359 const Coord_Vec<2> here{static_cast<ca_index_t>(r),
360 static_cast<ca_index_t>(c)};
361 if (grid_.at(here) < 4)
362 continue;
363 grid_.set(here, grid_.at(here) - 4);
364 add_if_inside(static_cast<ca_index_t>(r) - 1, static_cast<ca_index_t>(c));
365 add_if_inside(static_cast<ca_index_t>(r) + 1, static_cast<ca_index_t>(c));
366 add_if_inside(static_cast<ca_index_t>(r), static_cast<ca_index_t>(c) - 1);
367 add_if_inside(static_cast<ca_index_t>(r), static_cast<ca_index_t>(c) + 1);
369 }
370 if (sweep_topplings == 0)
371 break;
372 avalanche.size += sweep_topplings;
373 ++avalanche.duration;
374 }
375 return avalanche;
376 }
377
382 {
383 return grid_;
384 }
385
389 [[nodiscard]] bool stable() const
390 {
391 for (ca_size_t r = 0; r < grid_.size(0); ++r)
392 for (ca_size_t c = 0; c < grid_.size(1); ++c)
393 if (grid_.at({static_cast<ca_index_t>(r), static_cast<ca_index_t>(c)}) >= 4)
394 return false;
395 return true;
396 }
397
398private:
400 std::mt19937_64 rng_;
401
406 void add_if_inside(const ca_index_t row, const ca_index_t column)
407 {
408 if (row < 0 or column < 0
409 or row >= static_cast<ca_index_t>(grid_.size(0))
410 or column >= static_cast<ca_index_t>(grid_.size(1)))
411 return;
412 const Coord_Vec<2> coord{row, column};
413 grid_.set(coord, grid_.at(coord) + 1);
414 }
415};
416
419{
420 const char *name;
421 double feed;
422 double kill;
423};
424
426inline constexpr std::array<Gray_Scott_Preset, 3> gray_scott_presets{{
427 {"spots", 0.0350, 0.0650},
428 {"stripes", 0.0250, 0.0500},
429 {"mitosis", 0.0367, 0.0649},
430}};
431
434
442 const std::uint64_t master_seed)
443{
444 ah_domain_error_if(side < 8) << "make_gray_scott_seed: side must be at least 8";
445 Gray_Scott_Lattice frame({side, side}, Gray_Scott_Cell{1.0, 0.0});
446 const ca_size_t patch = (std::max) (ca_size_t{4}, side / 5);
447 const ca_size_t begin = side / 2 - patch / 2;
448 for (ca_size_t r = begin; r < begin + patch; ++r)
449 for (ca_size_t c = begin; c < begin + patch; ++c)
450 {
451 const Coord_Vec<2> coord{static_cast<ca_index_t>(r),
452 static_cast<ca_index_t>(c)};
453 const std::uint64_t h = cell_seed<2>(master_seed, 0, coord);
454 const double unit = static_cast<double>(h >> 11) * (1.0 / 9007199254740992.0);
455 const double noise = 0.02 * (unit - 0.5);
456 frame.set(coord, Gray_Scott_Cell{0.50 + noise, 0.25 - noise});
457 }
458 return frame;
459}
460
469 const ca_size_t side,
470 const std::size_t steps,
471 const std::uint64_t master_seed)
472{
473 Gray_Scott_Rule<double> rule(preset.feed, preset.kill, 0.16, 0.08);
475 engine(make_gray_scott_seed(side, master_seed), rule);
476 engine.run(steps);
477 return engine.frame();
478}
479
485{
486 auto byte = [](const double value)
487 {
488 const double bounded = std::clamp(value, 0.0, 1.0);
489 return static_cast<std::uint8_t>(255.0 * bounded + 0.5);
490 };
491 return RGB8{byte(2.2 * cell.v),
492 byte(1.2 * (1.0 - cell.u)),
493 byte(1.0 - 1.8 * cell.v)};
494}
495
501inline void write_gray_scott_png(const std::filesystem::path &path,
502 const Gray_Scott_Lattice &frame)
503{
504 if (const auto parent = path.parent_path(); not parent.empty())
505 std::filesystem::create_directories(parent);
506 std::ofstream out(path, std::ios::binary);
507 ah_runtime_error_if(not out) << "write_gray_scott_png: cannot open '" << path.string() << "'";
509}
510
513{
514 std::uint32_t width = 0;
515 std::uint32_t height = 0;
516 std::vector<std::uint8_t> raw;
517};
518
528inline Native_Png decode_native_png(std::istream &in)
529{
530 std::vector<std::uint8_t> png((std::istreambuf_iterator<char>(in)),
531 std::istreambuf_iterator<char>());
532 auto be32 = [](const std::vector<std::uint8_t> &bytes, const std::size_t pos)
533 {
534 return (static_cast<std::uint32_t>(bytes[pos]) << 24)
535 | (static_cast<std::uint32_t>(bytes[pos + 1]) << 16)
536 | (static_cast<std::uint32_t>(bytes[pos + 2]) << 8)
537 | static_cast<std::uint32_t>(bytes[pos + 3]);
538 };
539
540 static constexpr std::array<std::uint8_t, 8> signature{
541 0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n'};
542 ah_runtime_error_if(png.size() < signature.size()
543 or not std::equal(signature.begin(), signature.end(), png.begin()))
544 << "decode_native_png: invalid PNG signature";
545
547 std::vector<std::uint8_t> idat;
548 std::size_t pos = signature.size();
549 while (pos + 12 <= png.size())
550 {
551 const std::uint32_t len = be32(png, pos);
552 ah_runtime_error_if(pos + 12 + len > png.size())
553 << "decode_native_png: truncated chunk";
554 const std::string type(reinterpret_cast<const char *>(png.data() + pos + 4), 4);
555 const auto payload = png.begin() + static_cast<std::ptrdiff_t>(pos + 8);
556 if (type == "IHDR")
557 {
558 ah_runtime_error_if(len != 13) << "decode_native_png: malformed IHDR";
559 decoded.width = be32(png, pos + 8);
560 decoded.height = be32(png, pos + 12);
561 ah_runtime_error_if(png[pos + 16] != 8 or png[pos + 17] != 2)
562 << "decode_native_png: expected 8-bit RGB PNG";
563 }
564 else if (type == "IDAT")
565 {
566 idat.insert(idat.end(), payload, payload + len);
567 }
568 else if (type == "IEND")
569 {
570 break;
571 }
572 pos += 12 + len;
573 }
574
575 ah_runtime_error_if(idat.size() < 6) << "decode_native_png: IDAT too short";
576 std::size_t z = 2;
577 while (z + 5 <= idat.size() - 4)
578 {
579 const bool final = (idat[z] & 1u) != 0;
580 ah_runtime_error_if((idat[z] & 0x06u) != 0u)
581 << "decode_native_png: expected stored deflate blocks";
582 ++z;
583 const std::uint16_t len = static_cast<std::uint16_t>(idat[z]
584 | (idat[z + 1] << 8));
585 const std::uint16_t nlen = static_cast<std::uint16_t>(idat[z + 2]
586 | (idat[z + 3] << 8));
587 ah_runtime_error_if(static_cast<std::uint16_t>(~len) != nlen)
588 << "decode_native_png: invalid stored block length";
589 z += 4;
590 ah_runtime_error_if(z + len > idat.size() - 4)
591 << "decode_native_png: truncated stored block";
592 decoded.raw.insert(decoded.raw.end(),
593 idat.begin() + static_cast<std::ptrdiff_t>(z),
594 idat.begin() + static_cast<std::ptrdiff_t>(z + len));
595 z += len;
596 if (final)
597 break;
598 }
599
600 const std::size_t expected
601 = static_cast<std::size_t>(decoded.height) * (1 + 3 * static_cast<std::size_t>(decoded.width));
602 ah_runtime_error_if(decoded.width == 0 or decoded.height == 0 or decoded.raw.size() != expected)
603 << "decode_native_png: unexpected scanline size";
604 return decoded;
605}
606
612inline Native_Png read_native_png(const std::filesystem::path &path)
613{
614 std::ifstream in(path, std::ios::binary);
615 ah_runtime_error_if(not in) << "read_native_png: cannot open '" << path.string() << "'";
616 return decode_native_png(in);
617}
618
625inline double mean_channel_difference(const Native_Png &lhs,
626 const Native_Png &rhs)
627{
628 ah_domain_error_if(lhs.width != rhs.width or lhs.height != rhs.height)
629 << "mean_channel_difference: dimensions differ";
630 const std::size_t stride = 1 + 3 * static_cast<std::size_t>(lhs.width);
631 std::uint64_t difference = 0;
632 for (std::size_t row = 0; row < lhs.height; ++row)
633 {
634 ah_runtime_error_if(lhs.raw[row * stride] != 0 or rhs.raw[row * stride] != 0)
635 << "mean_channel_difference: expected filter type 0";
636 for (std::size_t i = 1; i < stride; ++i)
637 difference += static_cast<std::uint64_t>(
638 std::abs(static_cast<int>(lhs.raw[row * stride + i])
639 - static_cast<int>(rhs.raw[row * stride + i])));
640 }
641 const double channels = static_cast<double>(lhs.width) * lhs.height * 3.0;
642 return static_cast<double>(difference) / (255.0 * channels);
643}
644
646inline constexpr std::array<std::array<std::int64_t, 2>, 36> gosper_gun_cells{{
647 {{1, 5}}, {{1, 6}}, {{2, 5}}, {{2, 6}},
648 {{11, 5}}, {{11, 6}}, {{11, 7}}, {{12, 4}}, {{12, 8}},
649 {{13, 3}}, {{13, 9}}, {{14, 3}}, {{14, 9}},
650 {{15, 6}}, {{16, 4}}, {{16, 8}},
651 {{17, 5}}, {{17, 6}}, {{17, 7}}, {{18, 6}},
652 {{21, 3}}, {{21, 4}}, {{21, 5}},
653 {{22, 3}}, {{22, 4}}, {{22, 5}},
654 {{23, 2}}, {{23, 6}},
655 {{25, 1}}, {{25, 2}}, {{25, 6}}, {{25, 7}},
656 {{35, 3}}, {{35, 4}}, {{36, 3}}, {{36, 4}},
657}};
658
665template <typename F>
667 const std::int64_t offset_x = 0,
668 const std::int64_t offset_y = 0)
669{
670 for (const auto &cell : gosper_gun_cells)
671 visitor(offset_x + cell[0], offset_y + cell[1]);
672}
673
674} // namespace Reproductions
675} // namespace CA
676} // namespace Aleph
677
678#endif // CA_REPRODUCTION_SUPPORT_H
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:527
#define ah_runtime_error_if(C)
Throws std::runtime_error if condition holds.
Definition ah-errors.H:271
long double h
Definition btreepic.C:154
static int cell(const aleph_ca_engine_t *e, size_t r, size_t c)
Definition c_abi_smoke.c:53
size_t steps
Definition ca-c-api.h:126
size_t size_t int32_t value
Definition ca-c-api.h:116
size_t size_t int32_t * out
Definition ca-c-api.h:120
size_t row
Definition ca-c-api.h:115
size_t * rows
Definition ca-c-api.h:112
size_t cols
Definition ca-c-api.h:105
Dependency-free PNG frame sink for cellular automata.
Reproducible random-number support for stochastic CA rules (Phase 8).
Common typedefs and tag types for the Cellular Automata module.
Gray-Scott reaction-diffusion rule.
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::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.
Moore (Chebyshev) neighborhood of radius R in N dimensions.
Deterministic open-boundary Bak-Tang-Wiesenfeld sandpile.
Avalanche drop_at(const ca_size_t row, const ca_size_t column)
Drop one grain at (row, column) and stabilise.
void add_if_inside(const ca_index_t row, const ca_index_t column)
Add one grain when (row, column) lies inside the open grid.
const Grid & frame() const noexcept
Return the current stable grid.
BTW_Sandpile(const ca_size_t side, const std::uint64_t seed=0)
Construct an empty square sandpile.
bool stable() const
Test whether every cell is below the toppling threshold.
Avalanche drop_random()
Drop one grain at a uniformly selected cell and stabilise.
Synchronous double-buffered engine.
Minimal std::expected-style result type for C++20.
A coordinate type with N integral components.
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
const long double offset[]
Offset values indexed by symbol string length (bounded by MAX_OFFSET_INDEX)
static mpfr_t y
Definition mpfr_mul_d.c:3
RGB8 gray_scott_rgb(const Gray_Scott_Cell &cell)
Convert one Gray-Scott state to an RGB colour.
Linear_Fit fit_log_log_histogram(const std::vector< std::size_t > &samples, const std::size_t min_value, const std::size_t max_value, const std::size_t bins, const double sample_weight_power=0.0)
Fit a power-law exponent from logarithmically binned samples.
void for_each_gosper_gun_cell(F &&visitor, const std::int64_t offset_x=0, const std::int64_t offset_y=0)
Visit every live coordinate in the canonical Gosper gun.
constexpr std::array< std::array< std::int64_t, 2 >, 36 > gosper_gun_cells
Canonical 36-cell Gosper glider gun.
constexpr std::array< Gray_Scott_Preset, 3 > gray_scott_presets
Canonical visual presets used by the weekly Gray-Scott reproduction.
Native_Png decode_native_png(std::istream &in)
Decode a PNG emitted by Aleph::CA::write_png.
void write_histogram_csv(const std::filesystem::path &path, const std::vector< std::size_t > &samples)
Write an exact discrete histogram as CSV.
Gray_Scott_Lattice run_gray_scott(const Gray_Scott_Preset &preset, const ca_size_t side, const std::size_t steps, const std::uint64_t master_seed)
Run one Gray-Scott preset from the shared deterministic seed.
double morans_i_binary(const Lattice &frame, const typename Lattice::state_type empty_state, const typename Lattice::state_type type_a, const typename Lattice::state_type type_b)
Compute Moran's I for two occupied Schelling cell types.
double mean_channel_difference(const Native_Png &lhs, const Native_Png &rhs)
Compute normalized mean absolute per-channel PNG difference.
Gray_Scott_Lattice make_gray_scott_seed(const ca_size_t side, const std::uint64_t master_seed)
Build the deterministic finite-amplitude Gray-Scott perturbation.
void write_gray_scott_png(const std::filesystem::path &path, const Gray_Scott_Lattice &frame)
Write a Gray-Scott frame as a native Aleph RGB PNG.
Native_Png read_native_png(const std::filesystem::path &path)
Read and decode a native Aleph PNG.
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
double density(const Lattice &lat, const typename Lattice::state_type &s)
Definition ca-metrics.H:212
std::size_t ca_size_t
Unsigned size component used for extents and counts.
Definition ca-traits.H:63
void write_png(std::ostream &out, const Lattice &frame, Mapper &&mapper)
Write a rank-2 frame as an 8-bit RGB PNG image.
Definition ca-png.H:171
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
auto histogram(const Container &data, size_t num_bins) -> std::vector< std::pair< std::decay_t< decltype(*std::begin(data))>, size_t > >
Compute a histogram of the data.
Definition stat_utils.H:717
size_t size(Node *root) noexcept
and
Check uniqueness with explicit hash + equality functors.
auto mean(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute the arithmetic mean.
Definition stat_utils.H:190
auto min_value(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute minimum value.
Definition stat_utils.H:272
auto max_value(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute maximum value.
Definition stat_utils.H:294
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Zero-gradient (Neumann) boundary.
Definition ca-traits.H:152
Out-of-range neighbours behave as if the lattice ended.
Definition ca-traits.H:119
RGB byte triplet used by PPM exporters.
Definition ca-io.H:85
Two-field state for reaction-diffusion cellular automata.
Avalanche measurements for one BTW grain drop.
std::size_t duration
number of non-empty row-major sweeps.
std::size_t size
number of topplings.
One named Gray-Scott parameter preset.
const char * name
filesystem-safe preset name.
Least-squares result for a log-log histogram.
double intercept
fitted log-space intercept.
std::size_t points
populated bins included in the fit.
double r_squared
coefficient of determination.
Decoded subset of the dependency-free native PNG format.
std::vector< std::uint8_t > raw
rows with one filter byte plus RGB bytes.
In-place sequential update (no double buffer).
ValueArg< size_t > seed
Definition testHash.C:53
static int * k
static mt19937 engine
gsl_rng * r
Continuous and memory-bearing CA rules (Phase 9).
Synchronous double-buffered engine for cellular automata.
Cellular automata lattice with pluggable boundary policies.
Neighborhoods catalogue for Aleph::CA.
Dense, contiguous storage for cellular automata cells (1D/2D/3D).
Phase 13 update-scheme strategies for Aleph::CA.