Skip to content

Commit 4131e98

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

File tree

1 file changed

+160
-52
lines changed

1 file changed

+160
-52
lines changed

test/robustness/overlay/areal_areal/random_integer_grids.cpp

+160-52
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
88
// http://www.boost.org/LICENSE_1_0.txt)
99

10+
#include <boost/program_options/value_semantic.hpp>
1011
#define BOOST_GEOMETRY_NO_BOOST_TEST
1112

1213
#include <bitset>
14+
#include <chrono>
1315
#include <iostream>
1416
#include <random>
1517
#include <utility>
@@ -26,7 +28,9 @@
2628
#include <boost/geometry/geometries/geometries.hpp>
2729

2830
#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
31+
#ifndef BOOST_GEOMETRY_DEFAULT_TEST_TYPE
2932
#define BOOST_GEOMETRY_DEFAULT_TEST_TYPE int
33+
#endif
3034
#include <geometry_test_common.hpp>
3135

3236
constexpr int chunk_size = 64;
@@ -46,19 +50,23 @@ struct grid_settings
4650
int height = 5;
4751
int count = 1;
4852
generator_t::result_type seed = generator_t::default_seed;
53+
bool verbose = false;
54+
std::vector<std::uint64_t> bits1{};
55+
std::vector<std::uint64_t> bits2{};
4956
};
5057

5158
constexpr int cell_dimension = 2;
5259

5360
std::vector<box> grid_cells(grid_settings const& settings)
5461
{
5562
std::vector<box> out;
63+
out.reserve(settings.height * settings.width);
5664
for (int y = 0; y < settings.height; ++y)
5765
{
5866
for (int x = 0; x < settings.width; ++x)
5967
{
60-
out.push_back(box{point{x * cell_dimension, y * cell_dimension},
61-
point{(x + 1) * cell_dimension, (y + 1) * cell_dimension}});
68+
out.push_back(box{point(x * cell_dimension, y * cell_dimension),
69+
point((x + 1) * cell_dimension, (y + 1) * cell_dimension)});
6270
}
6371
}
6472
return out;
@@ -67,28 +75,38 @@ std::vector<box> grid_cells(grid_settings const& settings)
6775
std::vector<point> test_points(grid_settings const& settings)
6876
{
6977
std::vector<point> out;
78+
out.reserve(settings.height * settings.width);
7079
for (int y = 0; y < settings.height; ++y)
7180
{
7281
for (int x = 0; x < settings.width; ++x)
7382
{
74-
out.push_back(point{x * cell_dimension + cell_dimension / 2,
75-
y * cell_dimension + cell_dimension / 2});
83+
out.push_back(point(x * cell_dimension + cell_dimension / 2,
84+
y * cell_dimension + cell_dimension / 2));
7685
}
7786
}
7887
return out;
7988
}
8089

8190
std::ostream& operator<<(std::ostream& os, std::pair<bits, grid_settings> const& b_gs)
8291
{
83-
os << '\n';
84-
for (int y = b_gs.second.height - 1; y >= 0; --y)
92+
if(b_gs.second.verbose)
8593
{
86-
for (int x = 0; x < b_gs.second.width; ++x)
94+
os << '\n';
95+
for (int y = b_gs.second.height - 1; y >= 0; --y)
8796
{
88-
int index = y * b_gs.second.width + x;
89-
os << b_gs.first[index / chunk_size][index % chunk_size];
97+
for (int x = 0; x < b_gs.second.width; ++x)
98+
{
99+
int index = y * b_gs.second.width + x;
100+
os << b_gs.first[index / chunk_size][index % chunk_size];
101+
}
102+
os << '\n';
90103
}
91-
os << '\n';
104+
}
105+
else
106+
{
107+
os << '{' << b_gs.first[0].to_ullong();
108+
for(size_t i = 1; i < b_gs.first.size(); ++i) os << ' ' << b_gs.first[i].to_ullong();
109+
os << '}';
92110
}
93111
return os;
94112
}
@@ -104,7 +122,7 @@ bits geometry_to_bits(mp_t const& geometry, std::vector<point> const& test_point
104122
}
105123

106124
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)
125+
grid_settings const& settings, std::map<std::string, int>& failures)
108126
{
109127
mp_t out;
110128
for (size_t i = 0; i < grid.size(); ++i)
@@ -121,15 +139,23 @@ mp_t bits_to_geometry(bits const& b, std::vector<box> const& grid, std::vector<p
121139
std::string reason{};
122140
if (! bg::is_valid(out, reason))
123141
{
124-
std::cout << bg::wkt(out) << "\ngenerated from" << b_gs(b)
125-
<< "is invalid: " << reason << ".\n\n";
126-
all_success = false;
142+
if(settings.verbose)
143+
{
144+
std::cout << bg::wkt(out) << "\ngenerated from" << b_gs(b)
145+
<< "is invalid: " << reason << ".\n\n";
146+
}
147+
else std::cout << b_gs(b) << " invalid (" << reason << ")\n";
148+
++failures["bits_to_geometry validity"];
127149
}
128150
if (geometry_to_bits(out, points) != b)
129151
{
130-
std::cout << "Generating grid from pattern" << b_gs(b)
131-
<< "results in mismatching geometry: " << bg::wkt(out) << ".\n\n";
132-
all_success = false;
152+
if(settings.verbose)
153+
{
154+
std::cout << "Generating grid from pattern" << b_gs(b)
155+
<< "results in mismatching geometry: " << bg::wkt(out) << ".\n\n";
156+
}
157+
else std::cout << b_gs(b) << " mismatch.\n";
158+
++failures["bits_to_geometry mismatch"];
133159
}
134160
return out;
135161
}
@@ -148,6 +174,14 @@ bits gen_bits(generator_t& generator, int bits_size)
148174
return b;
149175
}
150176

177+
bits to_bits(std::vector<std::uint64_t> const& in)
178+
{
179+
bits out;
180+
out.reserve(in.size());
181+
for(auto const& ullong : in) out.push_back(std::bitset<chunk_size>(ullong));
182+
return out;
183+
}
184+
151185
template <typename BitOp>
152186
bits apply_for_each(bits a, bits const& b, BitOp const& bit_op)
153187
{
@@ -159,64 +193,114 @@ template<typename BitOp, typename GeoOp>
159193
void test_op(bits const& bits1, bits const& bits2, mp_t const& geo1, mp_t const& geo2,
160194
std::string const& op_label, BitOp const& bit_op, GeoOp const& geo_op,
161195
std::vector<point> const& test_points, std::vector<box> const& grid,
162-
grid_settings const& settings, bool& success)
196+
grid_settings const& settings, std::map<std::string, int>& failures)
163197
{
164198
auto test_geo = geo_op(geo1, geo2);
165199
// Convenience lambda to pair bits with settings to use width/height in operator<<(os, ...)
166200
const auto b_gs = [&settings](bits const& b) { return std::make_pair(b, settings); };
167201
std::string reason{};
168202
if (! bg::is_valid(test_geo, reason))
169203
{
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;
204+
if(settings.verbose)
205+
{
206+
std::cout << op_label << "(\n\t" << bg::wkt(geo1) << ",\n\t " << bg::wkt(geo2) << "\n),"
207+
<< "\ngenerated from" << b_gs(bits1) << "and" << b_gs(bits2) << "is invalid: "
208+
<< reason << ".\n\n";
209+
}
210+
else
211+
{
212+
std::cout << op_label << '(' << b_gs(bits1) << ", " << b_gs(bits2) << " invalid ("
213+
<< reason << ").\n";
214+
}
215+
++failures[op_label + " validity"];
174216
}
175217
const bits expected = apply_for_each(bits1, bits2, bit_op);
176218
const bits obtained = geometry_to_bits(test_geo, test_points);
177219
if (obtained != expected)
178220
{
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;
221+
if(settings.verbose)
222+
{
223+
std::cout << op_label << "(\n\t" << bg::wkt(geo1) << ",\n\t" << bg::wkt(geo2) << "\n),"
224+
<< "\ngenerated from" << b_gs(bits1) << "and" << b_gs(bits2)
225+
<< "is incorrect.\nExpected: "
226+
<< bg::wkt(bits_to_geometry(expected, grid, test_points, settings, failures))
227+
<< "\ncorresponding to" << b_gs(expected) << "Obtained: "
228+
<< bg::wkt(test_geo) << "\ncorresponding to" << b_gs(obtained) << "\n";
229+
}
230+
else std::cout << op_label << '(' << b_gs(bits1) << ", " << b_gs(bits2) << ") mismatch.\n";
231+
++failures[op_label + " mismatch"];
186232
}
187233
}
188234

235+
void test_bits(bits const& bits1, bits const& bits2,
236+
std::vector<box> const& grid, std::vector<point> const& test_points,
237+
grid_settings const& settings, std::map<std::string, int>& failures)
238+
{
239+
const auto geo1 = bits_to_geometry(bits1, grid, test_points, settings, failures);
240+
const auto geo2 = bits_to_geometry(bits2, grid, test_points, settings, failures);
241+
test_op(bits1, bits2, geo1, geo2, "union", std::bit_or<>{},
242+
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::union_(g1, g2, g); return g; },
243+
test_points, grid, settings, failures);
244+
test_op(bits1, bits2, geo1, geo2, "intersection", std::bit_and<>{},
245+
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::intersection(g1, g2, g); return g; },
246+
test_points, grid, settings, failures);
247+
test_op(bits1, bits2, geo1, geo2, "sym_difference", std::bit_xor<>{},
248+
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::sym_difference(g1, g2, g); return g; },
249+
test_points, grid, settings, failures);
250+
test_op(bits1, bits2, geo1, geo2, "difference g1 \\ g2",
251+
[](std::bitset<chunk_size> b1, std::bitset<chunk_size> b2) { return b1 & (~b2); },
252+
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::difference(g1, g2, g); return g; },
253+
test_points, grid, settings, failures);
254+
test_op(bits1, bits2, geo1, geo2, "difference g2 \\ g1",
255+
[](std::bitset<chunk_size> b1, std::bitset<chunk_size> b2) { return b2 & (~b1); },
256+
[](mp_t const& g1, mp_t const& g2) { mp_t g; bg::difference(g2, g1, g); return g; },
257+
test_points, grid, settings, failures);
258+
}
259+
189260
bool test_all(grid_settings const& settings)
190261
{
191262
generator_t genenerator(settings.seed);
192263
const auto grid = grid_cells(settings);
193264
const auto points = test_points(settings);
194-
bool all_success = true;
265+
std::map<std::string, int> failures;
266+
auto const t0 = std::chrono::high_resolution_clock::now();
195267
for (int i = 0; i < settings.count || settings.count == -1; i++)
196268
{
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);
269+
const bits bits1 = settings.bits1.size() == 0 ?
270+
gen_bits(genenerator, settings.width * settings.height)
271+
: to_bits(settings.bits1);
272+
const bits bits2 = settings.bits2.size() == 0 ?
273+
gen_bits(genenerator, settings.width * settings.height)
274+
: to_bits(settings.bits2);
275+
test_bits(bits1, bits2, grid, points, settings, failures);
276+
}
277+
auto const t = std::chrono::high_resolution_clock::now();
278+
auto const elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t - t0).count();
279+
int failure_count = std::accumulate(failures.begin(), failures.end(), 0,
280+
[](int acc, auto const& kv) { return acc + kv.second; });
281+
std::cout << "\niterations: " << settings.count
282+
<< " errors: " << failure_count
283+
<< " time: " << elapsed_ms/1000 << '\n';
284+
if (failure_count != 0)
285+
{
286+
std::cout << "Failure counts by failure mode:\n";
287+
for(auto const& fm : failures) std::cout << '\t' << fm.first << ": " << fm.second << '\n';
288+
}
289+
return failure_count != 0;
290+
}
291+
292+
bool validate_bits_input(std::vector<std::uint64_t> const& bits_in, size_t bits_size)
293+
{
294+
if(bits_in.size() == 0) return true;
295+
if(bits_in.size() != (bits_size + chunk_size - 1) / chunk_size) return false;
296+
if (bits_size % chunk_size != 0)
297+
{
298+
std::bitset<chunk_size> bm;
299+
bm.set();
300+
bm >>= chunk_size - bits_size % chunk_size;
301+
if(bits_in.back() & ~bm.to_ullong()) return false;
218302
}
219-
return all_success;
303+
return true;
220304
}
221305

222306
int main(int argc, char** argv)
@@ -243,12 +327,36 @@ int main(int argc, char** argv)
243327
("height",
244328
po::value<decltype(settings.height)>(&settings.height)->default_value(settings.height),
245329
"Height of grid (>= 1)")
330+
("verbose",
331+
po::bool_switch(&settings.verbose),
332+
"Print WKT and bit patterns for each failure.")
333+
("bits1",
334+
po::value<decltype(settings.bits1)>(&settings.bits1)->multitoken(),
335+
"Fixed bit pattern for first operand as list of ullong.")
336+
("bits2",
337+
po::value<decltype(settings.bits2)>(&settings.bits2)->multitoken(),
338+
"Fixed bit pattern for second operand as list of ullong.")
246339
;
247340

248341
po::variables_map varmap;
249342
po::store(po::parse_command_line(argc, argv, description), varmap);
250343
po::notify(varmap);
251344

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

0 commit comments

Comments
 (0)