51#include <system_error>
72bool parse_u64(
const char *text, std::uint64_t &
out)
noexcept
76 std::string_view
sv{text};
77 if (
sv.empty()
or sv.front() ==
'+' or sv.front() ==
'-')
80 const auto [ptr,
ec] = std::from_chars(
sv.data(),
sv.data() +
sv.size(), v, 10);
81 if (
ec != std::errc{}
or ptr !=
sv.data() +
sv.size())
91 std::uniform_real_distribution<double> u(0.0, 1.0);
94 g.set({static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)},
101 if (a.extents() != b.extents())
103 for (
ca_size_t i = 0; i < a.size(0); ++i)
104 for (
ca_size_t j = 0; j < a.size(1); ++j)
105 if (a.at({static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)})
106 != b.at({static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)}))
111std::size_t
byte_count(
const std::filesystem::path &p)
114 const auto sz = std::filesystem::file_size(p,
ec);
115 return ec ? 0 :
static_cast<std::size_t
>(sz);
120 const auto tick = std::chrono::steady_clock::now().time_since_epoch().count();
121 auto p = std::filesystem::temp_directory_path()
122 / (
"aleph_ca_ckpt_p17_" + tag +
"_"
123 + std::to_string(
static_cast<long long>(
tick)));
124 std::filesystem::create_directories(p);
130 std::cout <<
"\n=== " << title <<
" ===\n";
148 const auto raw_path = dir /
"snap.raw.bin";
149 const auto cmp_path = dir /
"snap.cmp.bin";
164 std::cout << std::fixed << std::setprecision(2);
165 std::cout <<
" side : " <<
side <<
" x " <<
side
166 <<
" (sparse, ~5% alive)\n";
167 std::cout <<
" raw file : " <<
raw_size <<
" bytes ("
168 <<
raw_path.filename().string() <<
")\n";
169 std::cout <<
" compressed file : " <<
cmp_size <<
" bytes ("
170 <<
cmp_path.filename().string() <<
")\n";
171 std::cout <<
" compression ratio: " << ratio <<
"x\n";
181 std::cerr <<
" FAIL: raw and compressed restores differ\n";
182 std::filesystem::remove_all(dir);
185 std::cout <<
" round-trip : PASS (raw == compressed)\n";
187 std::filesystem::remove_all(dir);
197 const auto t0 = std::chrono::steady_clock::now();
199 const auto t1 = std::chrono::steady_clock::now();
200 return std::chrono::duration<double, std::milli>(
t1 -
t0).count();
210 constexpr std::size_t
every = 16;
225 (dir /
"sync_{step}.bin").
string());
226 sync_eng.on_post_step([&](std::size_t s,
const Grid &f) {
sync_obs.on_step_end(s, f); });
237 (dir /
"async_{step}.bin").
string(),
239 async_eng.on_post_step([&](std::size_t s,
const Grid &f) {
async_obs.on_step_end(s, f); });
244 auto pct = [&](
double t)
247 std::cout << std::fixed << std::setprecision(2);
248 std::cout <<
" side : " <<
side <<
" x " <<
side <<
"\n";
249 std::cout <<
" steps : " <<
steps <<
"\n";
250 std::cout <<
" snapshot every : " <<
every <<
" steps\n";
251 std::cout <<
" queue capacity : " <<
queue_capacity <<
" (Block policy)\n";
252 std::cout <<
" baseline (no obs.) : " <<
t_baseline <<
" ms\n";
253 std::cout <<
" sync observer : " <<
t_sync <<
" ms ("
254 << std::showpos <<
pct(
t_sync) << std::noshowpos <<
"% vs baseline)\n";
255 std::cout <<
" async observer : " <<
t_async <<
" ms ("
256 << std::showpos <<
pct(
t_async) << std::noshowpos <<
"% vs baseline)\n";
257 std::cout <<
" async total written : " <<
writer.total_written() <<
"\n";
258 std::cout <<
" async total dropped : " <<
writer.total_dropped() <<
"\n";
263 std::cerr <<
" FAIL: observers altered the engine trajectory\n";
264 std::filesystem::remove_all(dir);
267 std::cout <<
" trajectory check : PASS (all three engines agree)\n";
269 std::filesystem::remove_all(dir);
281 const auto base_path = dir /
"baseline.bin";
295 const auto base_step =
static_cast<std::uint64_t
>(
eng.steps_run());
306 std::cout << std::fixed << std::setprecision(2);
307 std::cout <<
" side : " <<
side <<
" x " <<
side <<
"\n";
308 std::cout <<
" baseline step : " <<
base_step <<
"\n";
309 std::cout <<
" delta step : " <<
dh.step_count
311 std::cout <<
" baseline file : " <<
base_size <<
" bytes\n";
312 std::cout <<
" delta file : " <<
delta_size <<
" bytes ("
316 <<
"% of baseline)\n";
327 std::cerr <<
" FAIL: reconstructed step count "
329 std::filesystem::remove_all(dir);
334 std::cerr <<
" FAIL: reconstructed frame differs from live engine\n";
335 std::filesystem::remove_all(dir);
338 std::cout <<
" reconstruction : PASS (baseline + delta == live)\n";
340 std::filesystem::remove_all(dir);
348 std::string
mode =
"all";
350 std::size_t
steps = 200;
358 or v >
static_cast<std::uint64_t
>(std::numeric_limits<ca_size_t>::max()))
360 std::cerr <<
"Invalid [side] (got '" <<
argv[2] <<
"')\n";
369 or v >
static_cast<std::uint64_t
>(std::numeric_limits<std::size_t>::max()))
371 std::cerr <<
"Invalid [steps] (got '" <<
argv[3] <<
"')\n";
374 steps =
static_cast<std::size_t
>(v);
378 std::cerr <<
"Invalid arguments: side >= 8, steps >= 4\n";
382 std::cout <<
"ca_checkpoint_phase17_example\n";
383 std::cout <<
" mode = " <<
mode <<
"\n";
384 std::cout <<
" side = " <<
side <<
"\n";
385 std::cout <<
" steps = " <<
steps <<
"\n";
397 std::cerr <<
"\nUnknown mode '" <<
mode
398 <<
"' (expected: compress | async | delta | all)\n";
402 std::cout <<
"\n" << (
rc == 0 ?
"Overall: PASS" :
"Overall: FAIL") <<
"\n";
void print_section(const string &title)
size_t size_t int32_t * out
Binary checkpoint format for Aleph::CA engines (Phase 15 + Phase 17 crash-safe / compress / async wri...
Common typedefs and tag types for the Cellular Automata module.
Background writer pumping snapshots onto a dedicated thread.
Lattice that adds boundary-aware access on top of a storage.
Moore (Chebyshev) neighborhood of radius R in N dimensions.
Observer that auto-saves the engine state every every steps to a templated path.
Synchronous double-buffered engine.
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
std::vector< std::uint8_t > snapshot_frame_bytes(const Engine &engine)
Flatten an engine frame into a row-major byte buffer.
constexpr Game_Of_Life_Rule make_game_of_life_rule() noexcept
Build the canonical Game of Life rule.
Checkpoint_Header inspect_checkpoint(const std::filesystem::path &path)
Read just the header from a checkpoint file.
Resume_Token apply_delta_checkpoint(Engine &engine, const std::filesystem::path &path)
Apply a delta checkpoint to the engine's current state.
void save_delta_checkpoint(Engine &engine, const std::vector< std::uint8_t > &baseline, const std::uint64_t base_step, const std::filesystem::path &path, const Checkpoint_Options &options={})
Write a delta checkpoint relative to a previous payload.
std::size_t ca_size_t
Unsigned size component used for extents and counts.
Resume_Token load_checkpoint_into(Engine &engine, const std::filesystem::path &path)
Restore an engine's state in-place from a checkpoint file.
void save_checkpoint(Engine &engine, const std::filesystem::path &path, const Checkpoint_Options &options={})
Write a complete engine snapshot to disk atomically.
Main namespace for Aleph-w library functions.
and
Check uniqueness with explicit hash + equality functors.
auto mode(const Container &data) -> std::decay_t< decltype(*std::begin(data))>
Compute the mode (most frequent value).
User-tunable knobs for save_checkpoint.
bool compress
Enable DEFLATE compression of the frame payload.
The lattice wraps around on every axis.
Synchronous double-buffered engine for cellular automata.
Cellular automata lattice with pluggable boundary policies.
Neighborhoods catalogue for Aleph::CA.
Rule mechanisms for Aleph::CA.
Dense, contiguous storage for cellular automata cells (1D/2D/3D).