10
10
#define BOOST_GEOMETRY_NO_BOOST_TEST
11
11
12
12
#include < bitset>
13
+ #include < chrono>
13
14
#include < iostream>
14
15
#include < random>
15
16
#include < utility>
26
27
#include < boost/geometry/geometries/geometries.hpp>
27
28
28
29
#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE
30
+ #ifndef BOOST_GEOMETRY_DEFAULT_TEST_TYPE
29
31
#define BOOST_GEOMETRY_DEFAULT_TEST_TYPE int
32
+ #endif
30
33
#include < geometry_test_common.hpp>
31
34
32
35
constexpr int chunk_size = 64 ;
@@ -46,19 +49,23 @@ struct grid_settings
46
49
int height = 5 ;
47
50
int count = 1 ;
48
51
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{};
49
55
};
50
56
51
57
constexpr int cell_dimension = 2 ;
52
58
53
59
std::vector<box> grid_cells (grid_settings const & settings)
54
60
{
55
61
std::vector<box> out;
62
+ out.reserve (settings.height * settings.width );
56
63
for (int y = 0 ; y < settings.height ; ++y)
57
64
{
58
65
for (int x = 0 ; x < settings.width ; ++x)
59
66
{
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) });
62
69
}
63
70
}
64
71
return out;
@@ -67,28 +74,38 @@ std::vector<box> grid_cells(grid_settings const& settings)
67
74
std::vector<point> test_points (grid_settings const & settings)
68
75
{
69
76
std::vector<point> out;
77
+ out.reserve (settings.height * settings.width );
70
78
for (int y = 0 ; y < settings.height ; ++y)
71
79
{
72
80
for (int x = 0 ; x < settings.width ; ++x)
73
81
{
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 ) );
76
84
}
77
85
}
78
86
return out;
79
87
}
80
88
81
89
std::ostream& operator <<(std::ostream& os, std::pair<bits, grid_settings> const & b_gs)
82
90
{
83
- os << ' \n ' ;
84
- for (int y = b_gs.second .height - 1 ; y >= 0 ; --y)
91
+ if (b_gs.second .verbose )
85
92
{
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)
87
95
{
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 ' ;
90
102
}
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 << ' }' ;
92
109
}
93
110
return os;
94
111
}
@@ -104,7 +121,7 @@ bits geometry_to_bits(mp_t const& geometry, std::vector<point> const& test_point
104
121
}
105
122
106
123
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 )
108
125
{
109
126
mp_t out;
110
127
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
121
138
std::string reason{};
122
139
if (! bg::is_valid (out, reason))
123
140
{
124
- std::cout << bg::wkt (out) << " \n generated 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) << " \n generated 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" ];
127
148
}
128
149
if (geometry_to_bits (out, points) != b)
129
150
{
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" ];
133
158
}
134
159
return out;
135
160
}
@@ -148,6 +173,14 @@ bits gen_bits(generator_t& generator, int bits_size)
148
173
return b;
149
174
}
150
175
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
+
151
184
template <typename BitOp>
152
185
bits apply_for_each (bits a, bits const & b, BitOp const & bit_op)
153
186
{
@@ -159,64 +192,114 @@ template<typename BitOp, typename GeoOp>
159
192
void test_op (bits const & bits1, bits const & bits2, mp_t const & geo1, mp_t const & geo2,
160
193
std::string const & op_label, BitOp const & bit_op, GeoOp const & geo_op,
161
194
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 )
163
196
{
164
197
auto test_geo = geo_op (geo1, geo2);
165
198
// Convenience lambda to pair bits with settings to use width/height in operator<<(os, ...)
166
199
const auto b_gs = [&settings](bits const & b) { return std::make_pair (b, settings); };
167
200
std::string reason{};
168
201
if (! bg::is_valid (test_geo, reason))
169
202
{
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
+ << " \n generated 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" ];
174
215
}
175
216
const bits expected = apply_for_each (bits1, bits2, bit_op);
176
217
const bits obtained = geometry_to_bits (test_geo, test_points);
177
218
if (obtained != expected)
178
219
{
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.\n Expected: "
182
- << bg::wkt (bits_to_geometry (expected, grid, test_points, settings, success))
183
- << " \n corresponding to" << b_gs (expected) << " Obtained: "
184
- << bg::wkt (test_geo) << " \n corresponding 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
+ << " \n generated from" << b_gs (bits1) << " and" << b_gs (bits2)
224
+ << " is incorrect.\n Expected: "
225
+ << bg::wkt (bits_to_geometry (expected, grid, test_points, settings, failures))
226
+ << " \n corresponding to" << b_gs (expected) << " Obtained: "
227
+ << bg::wkt (test_geo) << " \n corresponding 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" ];
186
231
}
187
232
}
188
233
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
+
189
259
bool test_all (grid_settings const & settings)
190
260
{
191
261
generator_t genenerator (settings.seed );
192
262
const auto grid = grid_cells (settings);
193
263
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 ();
195
266
for (int i = 0 ; i < settings.count || settings.count == -1 ; i++)
196
267
{
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 << " \n iterations: " << 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 ;
218
301
}
219
- return all_success ;
302
+ return true ;
220
303
}
221
304
222
305
int main (int argc, char ** argv)
@@ -243,12 +326,36 @@ int main(int argc, char** argv)
243
326
(" height" ,
244
327
po::value<decltype (settings.height )>(&settings.height )->default_value (settings.height ),
245
328
" 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." )
246
338
;
247
339
248
340
po::variables_map varmap;
249
341
po::store (po::parse_command_line (argc, argv, description), varmap);
250
342
po::notify (varmap);
251
343
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
+ }
252
359
if (settings.height < 1 || settings.width < 1 )
253
360
{
254
361
std::cout << " Invalid dimensions, height and width need to be positive.\n " ;
0 commit comments