40#ifndef CA_REPRODUCTION_SUPPORT_H
41#define CA_REPRODUCTION_SUPPORT_H
73namespace Reproductions {
108 const std::size_t min_value,
109 const std::size_t max_value,
110 const std::size_t
bins,
115 <<
"fit_log_log_histogram: invalid range or bin count";
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)
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));
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)
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);
138 points.emplace_back(std::log(x), std::log(
density));
142 <<
"fit_log_log_histogram: fewer than two populated bins";
146 for (
const auto &[x,
y] : points)
151 mean_x /=
static_cast<double>(points.size());
152 mean_y /=
static_cast<double>(points.size());
157 for (
const auto &[x,
y] : points)
159 const double dx = x -
mean_x;
160 const double dy =
y - mean_y;
171 fit.
points = points.size();
185 const std::vector<std::size_t> &samples)
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)
193 std::ofstream
out(path);
195 out <<
"size,count\n";
217template <
typename Lattice>
223 static_assert(
Lattice::rank == 2,
"morans_i_binary requires a rank-2 lattice");
256 auto centered = [=](
const auto value)
265 double denominator = 0.0;
266 double numerator = 0.0;
267 std::size_t weight = 0;
277 const double x = centered(
value);
278 denominator += x * x;
279 for (std::size_t
k = 0;
k < 4; ++
k)
292 if (weight == 0
or denominator == 0.0)
294 return (
static_cast<double>(
occupied) /
static_cast<double>(weight))
295 * (numerator / denominator);
334 std::uniform_int_distribution<ca_size_t> pick(0,
grid_.
size(0) - 1);
347 <<
"BTW_Sandpile::drop_at: coordinate out of range";
393 if (
grid_.
at({static_cast<ca_index_t>(r), static_cast<ca_index_t>(c)}) >= 4)
408 if (
row < 0
or column < 0
427 {
"spots", 0.0350, 0.0650},
428 {
"stripes", 0.0250, 0.0500},
429 {
"mitosis", 0.0367, 0.0649},
442 const std::uint64_t master_seed)
454 const double unit =
static_cast<double>(
h >> 11) * (1.0 / 9007199254740992.0);
455 const double noise = 0.02 * (
unit - 0.5);
470 const std::size_t
steps,
471 const std::uint64_t master_seed)
486 auto byte = [](
const double value)
488 const double bounded = std::clamp(
value, 0.0, 1.0);
489 return static_cast<std::uint8_t
>(255.0 * bounded + 0.5);
492 byte(1.2 * (1.0 -
cell.u)),
493 byte(1.0 - 1.8 *
cell.v)};
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);
516 std::vector<std::uint8_t>
raw;
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)
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]);
540 static constexpr std::array<std::uint8_t, 8>
signature{
541 0x89,
'P',
'N',
'G',
'\r',
'\n', 0x1a,
'\n'};
544 <<
"decode_native_png: invalid PNG signature";
547 std::vector<std::uint8_t>
idat;
549 while (pos + 12 <=
png.size())
551 const std::uint32_t len =
be32(
png, pos);
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);
562 <<
"decode_native_png: expected 8-bit RGB PNG";
564 else if (type ==
"IDAT")
566 idat.insert(
idat.end(), payload, payload + len);
568 else if (type ==
"IEND")
577 while (z + 5 <=
idat.size() - 4)
579 const bool final = (
idat[z] & 1u) != 0;
581 <<
"decode_native_png: expected stored deflate blocks";
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));
588 <<
"decode_native_png: invalid stored block length";
591 <<
"decode_native_png: truncated stored block";
593 idat.begin() +
static_cast<std::ptrdiff_t
>(z),
594 idat.begin() +
static_cast<std::ptrdiff_t
>(z + len));
601 =
static_cast<std::size_t
>(
decoded.height) * (1 + 3 *
static_cast<std::size_t
>(
decoded.width));
603 <<
"decode_native_png: unexpected scanline size";
614 std::ifstream
in(path, std::ios::binary);
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;
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])));
642 return static_cast<double>(difference) / (255.0 *
channels);
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}},
Exception handling system with formatted messages for Aleph-w.
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
#define ah_runtime_error_if(C)
Throws std::runtime_error if condition holds.
static int cell(const aleph_ca_engine_t *e, size_t r, size_t c)
size_t size_t int32_t value
size_t size_t int32_t * out
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().
const long double offset[]
Offset values indexed by symbol string length (bounded by MAX_OFFSET_INDEX)
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.
std::array< ca_index_t, N > Coord_Vec
Default coordinate vector.
double density(const Lattice &lat, const typename Lattice::state_type &s)
std::size_t ca_size_t
Unsigned size component used for extents and counts.
void write_png(std::ostream &out, const Lattice &frame, Mapper &&mapper)
Write a rank-2 frame as an 8-bit RGB PNG image.
Main namespace for Aleph-w library functions.
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.
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.
auto min_value(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute minimum value.
auto max_value(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute maximum value.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Zero-gradient (Neumann) boundary.
Out-of-range neighbours behave as if the lattice ended.
RGB byte triplet used by PPM exporters.
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.
double kill
removal rate k.
const char * name
filesystem-safe preset name.
Least-squares result for a log-log histogram.
double intercept
fitted log-space intercept.
double slope
fitted exponent.
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::uint32_t height
pixel height.
std::vector< std::uint8_t > raw
rows with one filter byte plus RGB bytes.
std::uint32_t width
pixel width.
In-place sequential update (no double buffer).
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.