Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ca-frame-stream.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
47#ifndef CA_FRAME_STREAM_H
48#define CA_FRAME_STREAM_H
49
50#include <cstddef>
51#include <filesystem>
52#include <fstream>
53#include <iomanip>
54#include <ostream>
55#include <sstream>
56#include <string>
57#include <tuple>
58#include <utility>
59
60#include <ah-errors.H>
61#include <tpl_array.H>
62
63#include <ca-io.H>
64#include <ca-tikz.H>
65
66namespace Aleph {
67namespace CA {
68
79template <typename Sink, typename Lattice>
80concept Frame_Sink = requires(Sink &sink, std::size_t step, const Lattice &frame)
81{
82 sink.accept(step, frame);
83 sink.flush();
84};
85
92{
93 PGM,
94 PPM,
95 RLE,
96 CSV,
97 JSON,
98 TikZ
99};
100
120
121namespace ca_frame_stream_detail {
122
123inline const char *extension(Frame_Output_Format format) noexcept
124{
125 switch (format)
126 {
128 return ".pgm";
130 return ".ppm";
132 return ".rle";
134 return ".csv";
136 return ".json";
138 return ".tex";
139 }
140 return ".frame";
141}
142
143inline const char *format_name(Frame_Output_Format format) noexcept
144{
145 switch (format)
146 {
148 return "pgm";
150 return "ppm";
152 return "rle";
154 return "csv";
156 return "json";
158 return "tikz";
159 }
160 return "unknown";
161}
162
163inline std::string padded_step(std::size_t step, std::size_t width)
164{
165 std::ostringstream out;
166 out << std::setw(static_cast<int>(width)) << std::setfill('0') << step;
167 return out.str();
168}
169
170inline std::filesystem::path format_step_path(const std::filesystem::path &pattern,
171 const std::size_t step,
172 const std::size_t zero_pad)
173{
174 std::string text = pattern.string();
175 const std::string value = padded_step(step, zero_pad);
176 auto replace_all = [&](const std::string &needle)
177 {
178 std::size_t pos = 0;
179 bool changed = false;
180 while ((pos = text.find(needle, pos)) != std::string::npos)
181 {
182 text.replace(pos, needle.size(), value);
183 pos += value.size();
184 changed = true;
185 }
186 return changed;
187 };
188
189 if (replace_all("{step}"))
190 return std::filesystem::path(text);
191 if (replace_all("{}"))
192 return std::filesystem::path(text);
193 return pattern;
194}
195
196} // namespace ca_frame_stream_detail
197
212[[nodiscard]] inline std::filesystem::path format_step_path(const std::filesystem::path &pattern,
213 const std::size_t step,
214 const std::size_t zero_pad = 6)
215{
216 return ca_frame_stream_detail::format_step_path(pattern, step, zero_pad);
217}
218
231template <typename... Sinks>
233{
234 std::tuple<Sinks...> sinks_;
235
236public:
240 explicit Composite_Frame_Sink(Sinks... sinks) : sinks_(std::move(sinks)...) {}
241
246 template <std::size_t I>
248 {
249 return std::get<I>(sinks_);
250 }
251
256 template <std::size_t I>
257 [[nodiscard]] const auto &get() const noexcept
258 {
259 return std::get<I>(sinks_);
260 }
261
267 template <typename Lattice>
268 void accept(const std::size_t step, const Lattice &frame)
269 {
270 static_assert((Frame_Sink<Sinks, Lattice> and ...),
271 "Every child sink must satisfy Frame_Sink<Sink, Lattice>");
272 std::apply([&](auto &...sink)
273 {
274 (sink.accept(step, frame), ...);
275 }, sinks_);
276 }
277
279 void flush()
280 {
281 std::apply([](auto &...sink)
282 {
283 (sink.flush(), ...);
284 }, sinks_);
285 }
286};
287
299{
302
303 [[nodiscard]] std::filesystem::path frame_path(std::size_t step) const
304 {
305 return opts_.directory
308 }
309
310 template <typename Lattice>
311 void write_one(std::ostream &out, const Lattice &frame) const
312 {
313 switch (opts_.format)
314 {
317 break;
320 break;
323 break;
326 break;
329 break;
332 break;
333 }
334 }
335
336public:
349 {
350 ah_domain_error_if(opts_.stride == 0) << "Directory_Frame_Sink: stride must be positive";
351 std::error_code ec;
352 std::filesystem::create_directories(opts_.directory, ec);
353 ah_runtime_error_if(ec) << "Directory_Frame_Sink: cannot create directory '"
354 << opts_.directory.string() << "': " << ec.message();
355 }
356
361 {
362 return opts_;
363 }
364
372
383 template <typename Lattice>
384 void accept(std::size_t step, const Lattice &frame)
385 {
386 if (step % opts_.stride != 0)
387 return;
388 const std::filesystem::path path = frame_path(step);
389 std::ofstream out(path, std::ios::binary);
390 ah_runtime_error_if(not out) << "Directory_Frame_Sink::accept: cannot open '" << path.string()
391 << "'";
392 write_one(out, frame);
393 ah_runtime_error_if(not out) << "Directory_Frame_Sink::accept: write failed for '"
394 << path.string() << "'";
395 written_.append(std::pair{step, path});
396 }
397
408 void flush() const
409 {
411 return;
412 const std::filesystem::path path = opts_.directory / "manifest.csv";
413 std::ofstream out(path);
414 ah_runtime_error_if(not out) << "Directory_Frame_Sink::flush: cannot open '" << path.string()
415 << "'";
416 out << "step,format,path\n";
417 for (const auto &[step, frame] : written_)
418 {
419 // Escape the path as a quoted CSV field so commas, quotes or
420 // other separator-like characters in the path do not corrupt
421 // the manifest layout. Internal '"' are doubled per RFC 4180.
422 const std::string raw = frame.string();
423 std::string quoted;
424 quoted.reserve(raw.size() + 2);
425 quoted.push_back('"');
426 for (const char c : raw)
427 {
428 if (c == '"')
429 quoted.push_back('"');
430 quoted.push_back(c);
431 }
432 quoted.push_back('"');
433 out << step << ',' << ca_frame_stream_detail::format_name(opts_.format) << ',' << quoted
434 << '\n';
435 }
436 ah_runtime_error_if(not out) << "Directory_Frame_Sink::flush: write failed for '"
437 << path.string() << "'";
438 }
439
449 [[nodiscard]] std::string montage_command_hint(const std::string &output_file = "ca.mp4",
450 unsigned fps = 24) const
451 {
452 std::ostringstream cmd;
453 cmd << "ffmpeg -y -framerate " << fps << " -i "
454 << (opts_.directory
455 / (opts_.prefix + "_%0" + std::to_string(opts_.zero_pad) + "d"
457 .string()
458 << " -pix_fmt yuv420p " << output_file;
459 return cmd.str();
460 }
461};
462
463} // namespace CA
464} // namespace Aleph
465
466#endif // CA_FRAME_STREAM_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
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
File-format readers and writers for cellular-automata frames.
TikZ renderers for cellular-automata frames.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:250
Fan-out sink that forwards every frame to several sinks.
void accept(const std::size_t step, const Lattice &frame)
Forward a frame to every child sink.
void flush()
Flush every child sink in tuple order.
auto & get() noexcept
Return child sink I.
Composite_Frame_Sink(Sinks... sinks)
Construct the composite sink.
const auto & get() const noexcept
Return child sink I.
std::tuple< Sinks... > sinks_
Directory-backed sink for CA frames.
std::filesystem::path frame_path(std::size_t step) const
std::string montage_command_hint(const std::string &output_file="ca.mp4", unsigned fps=24) const
Return an ffmpeg command hint for the current frame sequence.
void accept(std::size_t step, const Lattice &frame)
Accept a frame and write it if it passes the stride filter.
Array< std::pair< std::size_t, std::filesystem::path > > written_
const Frame_Stream_Options & options() const noexcept
Return the immutable sink options.
const Array< std::pair< std::size_t, std::filesystem::path > > & written_frames() const noexcept
Return the frame files written so far.
void flush() const
Write the optional manifest.
void write_one(std::ostream &out, const Lattice &frame) const
Directory_Frame_Sink(Frame_Stream_Options opts)
Build a frame sink.
Lattice that adds boundary-aware access on top of a storage.
Concept implemented by sinks that consume CA frames.
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::string padded_step(std::size_t step, std::size_t width)
const char * extension(Frame_Output_Format format) noexcept
std::filesystem::path format_step_path(const std::filesystem::path &pattern, const std::size_t step, const std::size_t zero_pad)
const char * format_name(Frame_Output_Format format) noexcept
void write_pgm(std::ostream &out, const Lattice &frame, Mapper &&mapper, const NetPBM_Write_Options &opts={})
Write a binary PGM (P5) image.
Definition ca-io.H:1444
Frame_Output_Format
File format used by Directory_Frame_Sink.
@ JSON
JSON snapshot (.json)
@ PPM
binary NetPBM RGB (.ppm)
@ TikZ
TikZ picture (.tex)
@ PGM
binary NetPBM grayscale (.pgm)
void write_rle(std::ostream &out, const Lattice &frame, const RLE_Write_Options &opts={}, const typename Lattice::state_type &dead=typename Lattice::state_type{})
Write a 2D frame in Conway RLE format.
Definition ca-io.H:575
void write_ppm(std::ostream &out, const Lattice &frame, Mapper &&mapper, const NetPBM_Write_Options &opts={})
Write a binary PPM (P6) image.
Definition ca-io.H:1496
std::filesystem::path format_step_path(const std::filesystem::path &pattern, const std::size_t step, const std::size_t zero_pad=6)
Format a step-indexed file path.
void write_csv(std::ostream &out, const Lattice &frame, const CSV_Options &opts={})
Write a numeric CSV snapshot.
Definition ca-io.H:1207
void write_json(std::ostream &out, const Lattice &frame, const JSON_Write_Options &opts={})
Write a JSON snapshot.
Definition ca-io.H:1314
void render_lattice_tikz(std::ostream &out, const Lattice &frame, Palette &&palette, const Rect_Tikz_Options &opts={})
Render any supported 2D CA lattice as TikZ.
Definition ca-tikz.H:225
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
STL namespace.
Options controlling CSV output and input.
Definition ca-io.H:185
Options for directory-backed frame streams.
NetPBM_Write_Options netpbm_options
PGM/PPM options.
std::filesystem::path directory
destination directory
Frame_Output_Format format
exporter format
RLE_Write_Options rle_options
RLE options when format is RLE.
CSV_Options csv_options
CSV options when format is CSV.
std::string prefix
filename prefix
std::size_t stride
write every Nth step
JSON_Write_Options json_options
JSON options when format is JSON.
bool write_manifest
write manifest.csv
std::size_t zero_pad
step field width in filenames
Rect_Tikz_Options tikz_options
TikZ options when format is TikZ.
Options controlling JSON snapshot output.
Definition ca-io.H:196
Options controlling NetPBM output.
Definition ca-io.H:207
Options controlling Conway RLE output.
Definition ca-io.H:159
TikZ rendering options for rectangular frames.
Definition ca-tikz.H:74
CmdLine cmd
Definition testHash.C:48
Dynamic array container with automatic resizing.