Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ca_io_test.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 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
36#include <cstdint>
37#include <set>
38#include <sstream>
39#include <stdexcept>
40#include <string>
41#include <utility>
42
43#include <gtest/gtest.h>
44
45#include <ca-io.H>
46#include <tpl_ca_lattice.H>
47#include <tpl_ca_storage.H>
48
49using namespace Aleph::CA;
50
51namespace
52{
55 using Cell = std::pair<ca_index_t, ca_index_t>;
56
58 std::initializer_list<Cell> alive)
59 {
60 Grid g({rows, cols}, 0);
61 for (const auto &c : alive)
62 g.set({c.first, c.second}, 1);
63 return g;
64 }
65
66 Grid make_values_grid()
67 {
68 Grid g({2, 3}, 0);
69 int v = 1;
70 for (ca_index_t r = 0; r < 2; ++r)
71 for (ca_index_t c = 0; c < 3; ++c)
72 g.set({r, c}, v++);
73 return g;
74 }
75
76 std::set<Cell> alive_cells(const Grid &g)
77 {
78 std::set<Cell> out;
79 for (ca_index_t r = 0; r < static_cast<ca_index_t>(g.size(0)); ++r)
80 for (ca_index_t c = 0; c < static_cast<ca_index_t>(g.size(1)); ++c)
81 if (g.at({r, c}) != 0)
82 out.insert({r, c});
83 return out;
84 }
85
86 void expect_same_frame(const Grid &a, const Grid &b)
87 {
88 ASSERT_EQ(a.size(0), b.size(0));
89 ASSERT_EQ(a.size(1), b.size(1));
90 for (ca_index_t r = 0; r < static_cast<ca_index_t>(a.size(0)); ++r)
91 for (ca_index_t c = 0; c < static_cast<ca_index_t>(a.size(1)); ++c)
92 EXPECT_EQ(a.at({r, c}), b.at({r, c})) << "at (" << r << ", " << c << ")";
93 }
94
95 std::string bytes(std::initializer_list<unsigned> values)
96 {
97 std::string out;
98 for (const unsigned v : values)
100 return out;
101 }
102}
103
105{
106 const Grid src = make_grid(4, 5, {{1, 2}, {2, 3}, {3, 1}, {3, 2}, {3, 3}});
108 opts.name = "glider";
109 opts.comment = "full-frame snapshot";
110
111 const std::string rle = write_rle_string(src, opts);
112 EXPECT_NE(rle.find("#N glider"), std::string::npos);
113 EXPECT_NE(rle.find("#C full-frame snapshot"), std::string::npos);
114 EXPECT_NE(rle.find("x = 5, y = 4, rule = B3/S23"), std::string::npos);
115
116 const RLE_Pattern pattern = read_rle_string(rle);
117 EXPECT_EQ(pattern.width, 5u);
118 EXPECT_EQ(pattern.height, 4u);
119 EXPECT_EQ(pattern.rule, "B3/S23");
120 const Grid dst = make_lattice_from_pattern<Grid>(pattern);
122}
123
125{
126 const Grid src = make_grid(6, 7, {{2, 3}, {3, 4}, {4, 2}, {4, 3}, {4, 4}});
128 opts.trim_dead_border = true;
129 opts.line_width = 0;
130
131 const std::string rle = write_rle_string(src, opts);
132 EXPECT_NE(rle.find("x = 3, y = 3, rule = B3/S23"), std::string::npos);
133 EXPECT_NE(rle.find("bob$2bo$3o!"), std::string::npos) << rle;
134
137 (std::set<Cell>{{0, 1}, {1, 2}, {2, 0}, {2, 1}, {2, 2}}));
138}
139
141{
142 const std::string text =
143 "#N mixed dialect\n"
144 "#C A is accepted as alive and . as dead\n"
145 "x = 5, y = 3, rule = B36/S23\n"
146 "2A3b$5.$4bo!\n";
147 const RLE_Pattern pattern = read_rle_string(text);
148 EXPECT_EQ(pattern.name, "mixed dialect");
149 ASSERT_EQ(pattern.comments.size(), 1u);
150 EXPECT_EQ(pattern.rule, "B36/S23");
151 EXPECT_EQ(pattern.width, 5u);
152 EXPECT_EQ(pattern.height, 3u);
153 EXPECT_EQ(pattern.alive,
154 (Array<Coord_Vec<2>>{{0, 0}, {0, 1}, {2, 4}}));
155}
156
158{
159 EXPECT_THROW(read_rle_string("3o!\n"), std::domain_error);
160 EXPECT_THROW(read_rle_string("x = 2, y = 1\n3o!\n"), std::domain_error);
161 EXPECT_THROW(read_rle_string("x = 2, y = 1\n2"), std::domain_error);
162 EXPECT_THROW(read_rle_string("x = 2, y = 1\nbo?\n"), std::domain_error);
163}
164
166{
167 const Grid src = make_grid(3, 4, {{0, 1}, {1, 2}, {2, 0}, {2, 1}, {2, 2}});
169 opts.comment = "plaintext glider";
170 const std::string text = write_plaintext_string(src, opts);
171 EXPECT_NE(text.find("!plaintext glider"), std::string::npos);
172 EXPECT_NE(text.find(".O.."), std::string::npos);
173
174 const Binary_Cell_Pattern pattern = read_plaintext_string(text);
175 EXPECT_EQ(pattern.width, 4u);
176 EXPECT_EQ(pattern.height, 3u);
177 const Grid dst = make_lattice_from_pattern<Grid>(pattern);
179}
180
182{
183 const Binary_Cell_Pattern pattern = read_plaintext_string("!demo\n*..\n.O.\n");
184 EXPECT_EQ(pattern.width, 3u);
185 EXPECT_EQ(pattern.height, 2u);
186 EXPECT_EQ(pattern.alive, (Array<Coord_Vec<2>>{{0, 0}, {1, 1}}));
187 EXPECT_THROW(read_plaintext_string(".X.\n"), std::domain_error);
188}
189
191{
192 const std::string text =
193 "#Life 1.06\n"
194 "#D shifted pair\n"
195 "-2 -1\n"
196 "0 1\n";
197 std::istringstream in(text);
198 const Binary_Cell_Pattern pattern = read_life_106(in);
199 EXPECT_EQ(pattern.origin_col, -2);
200 EXPECT_EQ(pattern.origin_row, -1);
201 EXPECT_EQ(pattern.width, 3u);
202 EXPECT_EQ(pattern.height, 3u);
203 EXPECT_EQ(pattern.alive, (Array<Coord_Vec<2>>{{0, 0}, {2, 2}}));
204}
205
207{
208 const Grid src = make_grid(3, 3, {{0, 2}, {2, 0}});
209 std::ostringstream out;
210 write_life_106(out, src);
211
212 std::istringstream in(out.str());
213 const Binary_Cell_Pattern pattern = read_life_106(in);
214 EXPECT_EQ(pattern.width, 3u);
215 EXPECT_EQ(pattern.height, 3u);
216 EXPECT_EQ(pattern.alive, (Array<Coord_Vec<2>>{{0, 2}, {2, 0}}));
217}
218
220{
221 const Grid src = make_grid(3, 4, {{0, 0}, {1, 2}, {2, 3}});
222 std::ostringstream out;
223 write_life_105(out, src, "single block");
224 EXPECT_NE(out.str().find("#Life 1.05"), std::string::npos);
225 EXPECT_NE(out.str().find("#P 0 0"), std::string::npos);
226
227 std::istringstream in(out.str());
228 const Binary_Cell_Pattern pattern = read_life_105(in);
229 const Grid dst = make_lattice_from_pattern<Grid>(pattern);
231}
232
234{
235 const std::string text =
236 "#Life 1.05\n"
237 "#P -1 -1\n"
238 "*.\n"
239 ".*\n"
240 "#P 2 0\n"
241 "*\n";
242 std::istringstream in(text);
243 const Binary_Cell_Pattern pattern = read_life_105(in);
244 EXPECT_EQ(pattern.origin_col, -1);
245 EXPECT_EQ(pattern.origin_row, -1);
246 EXPECT_EQ(pattern.width, 4u);
247 EXPECT_EQ(pattern.height, 2u);
248 EXPECT_EQ(pattern.alive,
249 (Array<Coord_Vec<2>>{{0, 0}, {1, 1}, {1, 3}}));
250}
251
253{
254 const Grid src = make_values_grid();
256 opts.delimiter = ';';
257
258 std::ostringstream out;
259 write_csv(out, src, opts);
260 EXPECT_EQ(out.str(), "1;2;3\n4;5;6\n");
261
262 std::istringstream in(out.str());
266}
267
269{
270 {
271 std::istringstream in("1,2\n3\n");
272 EXPECT_THROW(read_csv_snapshot<int>(in), std::domain_error);
273 }
274 {
275 std::istringstream in("1,x\n");
276 EXPECT_THROW(read_csv_snapshot<int>(in), std::domain_error);
277 }
278}
279
281{
282 const Grid src = make_values_grid();
284 opts.pretty = true;
285 opts.rule = "demo";
286
287 std::ostringstream out;
288 write_json(out, src, opts);
289 EXPECT_NE(out.str().find("\"type\": \"Aleph::CA::frame\""), std::string::npos);
290 EXPECT_NE(out.str().find("\"rule\": \"demo\""), std::string::npos);
291
292 std::istringstream in(out.str());
296}
297
299{
300 ByteGrid frame({1, 3}, std::uint8_t{0});
301 frame.set({0, 0}, std::uint8_t{7});
302 frame.set({0, 1}, std::uint8_t{42});
303 frame.set({0, 2}, std::uint8_t{255});
304
305 std::ostringstream csv;
306 write_csv(csv, frame);
307 EXPECT_EQ(csv.str(), "7,42,255\n");
308
309 std::ostringstream json;
310 write_json(json, frame);
311 EXPECT_NE(json.str().find("\"cells\":[[7,42,255]]"), std::string::npos);
312}
313
315{
316 std::istringstream in(
317 "{\"type\":\"Aleph::CA::frame\",\"rank\":2,\"height\":1,\"width\":2,"
318 "\"cells\":[[1,2],[3,4]]}");
319 EXPECT_THROW(read_json_snapshot<int>(in), std::domain_error);
320}
321
323{
324 const Grid frame = make_grid(2, 2, {{0, 0}, {1, 1}});
325 std::ostringstream out;
326 {
328 stream.accept(0, frame);
329 stream.accept(4, frame);
330 stream.close();
331 }
332 EXPECT_NE(out.str().find("\"type\": \"Aleph::CA::frame-stream\""), std::string::npos);
333 EXPECT_NE(out.str().find("\"step\": 0"), std::string::npos);
334 EXPECT_NE(out.str().find("\"step\": 4"), std::string::npos);
335 EXPECT_NE(out.str().find("\"cells\":[[1,0],[0,1]]"), std::string::npos);
336}
337
339{
340 const Grid frame = make_grid(2, 3, {{0, 1}, {1, 2}});
341 std::ostringstream out(std::ios::binary);
342 write_pgm(out, frame);
343
344 std::string expected = "P5\n3 2\n255\n";
345 expected += bytes({255, 0, 255, 255, 255, 0});
346 EXPECT_EQ(out.str(), expected);
347}
348
350{
351 const Grid frame = make_grid(1, 2, {{0, 1}});
352 std::ostringstream out(std::ios::binary);
353 write_ppm(out, frame, [](int v)
354 {
355 return v == 0 ? RGB8{1, 2, 3} : RGB8{250, 0, 7};
356 });
357
358 std::string expected = "P6\n2 1\n255\n";
359 expected += bytes({1, 2, 3, 250, 0, 7});
360 EXPECT_EQ(out.str(), expected);
361}
size_t size_t int32_t * out
Definition ca-c-api.h:120
size_t * rows
Definition ca-c-api.h:112
size_t cols
Definition ca-c-api.h:105
File-format readers and writers for cellular-automata frames.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:365
Streaming JSON writer for CA trajectories.
Definition ca-io.H:1546
Lattice that adds boundary-aware access on top of a storage.
Minimal std::expected-style result type for C++20.
#define TEST(name)
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
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
void write_life_105(std::ostream &out, const Lattice &frame, const std::string &comment={}, const typename Lattice::state_type &dead=typename Lattice::state_type{})
Write a Life 1.05 file.
Definition ca-io.H:1072
Binary_Cell_Pattern read_plaintext_string(const std::string &s)
Read a Life plaintext pattern from a string.
Definition ca-io.H:961
void write_life_106(std::ostream &out, const Lattice &frame, const typename Lattice::state_type &dead=typename Lattice::state_type{})
Write a Life 1.06 file.
Definition ca-io.H:981
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
std::string write_plaintext_string(const Lattice &frame, const Plaintext_Write_Options &opts={}, const typename Lattice::state_type &dead=typename Lattice::state_type{})
Return a Life plaintext document.
Definition ca-io.H:897
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
Binary_Cell_Pattern read_life_105(std::istream &in)
Read a Life 1.05 pattern.
Definition ca-io.H:1106
void write_csv(std::ostream &out, const Lattice &frame, const CSV_Options &opts={})
Write a numeric CSV snapshot.
Definition ca-io.H:1207
std::string write_rle_string(const Lattice &frame, const RLE_Write_Options &opts={}, const typename Lattice::state_type &dead=typename Lattice::state_type{})
Return a frame encoded as Conway RLE.
Definition ca-io.H:668
RLE_Pattern read_rle_string(const std::string &s)
Read a Conway RLE pattern from a string.
Definition ca-io.H:785
Binary_Cell_Pattern read_life_106(std::istream &in)
Read a Life 1.06 pattern.
Definition ca-io.H:1007
void write_json(std::ostream &out, const Lattice &frame, const JSON_Write_Options &opts={})
Write a JSON snapshot.
Definition ca-io.H:1314
std::size_t ca_size_t
Unsigned size component used for extents and counts.
Definition ca-traits.H:63
Binary pattern shared by RLE, plaintext and Life formats.
Definition ca-io.H:104
std::string name
optional pattern name
Definition ca-io.H:110
ca_index_t origin_row
original row offset before normalisation
Definition ca-io.H:107
ca_size_t height
number of rows
Definition ca-io.H:106
ca_size_t width
number of columns
Definition ca-io.H:105
Array< std::string > comments
format comments without marker prefixes
Definition ca-io.H:111
ca_index_t origin_col
original column offset before normalisation
Definition ca-io.H:108
std::string rule
optional rule string, e.g. B3/S23
Definition ca-io.H:109
Array< Coord_Vec< 2 > > alive
live cells as {row, col}
Definition ca-io.H:112
Options controlling CSV output and input.
Definition ca-io.H:185
char delimiter
separator between cells
Definition ca-io.H:186
Dense numeric snapshot used by CSV and JSON readers.
Definition ca-io.H:128
Options controlling JSON snapshot output.
Definition ca-io.H:196
bool pretty
pretty-print with indentation
Definition ca-io.H:197
Out-of-range neighbours behave as if the lattice ended.
Definition ca-traits.H:119
Options controlling Life plaintext output.
Definition ca-io.H:173
std::string comment
optional ! comments, split on newlines
Definition ca-io.H:176
RGB byte triplet used by PPM exporters.
Definition ca-io.H:85
Options controlling Conway RLE output.
Definition ca-io.H:159
bool trim_dead_border
crop to the live-cell bounding box
Definition ca-io.H:163
std::string name
optional #N line
Definition ca-io.H:161
gsl_rng * r
Cellular automata lattice with pluggable boundary policies.
Dense, contiguous storage for cellular automata cells (1D/2D/3D).