32#include <gtest/gtest.h>
57 std::uint32_t width = 0;
58 std::uint32_t height = 0;
59 std::vector<std::uint8_t> raw;
74 return static_cast<long long>(
_getpid());
76 return static_cast<long long>(
getpid());
89 static std::atomic<unsigned long long>
counter{0};
90 const auto tick = std::chrono::steady_clock::now().time_since_epoch().count();
91 return std::filesystem::temp_directory_path()
92 / (name +
"_" + std::to_string(
static_cast<long long>(
tick)) +
93 "_" + std::to_string(process_id()) +
94 "_" + std::to_string(
counter++));
97 std::string
read_file(
const std::filesystem::path &path,
const bool binary =
false)
99 std::ifstream
in(path,
binary ? std::ios::binary :
std::ios::
in);
100 std::ostringstream
out;
105 std::uint32_t
be32(
const std::string &s, std::size_t pos)
107 return (
static_cast<std::uint32_t
>(
static_cast<unsigned char>(s[pos])) << 24)
108 | (
static_cast<std::uint32_t
>(
static_cast<unsigned char>(s[pos + 1])) << 16)
109 | (
static_cast<std::uint32_t
>(
static_cast<unsigned char>(s[pos + 2])) << 8)
110 |
static_cast<std::uint32_t
>(
static_cast<unsigned char>(s[pos + 3]));
120 EXPECT_EQ(
png.substr(0, 8), std::string(
"\x89PNG\r\n\x1a\n", 8));
125 while (pos + 12 <=
png.size())
127 const std::uint32_t len =
be32(
png, pos);
128 const std::string type =
png.substr(pos + 4, 4);
129 const std::string payload =
png.substr(pos + 8, len);
134 EXPECT_EQ(
static_cast<unsigned char>(payload[8]), 8u);
135 EXPECT_EQ(
static_cast<unsigned char>(payload[9]), 2u);
137 else if (type ==
"IDAT")
141 else if (type ==
"IEND")
148 if (
idat.size() < 6u)
154 while (z + 5 <=
idat.size() - 4)
156 const bool final = (
static_cast<unsigned char>(
idat[z]) & 1u) != 0;
157 if ((
static_cast<unsigned char>(
idat[z]) & 0x06u) != 0u)
159 ADD_FAILURE() <<
"compressed PNG block was not stored";
163 const std::uint16_t len =
static_cast<std::uint16_t
>(
164 static_cast<unsigned char>(
idat[z])
165 | (
static_cast<unsigned char>(
idat[z + 1]) << 8));
166 const std::uint16_t
nlen =
static_cast<std::uint16_t
>(
167 static_cast<unsigned char>(
idat[z + 2])
168 | (
static_cast<unsigned char>(
idat[z + 3]) << 8));
171 if (z + len >
idat.size())
173 ADD_FAILURE() <<
"stored block length exceeds IDAT";
177 idat.begin() +
static_cast<std::ptrdiff_t
>(z + len));
187 std::size_t
count = 0;
189 while ((pos = s.find(
needle, pos)) != std::string::npos)
200 std::ostringstream
out;
203 const DecodedPNG
png = decode_native_png(
out.str());
222 hex.set_axial({1, 0}, 1);
228 tri.set_tri({1, 1}, 1);
236 std::ostringstream
out;
238 const std::string
npy =
out.str();
241 EXPECT_EQ(
npy.substr(0, 6), std::string(
"\x93NUMPY", 6));
243 const std::uint16_t
header_len =
static_cast<std::uint16_t
>(
244 static_cast<unsigned char>(
npy[8]) | (
static_cast<unsigned char>(
npy[9]) << 8));
247 EXPECT_NE(header.find(
"'shape': (2, 3)"), std::string::npos);
248 EXPECT_NE(header.find(
"'fortran_order': False"), std::string::npos);
254 Grid3 g({2, 2, 2}, 0);
256 std::ostringstream
out;
260 const std::string
vtk =
out.str();
261 EXPECT_NE(
vtk.find(
"DATASET STRUCTURED_POINTS"), std::string::npos);
262 EXPECT_NE(
vtk.find(
"DIMENSIONS 2 2 2"), std::string::npos);
264 EXPECT_NE(
vtk.find(
"SCALARS alive int 1"), std::string::npos);
284 EXPECT_NE(dot.find(
"graph CA"), std::string::npos);
285 EXPECT_NE(dot.find(
"n1 [fillcolor=\"black\""), std::string::npos);
286 EXPECT_NE(dot.find(
"n0 -- n1"), std::string::npos);
287 EXPECT_NE(dot.find(
"n1 -- n2"), std::string::npos);
294 std::filesystem::remove_all(dir);
308 npy.accept(4, frame);
309 vtk.accept(4, frame);
310 svg.accept(4, frame);
317 std::filesystem::remove_all(dir);
Terminal and golden-test renderers for CA frames.
size_t size_t int32_t * out
GraphViz DOT renderer for graph cellular automata.
NumPy .npy writer for CA frames.
Dependency-free PNG frame sink for cellular automata.
Native SVG renderer for rectangular, hexagonal and triangular CAs.
VTK legacy writer for scientific CA visualisation.
Graph lattice: one cell per node + precomputed adjacency.
void set_node(std::size_t n, const T &v)
Direct write at node id n.
Hexagonal lattice with axial accessors over a 2D storage.
Lattice that adds boundary-aware access on top of a storage.
Path-pattern sink that writes one .npy file per frame.
Path-pattern sink that writes one PNG file per accepted frame.
Path-pattern sink that writes one SVG file per accepted frame.
void accept(const std::size_t step, const Lattice &frame)
Write one SVG frame using the default dead state.
Triangular lattice with parity helpers over a 2D storage.
Path-pattern sink that writes VTK legacy 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().
Native_Png decode_native_png(std::istream &in)
Decode a PNG emitted by Aleph::CA::write_png.
void write_vtk_legacy(std::ostream &out, const Lattice &frame, const VTK_Write_Options &opts={})
Write a 2D or 3D lattice as VTK legacy STRUCTURED_POINTS.
std::string render_ascii_string(const Lattice &frame, Palette &&palette, const Ascii_Render_Options &opts={})
Return the text rendering of a rank-2 frame.
Array< Array< std::size_t > > make_path_graph_adjacency(std::size_t n, bool cycle=false)
Build the adjacency of a path graph with n nodes.
std::string render_graph_lattice_dot_string(const Graph &graph, Palette &&palette, const DOT_Render_Options &opts={})
Return a graph frame rendered as DOT.
void write_png(std::ostream &out, const Lattice &frame, Mapper &&mapper)
Write a rank-2 frame as an 8-bit RGB PNG image.
std::string render_lattice_svg_string(const Lattice &frame, Palette &&palette, const SVG_Render_Options &opts={}, const typename Lattice::state_type &dead_state=typename Lattice::state_type{})
Return a frame rendered as SVG.
void write_npy(std::ostream &out, const Lattice &frame)
Write a lattice frame as a NumPy .npy array.
Itor find(const Itor &beg, const Itor &end, const T &value)
Find the first element equal to a value.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Options for textual CA rendering.
bool include_border
draw a simple +---+ border
Default binary DOT fill-colour palette.
Default binary RGB mapper.
Out-of-range neighbours behave as if the lattice ended.
Options for VTK legacy output.
std::string scalar_name
scalar field name
CA whose underlying topology is an arbitrary undirected graph.
Hexagonal lattice with axial / offset / cube coordinate conversions and a TikZ-compatible pixel mappi...
Cellular automata lattice with pluggable boundary policies.
Dense, contiguous storage for cellular automata cells (1D/2D/3D).
Triangular lattice with up/down parity helpers and pixel mapping suitable for visualisation.