Skip to content

Commit 27dfc3a

Browse files
committed
Add statistics, verbosity, fixed bit pattern options to random_integer_grids test.
1 parent d0e01be commit 27dfc3a

File tree

1 file changed

+159
-52
lines changed

1 file changed

+159
-52
lines changed

test/robustness/overlay/areal_areal/random_integer_grids.cpp

+159-52
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define BOOST_GEOMETRY_NO_BOOST_TEST
1111

1212
#include <bitset>
13+
#include <chrono>
1314
#include <iostream>
1415
#include <random>
1516
#include <utility>
@@ -26,7 +27,9 @@
2627
#include <boost/geometry/geometries/geometries.hpp>
2728

2829
#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
30+
#ifndef BOOST_GEOMETRY_DEFAULT_TEST_TYPE
2931
#define BOOST_GEOMETRY_DEFAULT_TEST_TYPE int
32+
#endif
3033
#include <geometry_test_common.hpp>
3134

3235
constexpr int chunk_size = 64;
@@ -46,19 +49,23 @@ struct grid_settings
4649
int height = 5;
4750
int count = 1;
4851
generator_t::result_type seed = generator_t::default_seed;
52+
bool verbose = false;
53+
std::vector<std::uint64_t> bits1{};
54+
std::vector<std::uint64_t> bits2{};
4955
};
5056

5157
constexpr int cell_dimension = 2;
5258

5359
std::vector<box> grid_cells(grid_settings const& settings)
5460
{
5561
std::vector<box> out;
62+
out.reserve(settings.height * settings.width);
5663
for (int y = 0; y < settings.height; ++y)
5764
{
5865
for (int x = 0; x < settings.width; ++x)
5966
{
60-
out.push_back(box{point{x * cell_dimension, y * cell_dimension},
61-
point{(x + 1) * cell_dimension, (y + 1) * cell_dimension}});
67+
out.push_back(box{point(x * cell_dimension, y * cell_dimension),
68+
point((x + 1) * cell_dimension, (y + 1) * cell_dimension)});
6269
}
6370
}
6471
return out;
@@ -67,28 +74,38 @@ std::vector<box> grid_cells(grid_settings const& settings)
6774
std::vector<point> test_points(grid_settings const& settings)
6875
{
6976
std::vector<point> out;
77+
out.reserve(settings.height * settings.width);
7078
for (int y = 0; y < settings.height; ++y)
7179
{
7280
for (int x = 0; x < settings.width; ++x)
7381
{
74-
out.push_back(point{x * cell_dimension + cell_dimension / 2,
75-
y * cell_dimension + cell_dimension / 2});
82+
out.push_back(point(x * cell_dimension + cell_dimension / 2,
83+
y * cell_dimension + cell_dimension / 2));
7684
}
7785
}
7886
return out;
7987
}
8088

8189
std::ostream& operator<<(std::ostream& os, std::pair<bits, grid_settings> const& b_gs)
8290
{
83-
os << '\n';
84-
for (int y = b_gs.second.height - 1; y >= 0; --y)
91+
if(b_gs.second.verbose)
8592
{
86-
for (int x = 0; x < b_gs.second.width; ++x)
93+
os << '\n';
94+
for (int y = b_gs.second.height - 1; y >= 0; --y)
8795
{
88-
int index = y * b_gs.second.width + x;
89-
os << b_gs.first[index / chunk_size][index % chunk_size];
96+
for (int x = 0; x < b_gs.second.width; ++x)
97+
{
98+
int index = y * b_gs.second.width + x;
99+
os << b_gs.first[index / chunk_size][index % chunk_size];
100+
}
101+
os << '\n';
90102
}
91-
os << '\n';
103+
}
104+
else
105+
{
106+
os << '{' << b_gs.first[0].to_ullong();
107+
for(size_t i = 1; i < b_gs.first.size(); ++i) os << ' ' << b_gs.first[i].to_ullong();
108+
os << '}';
92109
}
93110
return os;
94111
}
@@ -104,7 +121,7 @@ bits geometry_to_bits(mp_t const& geometry, std::vector<point> const& test_point
104121
}
105122

106123
mp_t bits_to_geometry(bits const& b, std::vector<box> const& grid, std::vector<point> const& points,
107-
grid_settings const& settings, bool& all_success)
124+
grid_settings const& settings, std::map<std::string, int>& failures)
108125
{
109126
mp_t out;
110127
for (size_t i = 0; i < grid.size(); ++i)
@@ -121,15 +138,23 @@ mp_t bits_to_geometry(bits const& b, std::vector<box> const& grid, std::vector<p
121138
std::string reason{};
122139
if (! bg::is_valid(out, reason))
123140
{
124-
std::cout << bg::wkt(out) << "\ngenerated from" << b_gs(b)
125-
<< "is invalid: " << reason << ".\n\n";
126-
all_success = false;
141+
if(settings.verbose)
142+
{
143+
std::cout << bg::wkt(out) << "\ngenerated from" << b_gs(b)
144+
<< "is invalid: " << reason << ".\n\n";
145+
}
146+
else std::cout << b_gs(b) << " invalid (" << reason << ")\n";
147+
++failures["bits_to_geometry validity"];
127148
}
128149
if (geometry_to_bits(out, points) != b)
129150
{
130-
std::cout << "Generating grid from pattern" << b_gs(b)
131-
<< "results in mismatching geometry: " << bg::wkt(out) << ".\n\n";
132-
all_success = false;
151+
if(settings.verbose)
152+
{
153+
std::cout << "Generating grid from pattern" << b_gs(b)
154+
<< "results in mismatching geometry: " << bg::wkt(out) << ".\n\n";
155+
}
156+
else std::cout << b_gs(b) << " mismatch.\n";
157+
++failures["bits_to_geometry mismatch"];
133158
}
134159
return out;
135160
}
@@ -148,6 +173,14 @@ bits gen_bits(generator_t& generator, int bits_size)
148173
return b;
149174
}
150175

176+
bits to_bits(std::vector<std::uint64_t> const& in)
177+
{
178+
bits out;
179+
out.reserve(in.size());
180+
for(auto const& ullong : in) out.push_back(std::bitset<chunk_size>(ullong));
181+
return out;
182+
}
183+
151184
template <typename BitOp>
152185
bits apply_for_each(bits a, bits const& b, BitOp const& bit_op)
153186
{
@@ -159,64 +192,114 @@ template<typename BitOp, typename GeoOp>
159192
void test_op(bits const& bits1, bits const& bits2, mp_t const& geo1, mp_t const& geo2,
160193
std::string const& op_label, BitOp const& bit_op, GeoOp const& geo_op,
161194
std::vector<point> const& test_points, std::vector<box> const& grid,
162-
grid_settings const& settings, bool& success)
195+
grid_settings const& settings, std::map<std::string, int>& failures)
163196
{
164197
auto test_geo = geo_op(geo1, geo2);
165198
// Convenience lambda to pair bits with settings to use width/height in operator<<(os, ...)
166199
const auto b_gs = [&settings](bits const& b) { return std::make_pair(b, settings); };
167200
std::string reason{};
168201
if (! bg::is_valid(test_geo, reason))
169202
{
170-
std::cout << op_label << "(\n\t " << bg::wkt(geo1) << ",\n\t " << bg::wkt(geo2) << "\n),\n"
171-
<< "generated from" << b_gs(bits1) << "and" << b_gs(bits2) << "is invalid: "
172-
<< reason << ".\n\n";
173-
success = false;
203+
if(settings.verbose)
204+
{
205+
std::cout << op_label << "(\n\t" << bg::wkt(geo1) << ",\n\t " << bg::wkt(geo2) << "\n),"
206+
<< "\ngenerated from" << b_gs(bits1) << "and" << b_gs(bits2) << "is invalid: "
207+
<< reason << ".\n\n";
208+
}
209+
else
210+
{
211+
std::cout << op_label << '(' << b_gs(bits1) << ", " << b_gs(bits2) << " invalid ("
212+
<< reason << ").\n";
213+
}
214+
++failures[op_label + " validity"];
174215
}
175216
const bits expected = apply_for_each(bits1, bits2, bit_op);
176217
const bits obtained = geometry_to_bits(test_geo, test_points);
177218
if (obtained != expected)
178219
{
179-
std::cout << op_label << "(\n\t" << bg::wkt(geo1) << ",\n\t" << bg::wkt(geo2) << "\n),\n"
180-
<< "generated from" << b_gs(bits1) << "and" << b_gs(bits2)
181-
<< "is incorrect.\nExpected: "
182-
<< bg::wkt(bits_to_geometry(expected, grid, test_points, settings, success))
183-
<< "\ncorresponding to" << b_gs(expected) << "Obtained: "
184-
<< bg::wkt(test_geo) << "\ncorresponding to" << b_gs(obtained) << "\n";
185-
success = false;
220+
if(settings.verbose)
221+
{
222+
std::cout << op_label << "(\n\t" << bg::wkt(geo1) << ",\n\t" << bg::wkt(geo2) << "\n),"
223+
<< "\ngenerated from" << b_gs(bits1) << "and" << b_gs(bits2)
224+
<< "is incorrect.\nExpected: "
225+
<< bg::wkt(bits_to_geometry(expected, grid, test_points, settings, failures))
226+
<< "\ncorresponding to" << b_gs(expected) << "Obtained: "
227+
<< bg::wkt(test_geo) << "\ncorresponding to" << b_gs(obtained) << "\n";
228+
}
229+
else std::cout << op_label << '(' << b_gs(bits1) << ", " << b_gs(bits2) << ") mismatch.\n";
230+
++failures[op_label + " mismatch"];
186231
}
187232
}
188233

234+
void test_bits(bits const& bits1, bits const& bits2,
235+
std::vector<box> const& grid, std::vector<point> const& test_points,
236+
grid_settings const& settings, std::map<std::string, int>& failures)
237+
{
238+
const auto geo1 = bits_to_geometry(bits1, grid, test_points, settings, failures);
239+
const auto geo2 = bits_to_geometry(bits2, grid, test_points, settings, failures);
240+
test_op(bits1, bits2, geo1, geo2, "union", std::bit_or<>{},
241+
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::union_(g1, g2, g); return g; },
242+
test_points, grid, settings, failures);
243+
test_op(bits1, bits2, geo1, geo2, "intersection", std::bit_and<>{},
244+
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::intersection(g1, g2, g); return g; },
245+
test_points, grid, settings, failures);
246+
test_op(bits1, bits2, geo1, geo2, "sym_difference", std::bit_xor<>{},
247+
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::sym_difference(g1, g2, g); return g; },
248+
test_points, grid, settings, failures);
249+
test_op(bits1, bits2, geo1, geo2, "difference g1 \\ g2",
250+
[](std::bitset<chunk_size> b1, std::bitset<chunk_size> b2) { return b1 & (~b2); },
251+
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::difference(g1, g2, g); return g; },
252+
test_points, grid, settings, failures);
253+
test_op(bits1, bits2, geo1, geo2, "difference g2 \\ g1",
254+
[](std::bitset<chunk_size> b1, std::bitset<chunk_size> b2) { return b2 & (~b1); },
255+
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::difference(g2, g1, g); return g; },
256+
test_points, grid, settings, failures);
257+
}
258+
189259
bool test_all(grid_settings const& settings)
190260
{
191261
generator_t genenerator(settings.seed);
192262
const auto grid = grid_cells(settings);
193263
const auto points = test_points(settings);
194-
bool all_success = true;
264+
std::map<std::string, int> failures;
265+
auto const t0 = std::chrono::high_resolution_clock::now();
195266
for (int i = 0; i < settings.count || settings.count == -1; i++)
196267
{
197-
const bits bits1 = gen_bits(genenerator, settings.width * settings.height);
198-
const bits bits2 = gen_bits(genenerator, settings.width * settings.height);
199-
const auto geo1 = bits_to_geometry(bits1, grid, points, settings, all_success);
200-
const auto geo2 = bits_to_geometry(bits2, grid, points, settings, all_success);
201-
test_op(bits1, bits2, geo1, geo2, "union", std::bit_or<>{},
202-
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::union_(g1, g2, g); return g; },
203-
points, grid, settings, all_success);
204-
test_op(bits1, bits2, geo1, geo2, "intersection", std::bit_and<>{},
205-
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::intersection(g1, g2, g); return g; },
206-
points, grid, settings, all_success);
207-
test_op(bits1, bits2, geo1, geo2, "sym_difference", std::bit_xor<>{},
208-
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::sym_difference(g1, g2, g); return g; },
209-
points, grid, settings, all_success);
210-
test_op(bits1, bits2, geo1, geo2, "difference g1 \\ g2",
211-
[](std::bitset<chunk_size> b1, std::bitset<chunk_size> b2) { return b1 & (~b2); },
212-
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::difference(g1, g2, g); return g; },
213-
points, grid, settings, all_success);
214-
test_op(bits1, bits2, geo1, geo2, "difference g2 \\ g1",
215-
[](std::bitset<chunk_size> b1, std::bitset<chunk_size> b2) { return b2 & (~b1); },
216-
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::difference(g2, g1, g); return g; },
217-
points, grid, settings, all_success);
268+
const bits bits1 = settings.bits1.size() == 0 ?
269+
gen_bits(genenerator, settings.width * settings.height)
270+
: to_bits(settings.bits1);
271+
const bits bits2 = settings.bits2.size() == 0 ?
272+
gen_bits(genenerator, settings.width * settings.height)
273+
: to_bits(settings.bits2);
274+
test_bits(bits1, bits2, grid, points, settings, failures);
275+
}
276+
auto const t = std::chrono::high_resolution_clock::now();
277+
auto const elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t - t0).count();
278+
int failure_count = std::accumulate(failures.begin(), failures.end(), 0,
279+
[](int acc, auto const& kv) { return acc + kv.second; });
280+
std::cout << "\niterations: " << settings.count
281+
<< " errors: " << failure_count
282+
<< " time: " << elapsed_ms/1000 << '\n';
283+
if (failure_count != 0)
284+
{
285+
std::cout << "Failure counts by failure mode:\n";
286+
for(auto const& fm : failures) std::cout << '\t' << fm.first << ": " << fm.second << '\n';
287+
}
288+
return failure_count != 0;
289+
}
290+
291+
bool validate_bits_input(std::vector<std::uint64_t> const& bits_in, size_t bits_size)
292+
{
293+
if(bits_in.size() == 0) return true;
294+
if(bits_in.size() != (bits_size + chunk_size - 1) / chunk_size) return false;
295+
if (bits_size % chunk_size != 0)
296+
{
297+
std::bitset<chunk_size> bm;
298+
bm.set();
299+
bm >>= chunk_size - bits_size % chunk_size;
300+
if(bits_in.back() & ~bm.to_ullong()) return false;
218301
}
219-
return all_success;
302+
return true;
220303
}
221304

222305
int main(int argc, char** argv)
@@ -243,12 +326,36 @@ int main(int argc, char** argv)
243326
("height",
244327
po::value<decltype(settings.height)>(&settings.height)->default_value(settings.height),
245328
"Height of grid (>= 1)")
329+
("verbose",
330+
po::bool_switch(&settings.verbose),
331+
"Print WKT and bit patterns for each failure.")
332+
("bits1",
333+
po::value<decltype(settings.bits1)>(&settings.bits1)->multitoken(),
334+
"Fixed bit pattern for first operand as list of ullong.")
335+
("bits2",
336+
po::value<decltype(settings.bits2)>(&settings.bits2)->multitoken(),
337+
"Fixed bit pattern for second operand as list of ullong.")
246338
;
247339

248340
po::variables_map varmap;
249341
po::store(po::parse_command_line(argc, argv, description), varmap);
250342
po::notify(varmap);
251343

344+
if (! validate_bits_input(settings.bits1, settings.height * settings.width))
345+
{
346+
std::cout << "bits1 was provided but does not match dimensions.\n";
347+
return 1;
348+
}
349+
if (! validate_bits_input(settings.bits2, settings.height * settings.width))
350+
{
351+
std::cout << "bits2 was provided but does not match dimensions.\n";
352+
return 1;
353+
}
354+
if ( settings.bits1.size() != 0 && settings.bits2.size() != 0 && settings.count != 1 )
355+
{
356+
std::cout << "Both bit patterns fixed, count is changed to 1.\n";
357+
settings.count = 1;
358+
}
252359
if(settings.height < 1 || settings.width < 1)
253360
{
254361
std::cout << "Invalid dimensions, height and width need to be positive.\n";

0 commit comments

Comments
 (0)