Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ca_long_run_with_checkpoints_example.cc
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
32#include <charconv>
33#include <chrono>
34#include <cstddef>
35#include <cstdint>
36#include <filesystem>
37#include <iostream>
38#include <limits>
39#include <random>
40#include <string>
41#include <string_view>
42#include <system_error>
43#include <type_traits>
44
45#include <ca-checkpoint.H>
46#include <ca-traits.H>
47#include <tpl_ca_engine.H>
48#include <tpl_ca_lattice.H>
49#include <tpl_ca_neighborhood.H>
50#include <tpl_ca_rule.H>
51#include <tpl_ca_storage.H>
52
53using namespace Aleph;
54using namespace Aleph::CA;
55
56namespace
57{
58
61
64bool parse_u64(const char *text, std::uint64_t &out) noexcept
65{
66 if (text == nullptr)
67 return false;
68 std::string_view sv{text};
69 if (sv.empty() or sv.front() == '+' or sv.front() == '-')
70 return false;
71 std::uint64_t v = 0;
72 const auto [ptr, ec] = std::from_chars(sv.data(), sv.data() + sv.size(), v, 10);
73 if (ec != std::errc{} or ptr != sv.data() + sv.size())
74 return false;
75 out = v;
76 return true;
77}
78
79Grid seed_grid(const ca_size_t side)
80{
81 Grid g({side, side}, 0);
82 std::mt19937 rng(0xC0FFEE);
83 std::uniform_real_distribution<double> u(0.0, 1.0);
84 for (ca_size_t i = 0; i < side; ++i)
85 for (ca_size_t j = 0; j < side; ++j)
86 g.set({static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)},
87 u(rng) < 0.35 ? 1 : 0);
88 return g;
89}
90
91std::size_t alive_count(const Grid &g)
92{
93 std::size_t n = 0;
94 for (ca_size_t i = 0; i < g.size(0); ++i)
95 for (ca_size_t j = 0; j < g.size(1); ++j)
96 if (g.at({static_cast<ca_index_t>(i), static_cast<ca_index_t>(j)}) != 0)
97 ++n;
98 return n;
99}
100
101bool grids_equal(const Grid &a, const Grid &b)
102{
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)}))
107 return false;
108 return true;
109}
110
111} // namespace
112
113int main(int argc, char **argv)
114{
115 std::size_t steps = 200;
116 ca_size_t side = 24;
117 std::size_t every = 50;
118
119 // Helper: validate-and-assign with explicit overflow check against
120 // the destination type's max. On 64-bit platforms `std::size_t` and
121 // `std::uint64_t` coincide, but the check is essential for narrower
122 // size_t targets (32-bit) and documents intent.
123 auto assign_arg = [](const char *arg, const char *name, auto &dst) -> bool
124 {
125 using Target = std::remove_reference_t<decltype(dst)>;
126 std::uint64_t v = 0;
127 if (not parse_u64(arg, v))
128 {
129 std::cerr << "Invalid [" << name << "] (got '" << arg << "')\n";
130 return false;
131 }
132 if (v > static_cast<std::uint64_t>(std::numeric_limits<Target>::max()))
133 {
134 std::cerr << "Invalid [" << name << "] out of range\n";
135 return false;
136 }
137 dst = static_cast<Target>(v);
138 return true;
139 };
140
141 if (argc >= 2 and not assign_arg(argv[1], "steps", steps))
142 return 1;
143 if (argc >= 3 and not assign_arg(argv[2], "side", side))
144 return 1;
145 if (argc >= 4 and not assign_arg(argv[3], "every", every))
146 return 1;
147 if (side < 4 or every == 0)
148 {
149 std::cerr << "Invalid arguments: side >= 4, every >= 1\n";
150 return 1;
151 }
152
153 // Unique scratch directory for this run.
154 const auto tick = std::chrono::steady_clock::now().time_since_epoch().count();
155 const auto dir = std::filesystem::temp_directory_path()
156 / ("aleph_ca_longrun_" + std::to_string(static_cast<long long>(tick)));
157 std::filesystem::create_directories(dir);
158
159 std::cout << "Long-run example with periodic checkpoints\n";
160 std::cout << " steps=" << steps << " side=" << side
161 << " every=" << every << " steps\n";
162 std::cout << " checkpoint dir: " << dir.string() << "\n\n";
163
164 Grid initial = seed_grid(side);
165 std::cout << "Initial alive cells: " << alive_count(initial) << "\n\n";
166
167 // ---- Reference: uninterrupted run --------------------------------
169 reference.run(steps);
170 std::cout << "Reference run: " << reference.steps_run()
171 << " steps completed, alive=" << alive_count(reference.frame()) << "\n";
172
173 // ---- Working run with checkpoint observer ------------------------
176 (dir / "snap_{step}.bin").string(),
177 /*zero_pad=*/6);
178 working.on_post_step([&](std::size_t s, const Grid &f) { obs.on_step_end(s, f); });
179
180 // Run only `steps - every` steps to leave a tail to be replayed by
181 // the resume below. (If the user picks tiny values, fall back to
182 // running everything.)
183 const std::size_t partial = steps > every ? steps - every : steps;
184 working.run(partial);
185 std::cout << "Working run: " << working.steps_run() << " steps then 'crash'\n";
186
187 // ---- Simulated crash + resume from latest snapshot --------------
189 if (obs.last_path().empty())
190 {
191 // No periodic checkpoint was written (this happens when
192 // `partial < every`, so the observer never triggered). Fall
193 // back to a fresh start: the resumed engine simply begins at
194 // step 0 with the same seed pattern as the reference.
195 std::cout << "No checkpoint produced (partial < every); restarting fresh.\n";
197 }
198 else
199 {
200 std::cout << "Most recent checkpoint: " << obs.last_path().string() << "\n\n";
201 const Resume_Token token = load_checkpoint_into(resumed, obs.last_path());
202 std::cout << "Resumed engine from step " << token.header.step_count
203 << " (file=" << token.source_path.string() << ")\n";
204 }
205 // Continue until we reach the same total step count as the
206 // reference run.
207 const std::size_t remaining = steps - resumed.steps_run();
208 resumed.run(remaining);
209 std::cout << "Resumed run: " << resumed.steps_run()
210 << " steps completed, alive=" << alive_count(resumed.frame()) << "\n";
211
212 // ---- Verify reproducibility -------------------------------------
213 if (not grids_equal(reference.frame(), resumed.frame()))
214 {
215 std::cerr << "\nFAIL: resumed frame differs from reference\n";
216 return 1;
217 }
218 std::cout << "\nPASS — resumed frame is bit-by-bit identical to the "
219 "uninterrupted reference run.\n";
220
221 // Cleanup.
222 std::filesystem::remove_all(dir);
223 return 0;
224}
int main()
size_t steps
Definition ca-c-api.h:126
size_t size_t int32_t * out
Definition ca-c-api.h:120
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.
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.
static mt19937 rng
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 Game_Of_Life_Rule make_game_of_life_rule() noexcept
Build the canonical Game of Life rule.
std::size_t ca_size_t
Unsigned size component used for extents and counts.
Definition ca-traits.H:63
Resume_Token load_checkpoint_into(Engine &engine, const std::filesystem::path &path)
Restore an engine's state in-place from a checkpoint file.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
std::uint64_t step_count
Number of completed steps at save time.
Resume handle returned by load_checkpoint_into.
std::filesystem::path source_path
Path of the checkpoint file consumed by load.
Checkpoint_Header header
Validated header read from source_path.
The lattice wraps around on every axis.
Definition ca-traits.H:124
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).