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