datasketches 0.2.7 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/ext/datasketches/kll_wrapper.cpp +20 -20
  4. data/ext/datasketches/theta_wrapper.cpp +2 -2
  5. data/lib/datasketches/version.rb +1 -1
  6. data/vendor/datasketches-cpp/CMakeLists.txt +9 -1
  7. data/vendor/datasketches-cpp/MANIFEST.in +21 -2
  8. data/vendor/datasketches-cpp/common/CMakeLists.txt +5 -2
  9. data/vendor/datasketches-cpp/common/include/common_defs.hpp +10 -0
  10. data/vendor/datasketches-cpp/common/include/kolmogorov_smirnov_impl.hpp +6 -6
  11. data/vendor/datasketches-cpp/common/include/memory_operations.hpp +1 -0
  12. data/vendor/datasketches-cpp/common/include/{quantile_sketch_sorted_view.hpp → quantiles_sorted_view.hpp} +60 -25
  13. data/vendor/datasketches-cpp/common/include/quantiles_sorted_view_impl.hpp +125 -0
  14. data/vendor/datasketches-cpp/common/include/version.hpp.in +36 -0
  15. data/vendor/datasketches-cpp/common/test/CMakeLists.txt +25 -6
  16. data/vendor/datasketches-cpp/common/test/quantiles_sorted_view_test.cpp +459 -0
  17. data/vendor/datasketches-cpp/cpc/test/CMakeLists.txt +1 -1
  18. data/vendor/datasketches-cpp/fi/include/frequent_items_sketch.hpp +28 -44
  19. data/vendor/datasketches-cpp/fi/include/frequent_items_sketch_impl.hpp +70 -78
  20. data/vendor/datasketches-cpp/fi/include/reverse_purge_hash_map.hpp +11 -4
  21. data/vendor/datasketches-cpp/fi/include/reverse_purge_hash_map_impl.hpp +16 -9
  22. data/vendor/datasketches-cpp/fi/test/CMakeLists.txt +1 -1
  23. data/vendor/datasketches-cpp/fi/test/frequent_items_sketch_custom_type_test.cpp +54 -41
  24. data/vendor/datasketches-cpp/fi/test/reverse_purge_hash_map_test.cpp +3 -3
  25. data/vendor/datasketches-cpp/hll/include/Hll4Array-internal.hpp +2 -2
  26. data/vendor/datasketches-cpp/hll/test/CMakeLists.txt +1 -1
  27. data/vendor/datasketches-cpp/kll/include/kll_helper.hpp +0 -32
  28. data/vendor/datasketches-cpp/kll/include/kll_sketch.hpp +176 -233
  29. data/vendor/datasketches-cpp/kll/include/kll_sketch_impl.hpp +337 -395
  30. data/vendor/datasketches-cpp/kll/test/CMakeLists.txt +1 -1
  31. data/vendor/datasketches-cpp/kll/test/kll_sketch_custom_type_test.cpp +26 -26
  32. data/vendor/datasketches-cpp/kll/test/kll_sketch_test.cpp +196 -232
  33. data/vendor/datasketches-cpp/kll/test/kll_sketch_validation.cpp +41 -31
  34. data/vendor/datasketches-cpp/pyproject.toml +17 -12
  35. data/vendor/datasketches-cpp/python/CMakeLists.txt +8 -1
  36. data/vendor/datasketches-cpp/python/datasketches/PySerDe.py +104 -0
  37. data/vendor/datasketches-cpp/python/datasketches/__init__.py +22 -0
  38. data/vendor/datasketches-cpp/python/include/py_serde.hpp +113 -0
  39. data/vendor/datasketches-cpp/python/jupyter/ThetaSketchNotebook.ipynb +31 -24
  40. data/vendor/datasketches-cpp/python/pybind11Path.cmd +18 -0
  41. data/vendor/datasketches-cpp/python/src/__init__.py +17 -1
  42. data/vendor/datasketches-cpp/python/src/datasketches.cpp +9 -3
  43. data/vendor/datasketches-cpp/python/src/kll_wrapper.cpp +18 -54
  44. data/vendor/datasketches-cpp/python/src/py_serde.cpp +111 -0
  45. data/vendor/datasketches-cpp/python/src/quantiles_wrapper.cpp +17 -53
  46. data/vendor/datasketches-cpp/python/src/req_wrapper.cpp +17 -55
  47. data/vendor/datasketches-cpp/python/src/vector_of_kll.cpp +62 -67
  48. data/vendor/datasketches-cpp/python/src/vo_wrapper.cpp +47 -14
  49. data/vendor/datasketches-cpp/python/tests/__init__.py +16 -0
  50. data/vendor/datasketches-cpp/python/tests/req_test.py +1 -1
  51. data/vendor/datasketches-cpp/python/tests/vo_test.py +25 -1
  52. data/vendor/datasketches-cpp/quantiles/include/quantiles_sketch.hpp +135 -180
  53. data/vendor/datasketches-cpp/quantiles/include/quantiles_sketch_impl.hpp +205 -210
  54. data/vendor/datasketches-cpp/quantiles/test/CMakeLists.txt +1 -1
  55. data/vendor/datasketches-cpp/quantiles/test/quantiles_compatibility_test.cpp +19 -18
  56. data/vendor/datasketches-cpp/quantiles/test/quantiles_sketch_test.cpp +240 -232
  57. data/vendor/datasketches-cpp/req/include/req_compactor.hpp +15 -9
  58. data/vendor/datasketches-cpp/req/include/req_compactor_impl.hpp +35 -19
  59. data/vendor/datasketches-cpp/req/include/req_sketch.hpp +126 -147
  60. data/vendor/datasketches-cpp/req/include/req_sketch_impl.hpp +265 -245
  61. data/vendor/datasketches-cpp/req/test/CMakeLists.txt +1 -1
  62. data/vendor/datasketches-cpp/req/test/req_sketch_custom_type_test.cpp +26 -26
  63. data/vendor/datasketches-cpp/req/test/req_sketch_test.cpp +116 -103
  64. data/vendor/datasketches-cpp/sampling/include/var_opt_sketch.hpp +22 -46
  65. data/vendor/datasketches-cpp/sampling/include/var_opt_sketch_impl.hpp +180 -207
  66. data/vendor/datasketches-cpp/sampling/include/var_opt_union.hpp +18 -39
  67. data/vendor/datasketches-cpp/sampling/include/var_opt_union_impl.hpp +75 -85
  68. data/vendor/datasketches-cpp/sampling/test/CMakeLists.txt +1 -1
  69. data/vendor/datasketches-cpp/sampling/test/var_opt_allocation_test.cpp +6 -6
  70. data/vendor/datasketches-cpp/sampling/test/var_opt_sketch_test.cpp +2 -2
  71. data/vendor/datasketches-cpp/sampling/test/var_opt_union_test.cpp +4 -4
  72. data/vendor/datasketches-cpp/setup.py +14 -2
  73. data/vendor/datasketches-cpp/theta/include/theta_sketch_impl.hpp +15 -25
  74. data/vendor/datasketches-cpp/theta/include/theta_update_sketch_base.hpp +0 -9
  75. data/vendor/datasketches-cpp/theta/include/theta_update_sketch_base_impl.hpp +5 -5
  76. data/vendor/datasketches-cpp/theta/test/CMakeLists.txt +1 -1
  77. data/vendor/datasketches-cpp/theta/test/theta_sketch_test.cpp +2 -1
  78. data/vendor/datasketches-cpp/tox.ini +26 -0
  79. data/vendor/datasketches-cpp/tuple/include/tuple_sketch.hpp +36 -12
  80. data/vendor/datasketches-cpp/tuple/include/tuple_sketch_impl.hpp +16 -4
  81. data/vendor/datasketches-cpp/tuple/test/CMakeLists.txt +2 -1
  82. data/vendor/datasketches-cpp/tuple/test/engagement_test.cpp +299 -0
  83. data/vendor/datasketches-cpp/tuple/test/tuple_sketch_test.cpp +26 -0
  84. data/vendor/datasketches-cpp/version.cfg.in +1 -0
  85. metadata +14 -5
  86. data/vendor/datasketches-cpp/common/include/quantile_sketch_sorted_view_impl.hpp +0 -91
@@ -47,53 +47,57 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
47
47
  test_allocator_total_bytes = 0;
48
48
 
49
49
  SECTION("k limits") {
50
- quantiles_float_sketch sketch1(quantiles_constants::MIN_K, 0); // this should work
51
- quantiles_float_sketch sketch2(quantiles_constants::MAX_K, 0); // this should work
52
- REQUIRE_THROWS_AS(new quantiles_float_sketch(quantiles_constants::MIN_K - 1, 0), std::invalid_argument);
53
- REQUIRE_THROWS_AS(new quantiles_float_sketch(40, 0), std::invalid_argument); // not power of 2
50
+ //std::cout << "sizeof(quantiles_sketch<float>)=" << sizeof(quantiles_sketch<float>) << '\n';
51
+ quantiles_float_sketch sketch1(quantiles_constants::MIN_K, std::less<float>(), 0); // this should work
52
+ quantiles_float_sketch sketch2(quantiles_constants::MAX_K, std::less<float>(), 0); // this should work
53
+ REQUIRE_THROWS_AS(new quantiles_float_sketch(quantiles_constants::MIN_K - 1, std::less<float>(), 0), std::invalid_argument);
54
+ REQUIRE_THROWS_AS(new quantiles_float_sketch(40, std::less<float>(), 0), std::invalid_argument); // not power of 2
54
55
  // MAX_K + 1 makes no sense because k is uint16_t
55
56
  }
56
57
 
57
58
  SECTION("empty") {
58
- quantiles_float_sketch sketch(128, 0);
59
+ quantiles_float_sketch sketch(128, std::less<float>(), 0);
59
60
  REQUIRE(sketch.is_empty());
60
61
  REQUIRE_FALSE(sketch.is_estimation_mode());
61
62
  REQUIRE(sketch.get_n() == 0);
62
63
  REQUIRE(sketch.get_num_retained() == 0);
63
- REQUIRE(std::isnan(sketch.get_rank(0)));
64
- REQUIRE(std::isnan(sketch.get_min_value()));
65
- REQUIRE(std::isnan(sketch.get_max_value()));
66
- REQUIRE(std::isnan(sketch.get_quantile(0.5)));
64
+ REQUIRE_THROWS_AS(sketch.get_min_item(), std::runtime_error);
65
+ REQUIRE_THROWS_AS(sketch.get_max_item(), std::runtime_error);
66
+ REQUIRE_THROWS_AS(sketch.get_rank(0), std::runtime_error);
67
+ REQUIRE_THROWS_AS(sketch.get_quantile(0.5), std::runtime_error);
67
68
  const double fractions[3] {0, 0.5, 1};
68
- REQUIRE(sketch.get_quantiles(fractions, 3).empty());
69
+ REQUIRE_THROWS_AS(sketch.get_quantiles(fractions, 3).empty(), std::runtime_error);
69
70
  const float split_points[1] {0};
70
- REQUIRE(sketch.get_PMF(split_points, 1).empty());
71
- REQUIRE(sketch.get_CDF(split_points, 1).empty());
71
+ REQUIRE_THROWS_AS(sketch.get_PMF(split_points, 1), std::runtime_error);
72
+ REQUIRE_THROWS_AS(sketch.get_CDF(split_points, 1), std::runtime_error);
72
73
 
73
- for (auto it: sketch) {
74
- unused(it);
74
+ for (auto pair: sketch) {
75
+ unused(pair);
75
76
  FAIL("should be no iterations over an empty sketch");
76
77
  }
77
- }
78
+ }
78
79
 
79
80
  SECTION("get bad quantile") {
80
- quantiles_float_sketch sketch(64, 0);
81
+ quantiles_float_sketch sketch(64, std::less<float>(), 0);
81
82
  sketch.update(0.0f); // has to be non-empty to reach the check
82
83
  REQUIRE_THROWS_AS(sketch.get_quantile(-1), std::invalid_argument);
83
84
  }
84
85
 
85
86
  SECTION("one item") {
86
- quantiles_float_sketch sketch(128, 0);
87
+ quantiles_float_sketch sketch(128, std::less<float>(), 0);
87
88
  sketch.update(1.0f);
88
89
  REQUIRE_FALSE(sketch.is_empty());
89
90
  REQUIRE_FALSE(sketch.is_estimation_mode());
90
91
  REQUIRE(sketch.get_n() == 1);
91
92
  REQUIRE(sketch.get_num_retained() == 1);
92
- REQUIRE(sketch.get_rank(1.0f) == 0.0);
93
- REQUIRE(sketch.get_rank(2.0f) == 1.0);
94
- REQUIRE(sketch.get_min_value() == 1.0);
95
- REQUIRE(sketch.get_max_value() == 1.0);
93
+ REQUIRE(sketch.get_rank(0) == 0);
94
+ REQUIRE(sketch.get_rank(1.0f) == 1);
95
+ REQUIRE(sketch.get_rank(1.0f, false) == 0);
96
+ REQUIRE(sketch.get_rank(2.0f, false) == 1);
97
+ REQUIRE(sketch.get_min_item() == 1.0);
98
+ REQUIRE(sketch.get_max_item() == 1.0);
96
99
  REQUIRE(sketch.get_quantile(0.5) == 1.0);
100
+
97
101
  const double fractions[3] {0, 0.5, 1};
98
102
  auto quantiles = sketch.get_quantiles(fractions, 3);
99
103
  REQUIRE(quantiles.size() == 3);
@@ -102,15 +106,20 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
102
106
  REQUIRE(quantiles[2] == 1.0);
103
107
 
104
108
  int count = 0;
105
- for (auto it: sketch) {
106
- REQUIRE(it.second == 1);
109
+ for (auto pair: sketch) {
110
+ REQUIRE(pair.second == 1);
107
111
  ++count;
108
112
  }
109
113
  REQUIRE(count == 1);
110
- }
114
+
115
+ // iterator dereferencing
116
+ auto it = sketch.begin();
117
+ REQUIRE(it->first == 1.0f);
118
+ REQUIRE((*it).first == 1.0f);
119
+ }
111
120
 
112
121
  SECTION("NaN") {
113
- quantiles_float_sketch sketch(256, 0);
122
+ quantiles_float_sketch sketch(256, std::less<float>(), 0);
114
123
  sketch.update(std::numeric_limits<float>::quiet_NaN());
115
124
  REQUIRE(sketch.is_empty());
116
125
 
@@ -123,45 +132,33 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
123
132
  SECTION("sampling mode") {
124
133
  const uint16_t k = 8;
125
134
  const uint32_t n = 16 * (2 * k) + 1;
126
- quantiles_float_sketch sk(k, 0);
135
+ quantiles_float_sketch sk(k, std::less<float>(), 0);
127
136
  for (uint32_t i = 0; i < n; ++i) {
128
137
  sk.update(static_cast<float>(i));
129
138
  }
130
139
  }
131
140
 
132
141
  SECTION("many items, exact mode") {
133
- const uint32_t n = 127;
134
- quantiles_float_sketch sketch(n + 1, 0);
135
- for (uint32_t i = 0; i < n; i++) {
142
+ const uint32_t n = 100;
143
+ quantiles_float_sketch sketch(128, std::less<float>(), 0);
144
+ for (uint32_t i = 1; i <= n; i++) {
136
145
  sketch.update(static_cast<float>(i));
137
- REQUIRE(sketch.get_n() == i + 1);
146
+ REQUIRE(sketch.get_n() == i);
138
147
  }
139
148
  REQUIRE_FALSE(sketch.is_empty());
140
149
  REQUIRE_FALSE(sketch.is_estimation_mode());
141
150
  REQUIRE(sketch.get_num_retained() == n);
142
- REQUIRE(sketch.get_min_value() == 0.0);
143
- REQUIRE(sketch.get_quantile(0) == 0.0);
144
- REQUIRE(sketch.get_max_value() == n - 1);
145
- REQUIRE(sketch.get_quantile(1) == n - 1);
146
-
147
- int count = 0;
148
- for (auto it: sketch) {
149
- REQUIRE(it.second == 1);
150
- ++count;
151
- }
152
- REQUIRE(count == n);
151
+ REQUIRE(sketch.get_min_item() == 1);
152
+ REQUIRE(sketch.get_quantile(0) == 1);
153
+ REQUIRE(sketch.get_max_item() == n);
154
+ REQUIRE(sketch.get_quantile(1) == n);
153
155
 
154
- const double fractions[3] {0, 0.5, 1};
155
- auto quantiles = sketch.get_quantiles(fractions, 3);
156
+ const double ranks[3] {0, 0.5, 1};
157
+ auto quantiles = sketch.get_quantiles(ranks, 3);
156
158
  REQUIRE(quantiles.size() == 3);
157
- REQUIRE(quantiles[0] == 0.0);
159
+ REQUIRE(quantiles[0] == 1);
158
160
  REQUIRE(quantiles[1] == static_cast<float>(n / 2));
159
- REQUIRE(quantiles[2] == n - 1 );
160
-
161
- for (uint32_t i = 0; i < n; i++) {
162
- const double trueRank = (double) i / n;
163
- REQUIRE(sketch.get_rank(static_cast<float>(i)) == trueRank);
164
- }
161
+ REQUIRE(quantiles[2] == n);
165
162
 
166
163
  // the alternative method must produce the same result
167
164
  auto quantiles2 = sketch.get_quantiles(3);
@@ -169,10 +166,24 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
169
166
  REQUIRE(quantiles[0] == quantiles2[0]);
170
167
  REQUIRE(quantiles[1] == quantiles2[1]);
171
168
  REQUIRE(quantiles[2] == quantiles2[2]);
169
+
170
+ int count = 0;
171
+ for (auto pair: sketch) {
172
+ REQUIRE(pair.second == 1);
173
+ ++count;
174
+ }
175
+ REQUIRE(count == n);
176
+
177
+ for (uint32_t i = 1; i <= n; i++) {
178
+ const double true_rank_inclusive = static_cast<double>(i) / n;
179
+ REQUIRE(sketch.get_rank(static_cast<float>(i)) == true_rank_inclusive);
180
+ const double true_rank_exclusive = static_cast<double>(i - 1) / n;
181
+ REQUIRE(sketch.get_rank(static_cast<float>(i), false) == true_rank_exclusive);
182
+ }
172
183
  }
173
184
 
174
185
  SECTION("10 items") {
175
- quantiles_float_sketch sketch(128, 0);
186
+ quantiles_float_sketch sketch(128, std::less<float>(), 0);
176
187
  sketch.update(1.0f);
177
188
  sketch.update(2.0f);
178
189
  sketch.update(3.0f);
@@ -183,24 +194,24 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
183
194
  sketch.update(8.0f);
184
195
  sketch.update(9.0f);
185
196
  sketch.update(10.0f);
186
- REQUIRE(sketch.get_quantile(0) == 1.0);
187
- REQUIRE(sketch.get_quantile(0.5) == 6.0);
188
- REQUIRE(sketch.get_quantile(0.99) == 10.0);
189
- REQUIRE(sketch.get_quantile(1) == 10.0);
197
+ REQUIRE(sketch.get_quantile(0) == 1);
198
+ REQUIRE(sketch.get_quantile(0.5) == 5);
199
+ REQUIRE(sketch.get_quantile(0.99) == 10);
200
+ REQUIRE(sketch.get_quantile(1) == 10);
190
201
  }
191
202
 
192
- SECTION("100 items") {
193
- quantiles_float_sketch sketch(128, 0);
194
- for (int i = 0; i < 100; ++i) sketch.update(static_cast<float>(i));
195
- REQUIRE(sketch.get_quantile(0) == 0);
203
+ SECTION("100 items, exact mode") {
204
+ quantiles_float_sketch sketch(128, std::less<float>(), 0);
205
+ for (int i = 1; i <= 100; ++i) sketch.update(static_cast<float>(i));
206
+ REQUIRE(sketch.get_quantile(0) == 1);
196
207
  REQUIRE(sketch.get_quantile(0.01) == 1);
197
208
  REQUIRE(sketch.get_quantile(0.5) == 50);
198
- REQUIRE(sketch.get_quantile(0.99) == 99.0);
199
- REQUIRE(sketch.get_quantile(1) == 99.0);
209
+ REQUIRE(sketch.get_quantile(0.99) == 99);
210
+ REQUIRE(sketch.get_quantile(1) == 100);
200
211
  }
201
212
 
202
213
  SECTION("many items, estimation mode") {
203
- quantiles_float_sketch sketch(128, 0);
214
+ quantiles_float_sketch sketch(128, std::less<float>(), 0);
204
215
  const int n = 1000000;
205
216
  for (int i = 0; i < n; i++) {
206
217
  sketch.update(static_cast<float>(i));
@@ -208,51 +219,30 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
208
219
  }
209
220
  REQUIRE_FALSE(sketch.is_empty());
210
221
  REQUIRE(sketch.is_estimation_mode());
211
- REQUIRE(sketch.get_min_value() == 0.0); // min value is exact
212
- REQUIRE(sketch.get_quantile(0) == 0.0); // min value is exact
213
- REQUIRE(sketch.get_max_value() == n - 1); // max value is exact
214
- REQUIRE(sketch.get_quantile(1) == n - 1); // max value is exact
222
+ REQUIRE(sketch.get_min_item() == 0.0); // min value is exact
223
+ REQUIRE(sketch.get_max_item() == n - 1); // max value is exact
215
224
 
216
225
  // test rank
217
226
  for (int i = 0; i < n; i++) {
218
- const double trueRank = static_cast<float>(i) / n;
227
+ const double trueRank = static_cast<float>(i + 1) / n;
219
228
  const double sketchRank = sketch.get_rank(static_cast<float>(i));
220
229
  REQUIRE(sketchRank == Approx(trueRank).margin(RANK_EPS_FOR_K_128));
221
230
  }
222
231
 
223
- // test quantiles at every 0.1 percentage point
224
- double fractions[1001];
225
- double reverse_fractions[1001]; // check that ordering does not matter
226
- for (int i = 0; i < 1001; i++) {
227
- fractions[i] = (double) i / 1000;
228
- reverse_fractions[1000 - i] = fractions[i];
229
- }
230
- auto quantiles = sketch.get_quantiles(fractions, 1001);
231
- auto reverse_quantiles = sketch.get_quantiles(reverse_fractions, 1001);
232
- float previous_quantile(0);
233
- for (int i = 0; i < 1001; i++) {
234
- // expensive in a loop, just to check the equivalence here, not advised for real code
235
- const float quantile = sketch.get_quantile(fractions[i]);
236
- REQUIRE(quantiles[i] == quantile);
237
- REQUIRE(reverse_quantiles[1000 - i] == quantile);
238
- REQUIRE(previous_quantile <= quantile);
239
- previous_quantile = quantile;
240
- }
241
-
242
232
  //std::cout << sketch.to_string();
243
233
 
244
234
  uint32_t count = 0;
245
235
  uint64_t total_weight = 0;
246
- for (auto it: sketch) {
236
+ for (auto pair: sketch) {
247
237
  ++count;
248
- total_weight += it.second;
238
+ total_weight += pair.second;
249
239
  }
250
240
  REQUIRE(count == sketch.get_num_retained());
251
241
  REQUIRE(total_weight == sketch.get_n());
252
242
  }
253
243
 
254
244
  SECTION("consistency between get_rank and get_PMF/CDF") {
255
- quantiles_float_sketch sketch(64, 0);
245
+ quantiles_float_sketch sketch(64, std::less<float>(), 0);
256
246
  const int n = 1000;
257
247
  float values[n];
258
248
  for (int i = 0; i < n; i++) {
@@ -287,149 +277,154 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
287
277
  // get_rank()
288
278
  // using knowledge of internal structure
289
279
  // value still in the base buffer to avoid randomness
290
- REQUIRE(sketch.get_rank<false>(80) == 0.79);
291
- REQUIRE(sketch.get_rank<true>(80) == 0.80);
280
+ REQUIRE(sketch.get_rank(80, false) == 0.79);
281
+ REQUIRE(sketch.get_rank(80, true) == 0.80);
292
282
 
293
283
  // value pushed into higher level
294
- REQUIRE(sketch.get_rank<false>(50) == Approx(0.49).margin(0.01));
295
- REQUIRE(sketch.get_rank<true>(50) == 0.50);
284
+ REQUIRE(sketch.get_rank(50, false) == Approx(0.49).margin(0.01));
285
+ REQUIRE(sketch.get_rank(50, true) == 0.50);
296
286
 
297
287
  // get_quantile()
298
288
  // value still in base buffer
299
- REQUIRE(sketch.get_quantile<false>(0.70) == 71);
300
- REQUIRE(sketch.get_quantile<true>(0.70) == 70);
289
+ REQUIRE(sketch.get_quantile(0.70, false) == 71);
290
+ REQUIRE(sketch.get_quantile(0.70, true) == 70);
301
291
 
302
292
  // value pushed into higher levell
303
- int quantile = sketch.get_quantile<false>(0.30);
293
+ int quantile = sketch.get_quantile(0.30, false);
304
294
  if (quantile != 31 && quantile != 32) { FAIL(); }
305
295
 
306
- quantile = sketch.get_quantile<true>(0.30);
296
+ quantile = sketch.get_quantile(0.30, true);
307
297
  if (quantile != 29 && quantile != 30) { FAIL(); }
308
298
  }
309
299
 
310
300
  SECTION("stream serialize deserialize empty") {
311
- quantiles_float_sketch sketch(128, 0);
301
+ quantiles_float_sketch sketch(128, std::less<float>(), 0);
312
302
  std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
313
303
  sketch.serialize(s);
314
304
  REQUIRE(static_cast<size_t>(s.tellp()) == sketch.get_serialized_size_bytes());
315
- auto sketch2 = quantiles_float_sketch::deserialize(s, serde<float>(), test_allocator<float>(0));
305
+ auto sketch2 = quantiles_float_sketch::deserialize(s, serde<float>(), std::less<float>(), 0);
316
306
  REQUIRE(static_cast<size_t>(s.tellp()) == sketch2.get_serialized_size_bytes());
317
307
  REQUIRE(s.tellg() == s.tellp());
318
308
  REQUIRE(sketch2.is_empty() == sketch.is_empty());
319
309
  REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
320
310
  REQUIRE(sketch2.get_n() == sketch.get_n());
321
311
  REQUIRE(sketch2.get_num_retained() == sketch.get_num_retained());
322
- REQUIRE(std::isnan(sketch2.get_min_value()));
323
- REQUIRE(std::isnan(sketch2.get_max_value()));
312
+ REQUIRE_THROWS_AS(sketch2.get_min_item(), std::runtime_error);
313
+ REQUIRE_THROWS_AS(sketch2.get_max_item(), std::runtime_error);
324
314
  REQUIRE(sketch2.get_normalized_rank_error(false) == sketch.get_normalized_rank_error(false));
325
315
  REQUIRE(sketch2.get_normalized_rank_error(true) == sketch.get_normalized_rank_error(true));
326
316
  }
327
317
 
328
318
  SECTION("bytes serialize deserialize empty") {
329
- quantiles_float_sketch sketch(256, 0);
319
+ quantiles_float_sketch sketch(256, std::less<float>(), 0);
330
320
  auto bytes = sketch.serialize();
331
- auto sketch2 = quantiles_float_sketch::deserialize(bytes.data(), bytes.size(), serde<float>(), 0);
321
+ auto sketch2 = quantiles_float_sketch::deserialize(bytes.data(), bytes.size(), serde<float>(),
322
+ std::less<float>(), 0);
332
323
  REQUIRE(bytes.size() == sketch.get_serialized_size_bytes());
333
324
  REQUIRE(sketch2.is_empty() == sketch.is_empty());
334
325
  REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
335
326
  REQUIRE(sketch2.get_n() == sketch.get_n());
336
327
  REQUIRE(sketch2.get_num_retained() == sketch.get_num_retained());
337
- REQUIRE(std::isnan(sketch2.get_min_value()));
338
- REQUIRE(std::isnan(sketch2.get_max_value()));
328
+ REQUIRE_THROWS_AS(sketch2.get_min_item(), std::runtime_error);
329
+ REQUIRE_THROWS_AS(sketch2.get_max_item(), std::runtime_error);
339
330
  REQUIRE(sketch2.get_normalized_rank_error(false) == sketch.get_normalized_rank_error(false));
340
331
  REQUIRE(sketch2.get_normalized_rank_error(true) == sketch.get_normalized_rank_error(true));
341
332
  }
342
333
 
343
334
  SECTION("stream serialize deserialize one item") {
344
- quantiles_float_sketch sketch(32, 0);
335
+ quantiles_float_sketch sketch(32, std::less<float>(), 0);
345
336
  sketch.update(1.0f);
346
337
  std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
347
338
  sketch.serialize(s);
348
339
  REQUIRE(static_cast<size_t>(s.tellp()) == sketch.get_serialized_size_bytes());
349
- auto sketch2 = quantiles_float_sketch::deserialize(s, serde<float>(), test_allocator<float>(0));
340
+ auto sketch2 = quantiles_float_sketch::deserialize(s, serde<float>(), std::less<float>(), 0);
350
341
  REQUIRE(static_cast<size_t>(s.tellp()) == sketch2.get_serialized_size_bytes());
351
342
  REQUIRE(s.tellg() == s.tellp());
352
343
  REQUIRE_FALSE(sketch2.is_empty());
353
344
  REQUIRE_FALSE(sketch2.is_estimation_mode());
354
345
  REQUIRE(sketch2.get_n() == 1);
355
346
  REQUIRE(sketch2.get_num_retained() == 1);
356
- REQUIRE(sketch2.get_min_value() == 1.0);
357
- REQUIRE(sketch2.get_max_value() == 1.0);
358
- REQUIRE(sketch2.get_quantile(0.5) == 1.0);
359
- REQUIRE(sketch2.get_rank(1) == 0.0);
360
- REQUIRE(sketch2.get_rank(2) == 1.0);
347
+ REQUIRE(sketch2.get_min_item() == 1);
348
+ REQUIRE(sketch2.get_max_item() == 1);
349
+ REQUIRE(sketch2.get_quantile(0.5) == 1);
350
+ REQUIRE(sketch2.get_rank(0) == 0);
351
+ REQUIRE(sketch2.get_rank(1) == 1);
352
+ REQUIRE(sketch2.get_rank(2) == 1);
361
353
  }
362
354
 
363
355
  SECTION("bytes serialize deserialize one item") {
364
- quantiles_float_sketch sketch(64, 0);
356
+ quantiles_float_sketch sketch(64, std::less<float>(), 0);
365
357
  sketch.update(1.0f);
366
358
  auto bytes = sketch.serialize();
367
359
  REQUIRE(bytes.size() == sketch.get_serialized_size_bytes());
368
- auto sketch2 = quantiles_float_sketch::deserialize(bytes.data(), bytes.size(), serde<float>(), 0);
360
+ auto sketch2 = quantiles_float_sketch::deserialize(bytes.data(), bytes.size(), serde<float>(),
361
+ std::less<float>(), 0);
369
362
  REQUIRE(bytes.size() == sketch2.get_serialized_size_bytes());
370
363
  REQUIRE_FALSE(sketch2.is_empty());
371
364
  REQUIRE_FALSE(sketch2.is_estimation_mode());
372
365
  REQUIRE(sketch2.get_n() == 1);
373
366
  REQUIRE(sketch2.get_num_retained() == 1);
374
- REQUIRE(sketch2.get_min_value() == 1.0);
375
- REQUIRE(sketch2.get_max_value() == 1.0);
376
- REQUIRE(sketch2.get_quantile(0.5) == 1.0);
377
- REQUIRE(sketch2.get_rank(1) == 0.0);
378
- REQUIRE(sketch2.get_rank(2) == 1.0);
367
+ REQUIRE(sketch2.get_min_item() == 1);
368
+ REQUIRE(sketch2.get_max_item() == 1);
369
+ REQUIRE(sketch2.get_quantile(0.5) == 1);
370
+ REQUIRE(sketch2.get_rank(0) == 0);
371
+ REQUIRE(sketch2.get_rank(1) == 1);
372
+ REQUIRE(sketch2.get_rank(2) == 1);
379
373
  }
380
374
 
381
375
  SECTION("stream serialize deserialize three items") {
382
- quantiles_float_sketch sketch(128, 0);
376
+ quantiles_float_sketch sketch(128, std::less<float>(), 0);
383
377
  sketch.update(1.0f);
384
378
  sketch.update(2.0f);
385
379
  sketch.update(3.0f);
386
380
  std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
387
381
  sketch.serialize(s);
388
382
  REQUIRE(static_cast<size_t>(s.tellp()) == sketch.get_serialized_size_bytes());
389
- auto sketch2 = quantiles_float_sketch::deserialize(s, serde<float>(), test_allocator<float>(0));
383
+ auto sketch2 = quantiles_float_sketch::deserialize(s, serde<float>(), std::less<float>(), 0);
390
384
  REQUIRE(static_cast<size_t>(s.tellp()) == sketch2.get_serialized_size_bytes());
391
385
  REQUIRE(s.tellg() == s.tellp());
392
386
  REQUIRE_FALSE(sketch2.is_empty());
393
387
  REQUIRE_FALSE(sketch2.is_estimation_mode());
394
388
  REQUIRE(sketch2.get_n() == 3);
395
389
  REQUIRE(sketch2.get_num_retained() == 3);
396
- REQUIRE(sketch2.get_min_value() == 1.0);
397
- REQUIRE(sketch2.get_max_value() == 3.0);
390
+ REQUIRE(sketch2.get_min_item() == 1.0);
391
+ REQUIRE(sketch2.get_max_item() == 3.0);
398
392
  }
399
393
 
400
394
  SECTION("bytes serialize deserialize three items") {
401
- quantiles_float_sketch sketch(128, 0);
395
+ quantiles_float_sketch sketch(128, std::less<float>(), 0);
402
396
  sketch.update(1.0f);
403
397
  sketch.update(2.0f);
404
398
  sketch.update(3.0f);
405
399
  auto bytes = sketch.serialize();
406
400
  REQUIRE(bytes.size() == sketch.get_serialized_size_bytes());
407
- auto sketch2 = quantiles_float_sketch::deserialize(bytes.data(), bytes.size(), serde<float>(), 0);
401
+ auto sketch2 = quantiles_float_sketch::deserialize(bytes.data(), bytes.size(), serde<float>(),
402
+ std::less<float>(), 0);
408
403
  REQUIRE(bytes.size() == sketch2.get_serialized_size_bytes());
409
404
  REQUIRE_FALSE(sketch2.is_empty());
410
405
  REQUIRE_FALSE(sketch2.is_estimation_mode());
411
406
  REQUIRE(sketch2.get_n() == 3);
412
407
  REQUIRE(sketch2.get_num_retained() == 3);
413
- REQUIRE(sketch2.get_min_value() == 1.0);
414
- REQUIRE(sketch2.get_max_value() == 3.0);
408
+ REQUIRE(sketch2.get_min_item() == 1.0);
409
+ REQUIRE(sketch2.get_max_item() == 3.0);
415
410
  }
416
411
 
417
412
  SECTION("stream serialize deserialize many floats") {
418
- quantiles_float_sketch sketch(128, 0);
413
+ quantiles_float_sketch sketch(128, std::less<float>(), 0);
419
414
  const int n = 1000;
420
415
  for (int i = 0; i < n; i++) sketch.update(static_cast<float>(i));
421
416
  std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
422
417
  sketch.serialize(s);
423
418
  REQUIRE(static_cast<size_t>(s.tellp()) == sketch.get_serialized_size_bytes());
424
- auto sketch2 = quantiles_float_sketch::deserialize(s, serde<float>(), test_allocator<float>(0));
419
+ auto sketch2 = quantiles_float_sketch::deserialize(s, serde<float>(), std::less<float>(), 0);
425
420
  REQUIRE(static_cast<size_t>(s.tellp()) == sketch2.get_serialized_size_bytes());
426
421
  REQUIRE(s.tellg() == s.tellp());
427
422
  REQUIRE(sketch2.is_empty() == sketch.is_empty());
428
423
  REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
429
424
  REQUIRE(sketch2.get_n() == sketch.get_n());
430
425
  REQUIRE(sketch2.get_num_retained() == sketch.get_num_retained());
431
- REQUIRE(sketch2.get_min_value() == sketch.get_min_value());
432
- REQUIRE(sketch2.get_max_value() == sketch.get_max_value());
426
+ REQUIRE(sketch2.get_min_item() == sketch.get_min_item());
427
+ REQUIRE(sketch2.get_max_item() == sketch.get_max_item());
433
428
  REQUIRE(sketch2.get_normalized_rank_error(false) == sketch.get_normalized_rank_error(false));
434
429
  REQUIRE(sketch2.get_normalized_rank_error(true) == sketch.get_normalized_rank_error(true));
435
430
  REQUIRE(sketch2.get_quantile(0.5) == sketch.get_quantile(0.5));
@@ -437,27 +432,31 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
437
432
  REQUIRE(sketch2.get_rank(static_cast<float>(n)) == sketch.get_rank(static_cast<float>(n)));
438
433
  }
439
434
  SECTION("bytes serialize deserialize many floats") {
440
- quantiles_float_sketch sketch(128, 0);
435
+ quantiles_float_sketch sketch(128, std::less<float>(), 0);
441
436
  const int n = 1000;
442
437
  for (int i = 0; i < n; i++) sketch.update(static_cast<float>(i));
443
438
  auto bytes = sketch.serialize();
444
439
  REQUIRE(bytes.size() == sketch.get_serialized_size_bytes());
445
- auto sketch2 = quantiles_float_sketch::deserialize(bytes.data(), bytes.size(), serde<float>(), 0);
440
+ auto sketch2 = quantiles_float_sketch::deserialize(bytes.data(), bytes.size(), serde<float>(),
441
+ std::less<float>(), 0);
446
442
  REQUIRE(bytes.size() == sketch2.get_serialized_size_bytes());
447
443
  REQUIRE(sketch2.is_empty() == sketch.is_empty());
448
444
  REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
449
445
  REQUIRE(sketch2.get_n() == sketch.get_n());
450
446
  REQUIRE(sketch2.get_num_retained() == sketch.get_num_retained());
451
- REQUIRE(sketch2.get_min_value() == sketch.get_min_value());
452
- REQUIRE(sketch2.get_max_value() == sketch.get_max_value());
447
+ REQUIRE(sketch2.get_min_item() == sketch.get_min_item());
448
+ REQUIRE(sketch2.get_max_item() == sketch.get_max_item());
453
449
  REQUIRE(sketch2.get_normalized_rank_error(false) == sketch.get_normalized_rank_error(false));
454
450
  REQUIRE(sketch2.get_normalized_rank_error(true) == sketch.get_normalized_rank_error(true));
455
451
  REQUIRE(sketch2.get_quantile(0.5) == sketch.get_quantile(0.5));
456
452
  REQUIRE(sketch2.get_rank(0) == sketch.get_rank(0));
457
453
  REQUIRE(sketch2.get_rank(static_cast<float>(n)) == sketch.get_rank(static_cast<float>(n)));
458
- REQUIRE_THROWS_AS(quantiles_sketch<int>::deserialize(bytes.data(), 7), std::out_of_range);
459
- REQUIRE_THROWS_AS(quantiles_sketch<int>::deserialize(bytes.data(), 15), std::out_of_range);
460
- REQUIRE_THROWS_AS(quantiles_sketch<int>::deserialize(bytes.data(), bytes.size() - 1), std::out_of_range);
454
+ REQUIRE_THROWS_AS(quantiles_float_sketch::deserialize(bytes.data(), 7, serde<float>(), std::less<float>(), 0),
455
+ std::out_of_range);
456
+ REQUIRE_THROWS_AS(quantiles_float_sketch::deserialize(bytes.data(), 15, serde<float>(), std::less<float>(), 0),
457
+ std::out_of_range);
458
+ REQUIRE_THROWS_AS(quantiles_float_sketch::deserialize(bytes.data(), bytes.size() - 1, serde<float>(),
459
+ std::less<float>(), 0), std::out_of_range);
461
460
  }
462
461
 
463
462
  SECTION("bytes serialize deserialize many ints") {
@@ -472,8 +471,8 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
472
471
  REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
473
472
  REQUIRE(sketch2.get_n() == sketch.get_n());
474
473
  REQUIRE(sketch2.get_num_retained() == sketch.get_num_retained());
475
- REQUIRE(sketch2.get_min_value() == sketch.get_min_value());
476
- REQUIRE(sketch2.get_max_value() == sketch.get_max_value());
474
+ REQUIRE(sketch2.get_min_item() == sketch.get_min_item());
475
+ REQUIRE(sketch2.get_max_item() == sketch.get_max_item());
477
476
  REQUIRE(sketch2.get_normalized_rank_error(false) == sketch.get_normalized_rank_error(false));
478
477
  REQUIRE(sketch2.get_normalized_rank_error(true) == sketch.get_normalized_rank_error(true));
479
478
  REQUIRE(sketch2.get_quantile(0.5) == sketch.get_quantile(0.5));
@@ -485,7 +484,7 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
485
484
  }
486
485
 
487
486
  SECTION("out of order split points, float") {
488
- quantiles_float_sketch sketch(256, 0);
487
+ quantiles_float_sketch sketch(256, std::less<float>(), 0);
489
488
  sketch.update(0.0f); // has too be non-empty to reach the check
490
489
  float split_points[2] = {1, 0};
491
490
  REQUIRE_THROWS_AS(sketch.get_CDF(split_points, 2), std::invalid_argument);
@@ -499,72 +498,72 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
499
498
  }
500
499
 
501
500
  SECTION("NaN split point") {
502
- quantiles_float_sketch sketch(512, 0);
501
+ quantiles_float_sketch sketch(512, std::less<float>(), 0);
503
502
  sketch.update(0.0f); // has too be non-empty to reach the check
504
503
  float split_points[1] = {std::numeric_limits<float>::quiet_NaN()};
505
504
  REQUIRE_THROWS_AS(sketch.get_CDF(split_points, 1), std::invalid_argument);
506
505
  }
507
506
 
508
507
  SECTION("merge") {
509
- quantiles_float_sketch sketch1(128, 0);
510
- quantiles_float_sketch sketch2(128, 0);
508
+ quantiles_float_sketch sketch1(128, std::less<float>(), 0);
509
+ quantiles_float_sketch sketch2(128, std::less<float>(), 0);
511
510
  const int n = 10000;
512
511
  for (int i = 0; i < n; i++) {
513
512
  sketch1.update(static_cast<float>(i));
514
513
  sketch2.update(static_cast<float>((2 * n) - i - 1));
515
514
  }
516
515
 
517
- REQUIRE(sketch1.get_min_value() == 0.0f);
518
- REQUIRE(sketch1.get_max_value() == n - 1);
519
- REQUIRE(sketch2.get_min_value() == n);
520
- REQUIRE(sketch2.get_max_value() == 2.0f * n - 1);
516
+ REQUIRE(sketch1.get_min_item() == 0.0f);
517
+ REQUIRE(sketch1.get_max_item() == n - 1);
518
+ REQUIRE(sketch2.get_min_item() == n);
519
+ REQUIRE(sketch2.get_max_item() == 2.0f * n - 1);
521
520
 
522
521
  sketch1.merge(sketch2);
523
522
 
524
523
  REQUIRE_FALSE(sketch1.is_empty());
525
524
  REQUIRE(sketch1.get_n() == 2 * n);
526
- REQUIRE(sketch1.get_min_value() == 0.0f);
527
- REQUIRE(sketch1.get_max_value() == 2.0f * n - 1);
525
+ REQUIRE(sketch1.get_min_item() == 0.0f);
526
+ REQUIRE(sketch1.get_max_item() == 2.0f * n - 1);
528
527
  REQUIRE(sketch1.get_quantile(0.5) == Approx(n).margin(n * RANK_EPS_FOR_K_128));
529
528
  }
530
529
 
531
530
  SECTION("merge from const") {
532
- quantiles_float_sketch sketch1(128, 0);
533
- quantiles_float_sketch sketch2(128, 0);
531
+ quantiles_float_sketch sketch1(128, std::less<float>(), 0);
532
+ quantiles_float_sketch sketch2(128, std::less<float>(), 0);
534
533
  const int n = 10000;
535
534
  for (int i = 0; i < n; i++) {
536
535
  sketch1.update(static_cast<float>(i));
537
536
  sketch2.update(static_cast<float>((2 * n) - i - 1));
538
537
  }
539
538
 
540
- REQUIRE(sketch1.get_min_value() == 0.0f);
541
- REQUIRE(sketch1.get_max_value() == n - 1);
542
- REQUIRE(sketch2.get_min_value() == n);
543
- REQUIRE(sketch2.get_max_value() == 2.0f * n - 1);
539
+ REQUIRE(sketch1.get_min_item() == 0.0f);
540
+ REQUIRE(sketch1.get_max_item() == n - 1);
541
+ REQUIRE(sketch2.get_min_item() == n);
542
+ REQUIRE(sketch2.get_max_item() == 2.0f * n - 1);
544
543
 
545
544
  sketch1.merge(const_cast<const quantiles_float_sketch&>(sketch2));
546
545
 
547
546
  REQUIRE_FALSE(sketch1.is_empty());
548
547
  REQUIRE(sketch1.get_n() == 2 * n);
549
- REQUIRE(sketch1.get_min_value() == 0.0f);
550
- REQUIRE(sketch1.get_max_value() == 2.0f * n - 1);
548
+ REQUIRE(sketch1.get_min_item() == 0.0f);
549
+ REQUIRE(sketch1.get_max_item() == 2.0f * n - 1);
551
550
  REQUIRE(sketch1.get_quantile(0.5) == Approx(n).margin(n * RANK_EPS_FOR_K_128));
552
551
  }
553
552
 
554
553
 
555
554
  SECTION("merge lower k") {
556
- quantiles_float_sketch sketch1(256, 0);
557
- quantiles_float_sketch sketch2(128, 0);
555
+ quantiles_float_sketch sketch1(256, std::less<float>(), 0);
556
+ quantiles_float_sketch sketch2(128, std::less<float>(), 0);
558
557
  const int n = 10000;
559
558
  for (int i = 0; i < n; i++) {
560
559
  sketch1.update(static_cast<float>(i));
561
560
  sketch2.update(static_cast<float>((2 * n) - i - 1));
562
561
  }
563
562
 
564
- REQUIRE(sketch1.get_min_value() == 0.0f);
565
- REQUIRE(sketch1.get_max_value() == n - 1);
566
- REQUIRE(sketch2.get_min_value() == n);
567
- REQUIRE(sketch2.get_max_value() == 2.0f * n - 1);
563
+ REQUIRE(sketch1.get_min_item() == 0.0f);
564
+ REQUIRE(sketch1.get_max_item() == n - 1);
565
+ REQUIRE(sketch2.get_min_item() == n);
566
+ REQUIRE(sketch2.get_max_item() == 2.0f * n - 1);
568
567
 
569
568
  REQUIRE(sketch1.get_k() == 256);
570
569
  REQUIRE(sketch2.get_k() == 128);
@@ -580,14 +579,14 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
580
579
 
581
580
  REQUIRE_FALSE(sketch1.is_empty());
582
581
  REQUIRE(sketch1.get_n() == 2 * n);
583
- REQUIRE(sketch1.get_min_value() == 0.0f);
584
- REQUIRE(sketch1.get_max_value() == 2.0f * n - 1);
582
+ REQUIRE(sketch1.get_min_item() == 0.0f);
583
+ REQUIRE(sketch1.get_max_item() == 2.0f * n - 1);
585
584
  REQUIRE(sketch1.get_quantile(0.5) == Approx(n).margin(n * RANK_EPS_FOR_K_128));
586
585
  }
587
586
 
588
587
  SECTION("merge exact mode, lower k") {
589
- quantiles_float_sketch sketch1(256, 0);
590
- quantiles_float_sketch sketch2(128, 0);
588
+ quantiles_float_sketch sketch1(256, std::less<float>(), 0);
589
+ quantiles_float_sketch sketch2(128, std::less<float>(), 0);
591
590
  const int n = 10000;
592
591
  for (int i = 0; i < n; i++) {
593
592
  sketch1.update(static_cast<float>(i));
@@ -600,8 +599,8 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
600
599
 
601
600
  REQUIRE_FALSE(sketch1.is_empty());
602
601
  REQUIRE(sketch1.get_n() == n);
603
- REQUIRE(sketch1.get_min_value() == 0.0f);
604
- REQUIRE(sketch1.get_max_value() == n - 1);
602
+ REQUIRE(sketch1.get_min_item() == 0.0f);
603
+ REQUIRE(sketch1.get_max_item() == n - 1);
605
604
  REQUIRE(sketch1.get_quantile(0.5) == Approx(n / 2).margin(n / 2 * RANK_EPS_FOR_K_128));
606
605
 
607
606
  sketch2.update(static_cast<float>(0));
@@ -611,27 +610,27 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
611
610
  }
612
611
 
613
612
  SECTION("merge min value from other") {
614
- quantiles_float_sketch sketch1(128, 0);
615
- quantiles_float_sketch sketch2(128, 0);
613
+ quantiles_float_sketch sketch1(128, std::less<float>(), 0);
614
+ quantiles_float_sketch sketch2(128, std::less<float>(), 0);
616
615
  sketch1.update(1.0f);
617
616
  sketch2.update(2.0f);
618
617
  sketch2.merge(sketch1);
619
- REQUIRE(sketch2.get_min_value() == 1.0f);
620
- REQUIRE(sketch2.get_max_value() == 2.0f);
618
+ REQUIRE(sketch2.get_min_item() == 1.0f);
619
+ REQUIRE(sketch2.get_max_item() == 2.0f);
621
620
  }
622
621
 
623
622
  SECTION("merge min and max values from other") {
624
- quantiles_float_sketch sketch1(128, 0);
623
+ quantiles_float_sketch sketch1(128, std::less<float>(), 0);
625
624
  for (int i = 0; i < 1000000; i++) sketch1.update(static_cast<float>(i));
626
- quantiles_float_sketch sketch2(128, 0);
625
+ quantiles_float_sketch sketch2(128, std::less<float>(), 0);
627
626
  sketch2.merge(sketch1);
628
- REQUIRE(sketch2.get_min_value() == 0.0f);
629
- REQUIRE(sketch2.get_max_value() == 999999.0f);
627
+ REQUIRE(sketch2.get_min_item() == 0.0f);
628
+ REQUIRE(sketch2.get_max_item() == 999999.0f);
630
629
  }
631
630
 
632
631
  SECTION("merge: two empty") {
633
- quantiles_float_sketch sk1(128, 0);
634
- quantiles_float_sketch sk2(64, 0);
632
+ quantiles_float_sketch sk1(128, std::less<float>(), 0);
633
+ quantiles_float_sketch sk2(64, std::less<float>(), 0);
635
634
  sk1.merge(sk2);
636
635
  REQUIRE(sk1.get_n() == 0);
637
636
  REQUIRE(sk1.get_k() == 128);
@@ -643,8 +642,8 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
643
642
 
644
643
  SECTION("merge: exact as input") {
645
644
  const uint16_t k = 128;
646
- quantiles_float_sketch sketch1(2 * k, 0);
647
- quantiles_float_sketch sketch2(k, 0);
645
+ quantiles_float_sketch sketch1(2 * k, std::less<float>(), 0);
646
+ quantiles_float_sketch sketch2(k, std::less<float>(), 0);
648
647
 
649
648
  for (int i = 0; i < k / 2; i++) {
650
649
  sketch1.update(static_cast<float>(i));
@@ -658,14 +657,14 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
658
657
  sketch1.merge(sketch2);
659
658
  REQUIRE(sketch1.get_n() == 101 * k);
660
659
  REQUIRE(sketch1.get_k() == 2 * k); // no reason to have shrunk
661
- REQUIRE(sketch1.get_min_value() == 0.0f);
662
- REQUIRE(sketch1.get_max_value() == static_cast<float>(100 * k - 1));
660
+ REQUIRE(sketch1.get_min_item() == 0.0f);
661
+ REQUIRE(sketch1.get_max_item() == static_cast<float>(100 * k - 1));
663
662
  }
664
663
 
665
664
  SECTION("merge: src estimation, tgt exact, tgt.k > src.k") {
666
665
  const uint16_t k = 128;
667
- quantiles_float_sketch sketch1(2 * k, 0);
668
- quantiles_float_sketch sketch2(k, 0);
666
+ quantiles_float_sketch sketch1(2 * k, std::less<float>(), 0);
667
+ quantiles_float_sketch sketch2(k, std::less<float>(), 0);
669
668
 
670
669
  for (int i = 0; i < k / 2; i++) {
671
670
  sketch1.update(static_cast<float>(i));
@@ -679,14 +678,14 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
679
678
  sketch1.merge(sketch2);
680
679
  REQUIRE(sketch1.get_n() == 101 * k);
681
680
  REQUIRE(sketch1.get_k() == k); // no reason to have shrunk
682
- REQUIRE(sketch1.get_min_value() == 0.0f);
683
- REQUIRE(sketch1.get_max_value() == static_cast<float>(100 * k - 1));
681
+ REQUIRE(sketch1.get_min_item() == 0.0f);
682
+ REQUIRE(sketch1.get_max_item() == static_cast<float>(100 * k - 1));
684
683
  }
685
684
 
686
685
  SECTION("merge: both estimation, tgt.k < src.k") {
687
686
  const uint16_t k = 128;
688
- quantiles_float_sketch sketch1(k, 0);
689
- quantiles_float_sketch sketch2(2 * k, 0);
687
+ quantiles_float_sketch sketch1(k, std::less<float>(), 0);
688
+ quantiles_float_sketch sketch2(2 * k, std::less<float>(), 0);
690
689
 
691
690
  for (int i = 0; i < 100 * k; i++) {
692
691
  sketch1.update(static_cast<float>(i));
@@ -696,15 +695,15 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
696
695
  sketch1.merge(sketch2);
697
696
  REQUIRE(sketch1.get_n() == 200 * k);
698
697
  REQUIRE(sketch1.get_k() == k); // no reason to have shrunk
699
- REQUIRE(sketch1.get_min_value() == static_cast<float>(-100 * k + 1));
700
- REQUIRE(sketch1.get_max_value() == static_cast<float>(100 * k - 1));
698
+ REQUIRE(sketch1.get_min_item() == static_cast<float>(-100 * k + 1));
699
+ REQUIRE(sketch1.get_max_item() == static_cast<float>(100 * k - 1));
701
700
  REQUIRE(sketch1.get_quantile(0.5) == Approx(0.0).margin(100 * k * RANK_EPS_FOR_K_128));
702
701
  }
703
702
 
704
703
  SECTION("merge: src estimation, tgt exact, equal k") {
705
704
  const uint16_t k = 128;
706
- quantiles_float_sketch sketch1(k, 0);
707
- quantiles_float_sketch sketch2(k, 0);
705
+ quantiles_float_sketch sketch1(k, std::less<float>(), 0);
706
+ quantiles_float_sketch sketch2(k, std::less<float>(), 0);
708
707
 
709
708
  for (int i = 0; i < k / 2; i++) {
710
709
  sketch1.update(static_cast<float>(i));
@@ -718,16 +717,16 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
718
717
  sketch1.merge(sketch2);
719
718
  REQUIRE(sketch1.get_n() == 100 * k);
720
719
  REQUIRE(sketch1.get_k() == k);
721
- REQUIRE(sketch1.get_min_value() == 0.0f);
722
- REQUIRE(sketch1.get_max_value() == static_cast<float>(100 * k - 1));
720
+ REQUIRE(sketch1.get_min_item() == 0.0f);
721
+ REQUIRE(sketch1.get_max_item() == static_cast<float>(100 * k - 1));
723
722
  float n = 100 * k - 1;
724
723
  REQUIRE(sketch1.get_quantile(0.5) == Approx(n / 2).margin(n / 2 * RANK_EPS_FOR_K_128));
725
724
  }
726
725
 
727
726
  SECTION("merge: both estimation, no base buffer, same k") {
728
727
  const uint16_t k = 128;
729
- quantiles_float_sketch sketch1(k, 0);
730
- quantiles_float_sketch sketch2(k, 0);
728
+ quantiles_float_sketch sketch1(k, std::less<float>(), 0);
729
+ quantiles_float_sketch sketch2(k, std::less<float>(), 0);
731
730
 
732
731
  uint64_t n = 2 * k;
733
732
  for (uint64_t i = 0; i < n; i++) {
@@ -738,15 +737,15 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
738
737
  sketch1.merge(sketch2);
739
738
  REQUIRE(sketch1.get_n() == 2 * n);
740
739
  REQUIRE(sketch1.get_k() == k);
741
- REQUIRE(sketch1.get_min_value() == 0.0f);
742
- REQUIRE(sketch1.get_max_value() == static_cast<float>(2 * n - 1));
740
+ REQUIRE(sketch1.get_min_item() == 0.0f);
741
+ REQUIRE(sketch1.get_max_item() == static_cast<float>(2 * n - 1));
743
742
  REQUIRE(sketch1.get_quantile(0.5) == Approx(n).margin(n * RANK_EPS_FOR_K_128));
744
743
  }
745
744
 
746
745
  SECTION("merge: both estimation, no base buffer, tgt.k < src.k") {
747
746
  const uint16_t k = 128;
748
- quantiles_float_sketch sketch1(k, 0);
749
- quantiles_float_sketch sketch2(2 * k, 0);
747
+ quantiles_float_sketch sketch1(k, std::less<float>(), 0);
748
+ quantiles_float_sketch sketch2(2 * k, std::less<float>(), 0);
750
749
 
751
750
  uint64_t n = 4 * k;
752
751
  for (uint64_t i = 0; i < n; i++) {
@@ -757,16 +756,16 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
757
756
  sketch1.merge(sketch2);
758
757
  REQUIRE(sketch1.get_n() == 2 * n);
759
758
  REQUIRE(sketch1.get_k() == k);
760
- REQUIRE(sketch1.get_min_value() == 0.0f);
761
- REQUIRE(sketch1.get_max_value() == static_cast<float>(2 * n - 1));
759
+ REQUIRE(sketch1.get_min_item() == 0.0f);
760
+ REQUIRE(sketch1.get_max_item() == static_cast<float>(2 * n - 1));
762
761
  REQUIRE(sketch1.get_quantile(0.5) == Approx(n).margin(n * RANK_EPS_FOR_K_128));
763
762
  }
764
763
 
765
764
  SECTION("sketch of ints") {
766
765
  quantiles_sketch<int> sketch;
767
766
  REQUIRE_THROWS_AS(sketch.get_quantile(0), std::runtime_error);
768
- REQUIRE_THROWS_AS(sketch.get_min_value(), std::runtime_error);
769
- REQUIRE_THROWS_AS(sketch.get_max_value(), std::runtime_error);
767
+ REQUIRE_THROWS_AS(sketch.get_min_item(), std::runtime_error);
768
+ REQUIRE_THROWS_AS(sketch.get_max_item(), std::runtime_error);
770
769
 
771
770
  const int n = 10000;
772
771
  for (int i = 0; i < n; i++) sketch.update(i);
@@ -781,8 +780,8 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
781
780
  REQUIRE(sketch2.is_estimation_mode() == sketch.is_estimation_mode());
782
781
  REQUIRE(sketch2.get_n() == sketch.get_n());
783
782
  REQUIRE(sketch2.get_num_retained() == sketch.get_num_retained());
784
- REQUIRE(sketch2.get_min_value() == sketch.get_min_value());
785
- REQUIRE(sketch2.get_max_value() == sketch.get_max_value());
783
+ REQUIRE(sketch2.get_min_item() == sketch.get_min_item());
784
+ REQUIRE(sketch2.get_max_item() == sketch.get_max_item());
786
785
  REQUIRE(sketch2.get_normalized_rank_error(false) == sketch.get_normalized_rank_error(false));
787
786
  REQUIRE(sketch2.get_normalized_rank_error(true) == sketch.get_normalized_rank_error(true));
788
787
  REQUIRE(sketch2.get_quantile(0.5) == sketch.get_quantile(0.5));
@@ -791,30 +790,31 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
791
790
  }
792
791
 
793
792
  SECTION("sketch of strings stream") {
794
- quantiles_string_sketch sketch1(128, 0);
793
+ quantiles_string_sketch sketch1(128, std::less<std::string>(), 0);
795
794
  REQUIRE_THROWS_AS(sketch1.get_quantile(0), std::runtime_error);
796
- REQUIRE_THROWS_AS(sketch1.get_min_value(), std::runtime_error);
797
- REQUIRE_THROWS_AS(sketch1.get_max_value(), std::runtime_error);
795
+ REQUIRE_THROWS_AS(sketch1.get_min_item(), std::runtime_error);
796
+ REQUIRE_THROWS_AS(sketch1.get_max_item(), std::runtime_error);
798
797
  REQUIRE(sketch1.get_serialized_size_bytes() == 8);
799
798
 
800
799
  const int n = 1000;
801
800
  for (int i = 0; i < n; i++) sketch1.update(std::to_string(i));
802
801
 
803
- REQUIRE(sketch1.get_min_value() == std::string("0"));
804
- REQUIRE(sketch1.get_max_value() == std::string("999"));
802
+ REQUIRE(sketch1.get_min_item() == std::string("0"));
803
+ REQUIRE(sketch1.get_max_item() == std::string("999"));
805
804
 
806
805
  std::stringstream s(std::ios::in | std::ios::out | std::ios::binary);
807
806
  sketch1.serialize(s);
808
807
  REQUIRE(static_cast<size_t>(s.tellp()) == sketch1.get_serialized_size_bytes());
809
- auto sketch2 = quantiles_string_sketch::deserialize(s, serde<std::string>(), test_allocator<std::string>(0));
808
+ auto sketch2 = quantiles_string_sketch::deserialize(s, serde<std::string>(),
809
+ std::less<std::string>(), 0);
810
810
  REQUIRE(static_cast<size_t>(s.tellp()) == sketch2.get_serialized_size_bytes());
811
811
  REQUIRE(s.tellg() == s.tellp());
812
812
  REQUIRE(sketch2.is_empty() == sketch1.is_empty());
813
813
  REQUIRE(sketch2.is_estimation_mode() == sketch1.is_estimation_mode());
814
814
  REQUIRE(sketch2.get_n() == sketch1.get_n());
815
815
  REQUIRE(sketch2.get_num_retained() == sketch1.get_num_retained());
816
- REQUIRE(sketch2.get_min_value() == sketch1.get_min_value());
817
- REQUIRE(sketch2.get_max_value() == sketch1.get_max_value());
816
+ REQUIRE(sketch2.get_min_item() == sketch1.get_min_item());
817
+ REQUIRE(sketch2.get_max_item() == sketch1.get_max_item());
818
818
  REQUIRE(sketch2.get_normalized_rank_error(false) == sketch1.get_normalized_rank_error(false));
819
819
  REQUIRE(sketch2.get_normalized_rank_error(true) == sketch1.get_normalized_rank_error(true));
820
820
  REQUIRE(sketch2.get_quantile(0.5) == sketch1.get_quantile(0.5));
@@ -827,28 +827,29 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
827
827
  }
828
828
 
829
829
  SECTION("sketch of strings bytes") {
830
- quantiles_string_sketch sketch1(128, 0);
830
+ quantiles_string_sketch sketch1(128, std::less<std::string>(), 0);
831
831
  REQUIRE_THROWS_AS(sketch1.get_quantile(0), std::runtime_error);
832
- REQUIRE_THROWS_AS(sketch1.get_min_value(), std::runtime_error);
833
- REQUIRE_THROWS_AS(sketch1.get_max_value(), std::runtime_error);
832
+ REQUIRE_THROWS_AS(sketch1.get_min_item(), std::runtime_error);
833
+ REQUIRE_THROWS_AS(sketch1.get_max_item(), std::runtime_error);
834
834
  REQUIRE(sketch1.get_serialized_size_bytes() == 8);
835
835
 
836
836
  const int n = 10000;
837
837
  for (int i = 0; i < n; i++) sketch1.update(std::to_string(i));
838
838
 
839
- REQUIRE(sketch1.get_min_value() == std::string("0"));
840
- REQUIRE(sketch1.get_max_value() == std::string("9999"));
839
+ REQUIRE(sketch1.get_min_item() == std::string("0"));
840
+ REQUIRE(sketch1.get_max_item() == std::string("9999"));
841
841
 
842
842
  auto bytes = sketch1.serialize();
843
843
  REQUIRE(bytes.size() == sketch1.get_serialized_size_bytes());
844
- auto sketch2 = quantiles_string_sketch::deserialize(bytes.data(), bytes.size(), serde<std::string>(), 0);
844
+ auto sketch2 = quantiles_string_sketch::deserialize(bytes.data(), bytes.size(), serde<std::string>(),
845
+ std::less<std::string>(), 0);
845
846
  REQUIRE(bytes.size() == sketch2.get_serialized_size_bytes());
846
847
  REQUIRE(sketch2.is_empty() == sketch1.is_empty());
847
848
  REQUIRE(sketch2.is_estimation_mode() == sketch1.is_estimation_mode());
848
849
  REQUIRE(sketch2.get_n() == sketch1.get_n());
849
850
  REQUIRE(sketch2.get_num_retained() == sketch1.get_num_retained());
850
- REQUIRE(sketch2.get_min_value() == sketch1.get_min_value());
851
- REQUIRE(sketch2.get_max_value() == sketch1.get_max_value());
851
+ REQUIRE(sketch2.get_min_item() == sketch1.get_min_item());
852
+ REQUIRE(sketch2.get_max_item() == sketch1.get_max_item());
852
853
  REQUIRE(sketch2.get_normalized_rank_error(false) == sketch1.get_normalized_rank_error(false));
853
854
  REQUIRE(sketch2.get_normalized_rank_error(true) == sketch1.get_normalized_rank_error(true));
854
855
  REQUIRE(sketch2.get_quantile(0.5) == sketch1.get_quantile(0.5));
@@ -857,11 +858,12 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
857
858
  }
858
859
 
859
860
  SECTION("sketch of strings, single item, bytes") {
860
- quantiles_string_sketch sketch1(64, 0);
861
+ quantiles_string_sketch sketch1(64, std::less<std::string>(), 0);
861
862
  sketch1.update("a");
862
863
  auto bytes = sketch1.serialize();
863
864
  REQUIRE(bytes.size() == sketch1.get_serialized_size_bytes());
864
- auto sketch2 = quantiles_string_sketch::deserialize(bytes.data(), bytes.size(), serde<std::string>(), 0);
865
+ auto sketch2 = quantiles_string_sketch::deserialize(bytes.data(), bytes.size(),
866
+ serde<std::string>(), std::less<std::string>(), 0);
865
867
  REQUIRE(bytes.size() == sketch2.get_serialized_size_bytes());
866
868
  }
867
869
 
@@ -886,20 +888,20 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
886
888
 
887
889
  SECTION("move") {
888
890
  quantiles_sketch<int> sketch1;
889
- const int n(100);
891
+ const int n = 100;
890
892
  for (int i = 0; i < n; i++) sketch1.update(i);
891
893
 
892
894
  // move constructor
893
895
  quantiles_sketch<int> sketch2(std::move(sketch1));
894
896
  for (int i = 0; i < n; i++) {
895
- REQUIRE(sketch2.get_rank(i) == (double) i / n);
897
+ REQUIRE(sketch2.get_rank(i) == static_cast<double>(i + 1) / n);
896
898
  }
897
899
 
898
900
  // move assignment
899
901
  quantiles_sketch<int> sketch3;
900
902
  sketch3 = std::move(sketch2);
901
903
  for (int i = 0; i < n; i++) {
902
- REQUIRE(sketch3.get_rank(i) == (double) i / n);
904
+ REQUIRE(sketch3.get_rank(i) == static_cast<double>(i + 1) / n);
903
905
  }
904
906
  }
905
907
 
@@ -908,7 +910,7 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
908
910
  const int n = 403;
909
911
  quantiles_sketch<double> sk_double(k);
910
912
 
911
- quantiles_sketch<float> sk_float(k, sk_double.get_allocator());
913
+ quantiles_sketch<float> sk_float(k);
912
914
  REQUIRE(sk_float.is_empty());
913
915
 
914
916
  for (int i = 0; i < n; ++i) sk_double.update(i + .01);
@@ -918,10 +920,10 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
918
920
  REQUIRE(sk_double.get_k() == sk_int.get_k());
919
921
  REQUIRE(sk_double.get_num_retained() == sk_int.get_num_retained());
920
922
 
921
- auto sv_double = sk_double.get_sorted_view(false);
923
+ auto sv_double = sk_double.get_sorted_view();
922
924
  std::vector<std::pair<double, uint64_t>> vec_double(sv_double.begin(), sv_double.end());
923
925
 
924
- auto sv_int = sk_int.get_sorted_view(false);
926
+ auto sv_int = sk_int.get_sorted_view();
925
927
  std::vector<std::pair<int, uint64_t>> vec_int(sv_int.begin(), sv_int.end());
926
928
 
927
929
  REQUIRE(vec_double.size() == vec_int.size());
@@ -966,6 +968,12 @@ TEST_CASE("quantiles sketch", "[quantiles_sketch]") {
966
968
  REQUIRE(sb.get_n() == 3);
967
969
  }
968
970
 
971
+ SECTION("comparator and allocator") {
972
+ quantiles_sketch<int> sketch;
973
+ REQUIRE(sketch.get_comparator()(1, 2));
974
+ REQUIRE(sketch.get_allocator() == std::allocator<int>());
975
+ }
976
+
969
977
  // cleanup
970
978
  if (test_allocator_total_bytes != 0) {
971
979
  REQUIRE(test_allocator_total_bytes == 0);