datasketches 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/ext/datasketches/cpc_wrapper.cpp +8 -9
- data/ext/datasketches/fi_wrapper.cpp +4 -5
- data/ext/datasketches/hll_wrapper.cpp +9 -10
- data/ext/datasketches/kll_wrapper.cpp +13 -12
- data/ext/datasketches/theta_wrapper.cpp +11 -13
- data/ext/datasketches/vo_wrapper.cpp +1 -2
- data/lib/datasketches/version.rb +1 -1
- data/vendor/datasketches-cpp/CMakeLists.txt +5 -3
- data/vendor/datasketches-cpp/CODE_OF_CONDUCT.md +1 -1
- data/vendor/datasketches-cpp/LICENSE +14 -0
- data/vendor/datasketches-cpp/README.md +67 -73
- data/vendor/datasketches-cpp/benchmarks/CMakeLists.txt +52 -0
- data/vendor/datasketches-cpp/benchmarks/benchmark_count_min_sketch.cpp +153 -0
- data/vendor/datasketches-cpp/benchmarks/benchmark_count_min_sketch_serialization.cpp +161 -0
- data/vendor/datasketches-cpp/common/CMakeLists.txt +1 -0
- data/vendor/datasketches-cpp/common/include/binomial_bounds.hpp +2 -2
- data/vendor/datasketches-cpp/common/include/fdlibm_log.hpp +101 -0
- data/vendor/datasketches-cpp/common/include/serde.hpp +6 -0
- data/vendor/datasketches-cpp/common/test/CMakeLists.txt +44 -2
- data/vendor/datasketches-cpp/common/test/binomial_bounds_test.cpp +279 -0
- data/vendor/datasketches-cpp/common/test/deserialize_hardening_test.cpp +188 -0
- data/vendor/datasketches-cpp/count/include/count_min.hpp +17 -4
- data/vendor/datasketches-cpp/count/include/count_min_impl.hpp +65 -83
- data/vendor/datasketches-cpp/count/test/count_min_test.cpp +63 -7
- data/vendor/datasketches-cpp/cpc/include/compression_data.hpp +2 -0
- data/vendor/datasketches-cpp/cpc/include/cpc_compressor_impl.hpp +16 -7
- data/vendor/datasketches-cpp/cpc/include/cpc_sketch.hpp +1 -0
- data/vendor/datasketches-cpp/cpc/include/cpc_sketch_impl.hpp +54 -36
- data/vendor/datasketches-cpp/cpc/include/cpc_union_impl.hpp +27 -27
- data/vendor/datasketches-cpp/cpc/include/cpc_util.hpp +7 -7
- data/vendor/datasketches-cpp/cpc/include/icon_estimator.hpp +5 -5
- data/vendor/datasketches-cpp/cpc/include/u32_table_impl.hpp +16 -16
- data/vendor/datasketches-cpp/cpc/test/cpc_sketch_test.cpp +35 -0
- data/vendor/datasketches-cpp/fi/include/frequent_items_sketch.hpp +28 -3
- data/vendor/datasketches-cpp/fi/include/frequent_items_sketch_impl.hpp +41 -25
- data/vendor/datasketches-cpp/fi/include/reverse_purge_hash_map.hpp +3 -1
- data/vendor/datasketches-cpp/fi/include/reverse_purge_hash_map_impl.hpp +10 -5
- data/vendor/datasketches-cpp/fi/test/frequent_items_sketch_serialize_for_java.cpp +24 -0
- data/vendor/datasketches-cpp/fi/test/frequent_items_sketch_test.cpp +116 -0
- data/vendor/datasketches-cpp/filters/include/bloom_filter.hpp +1 -1
- data/vendor/datasketches-cpp/filters/include/bloom_filter_impl.hpp +32 -12
- data/vendor/datasketches-cpp/filters/test/bloom_filter_test.cpp +28 -1
- data/vendor/datasketches-cpp/hll/include/CouponHashSet-internal.hpp +1 -2
- data/vendor/datasketches-cpp/hll/include/CouponList-internal.hpp +19 -5
- data/vendor/datasketches-cpp/hll/include/CubicInterpolation-internal.hpp +4 -4
- data/vendor/datasketches-cpp/hll/include/HarmonicNumbers-internal.hpp +2 -1
- data/vendor/datasketches-cpp/hll/include/Hll4Array-internal.hpp +4 -4
- data/vendor/datasketches-cpp/hll/include/Hll4Array.hpp +1 -1
- data/vendor/datasketches-cpp/hll/include/Hll6Array-internal.hpp +3 -3
- data/vendor/datasketches-cpp/hll/include/Hll6Array.hpp +1 -1
- data/vendor/datasketches-cpp/hll/include/Hll8Array-internal.hpp +6 -3
- data/vendor/datasketches-cpp/hll/include/Hll8Array.hpp +1 -1
- data/vendor/datasketches-cpp/hll/include/HllArray-internal.hpp +35 -29
- data/vendor/datasketches-cpp/hll/include/HllArray.hpp +1 -1
- data/vendor/datasketches-cpp/hll/include/HllSketch-internal.hpp +3 -5
- data/vendor/datasketches-cpp/hll/include/HllSketchImpl-internal.hpp +5 -11
- data/vendor/datasketches-cpp/hll/include/HllSketchImpl.hpp +2 -4
- data/vendor/datasketches-cpp/hll/include/HllSketchImplFactory.hpp +11 -10
- data/vendor/datasketches-cpp/hll/include/HllUnion-internal.hpp +17 -8
- data/vendor/datasketches-cpp/hll/include/HllUtil.hpp +12 -3
- data/vendor/datasketches-cpp/hll/include/coupon_iterator-internal.hpp +2 -2
- data/vendor/datasketches-cpp/hll/include/coupon_iterator.hpp +3 -0
- data/vendor/datasketches-cpp/hll/include/hll.hpp +11 -4
- data/vendor/datasketches-cpp/hll/include/hll.private.hpp +19 -0
- data/vendor/datasketches-cpp/hll/test/CMakeLists.txt +2 -0
- data/vendor/datasketches-cpp/hll/test/CouponListTest.cpp +64 -0
- data/vendor/datasketches-cpp/hll/test/HllFullSizeTest.cpp +137 -0
- data/vendor/datasketches-cpp/hll/test/HllKxqRebuildTest.cpp +150 -0
- data/vendor/datasketches-cpp/hll/test/HllSketchTest.cpp +3 -3
- data/vendor/datasketches-cpp/hll/test/HllUnionTest.cpp +71 -1
- data/vendor/datasketches-cpp/kll/include/kll_helper_impl.hpp +10 -10
- data/vendor/datasketches-cpp/kll/include/kll_sketch.hpp +10 -1
- data/vendor/datasketches-cpp/kll/include/kll_sketch_impl.hpp +33 -24
- data/vendor/datasketches-cpp/kll/test/kll_sketch_deserialize_from_java_test.cpp +24 -0
- data/vendor/datasketches-cpp/kll/test/kll_sketch_serialize_for_java.cpp +10 -0
- data/vendor/datasketches-cpp/quantiles/include/quantiles_sketch.hpp +11 -2
- data/vendor/datasketches-cpp/quantiles/include/quantiles_sketch_impl.hpp +24 -15
- data/vendor/datasketches-cpp/req/include/req_sketch.hpp +9 -0
- data/vendor/datasketches-cpp/req/include/req_sketch_impl.hpp +24 -15
- data/vendor/datasketches-cpp/req/test/req_sketch_deserialize_from_java_test.cpp +46 -0
- data/vendor/datasketches-cpp/req/test/req_sketch_serialize_for_java.cpp +20 -0
- data/vendor/datasketches-cpp/req/test/req_sketch_test.cpp +70 -0
- data/vendor/datasketches-cpp/sampling/include/ebpps_sample_impl.hpp +17 -8
- data/vendor/datasketches-cpp/sampling/include/ebpps_sketch.hpp +13 -0
- data/vendor/datasketches-cpp/sampling/include/var_opt_sketch.hpp +10 -1
- data/vendor/datasketches-cpp/sampling/include/var_opt_sketch_impl.hpp +6 -7
- data/vendor/datasketches-cpp/sampling/include/var_opt_union.hpp +5 -1
- data/vendor/datasketches-cpp/sampling/include/var_opt_union_impl.hpp +2 -1
- data/vendor/datasketches-cpp/sampling/test/ebpps_allocation_test.cpp +1 -1
- data/vendor/datasketches-cpp/sampling/test/ebpps_sketch_test.cpp +2 -2
- data/vendor/datasketches-cpp/sampling/test/var_opt_allocation_test.cpp +1 -1
- data/vendor/datasketches-cpp/sampling/test/var_opt_sketch_test.cpp +10 -4
- data/vendor/datasketches-cpp/sampling/test/var_opt_union_test.cpp +12 -0
- data/vendor/datasketches-cpp/tdigest/include/tdigest.hpp +38 -2
- data/vendor/datasketches-cpp/tdigest/include/tdigest_impl.hpp +168 -9
- data/vendor/datasketches-cpp/tdigest/test/CMakeLists.txt +1 -0
- data/vendor/datasketches-cpp/tdigest/test/tdigest_iterator_test.cpp +274 -0
- data/vendor/datasketches-cpp/tdigest/test/tdigest_test.cpp +275 -0
- data/vendor/datasketches-cpp/theta/include/compact_theta_sketch_parser.hpp +2 -0
- data/vendor/datasketches-cpp/theta/include/compact_theta_sketch_parser_impl.hpp +24 -3
- data/vendor/datasketches-cpp/theta/include/theta_constants.hpp +4 -2
- data/vendor/datasketches-cpp/theta/include/theta_helpers.hpp +32 -0
- data/vendor/datasketches-cpp/theta/include/theta_set_difference_base_impl.hpp +4 -2
- data/vendor/datasketches-cpp/theta/include/theta_sketch.hpp +22 -4
- data/vendor/datasketches-cpp/theta/include/theta_sketch_impl.hpp +60 -38
- data/vendor/datasketches-cpp/theta/include/theta_union_base_impl.hpp +2 -6
- data/vendor/datasketches-cpp/theta/include/theta_update_sketch_base_impl.hpp +2 -2
- data/vendor/datasketches-cpp/theta/test/bit_packing_test.cpp +50 -0
- data/vendor/datasketches-cpp/theta/test/theta_a_not_b_test.cpp +22 -0
- data/vendor/datasketches-cpp/theta/test/theta_sketch_test.cpp +315 -0
- data/vendor/datasketches-cpp/tools/rat-check.sh +68 -0
- data/vendor/datasketches-cpp/tuple/include/array_tuple_sketch.hpp +35 -4
- data/vendor/datasketches-cpp/tuple/include/array_tuple_sketch_impl.hpp +2 -2
- data/vendor/datasketches-cpp/tuple/include/tuple_sketch.hpp +41 -0
- data/vendor/datasketches-cpp/tuple/include/tuple_sketch_impl.hpp +5 -4
- data/vendor/datasketches-cpp/tuple/test/tuple_sketch_test.cpp +59 -0
- data/vendor/datasketches-cpp/version.cfg.in +1 -1
- metadata +12 -2
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
+
* or more contributor license agreements. See the NOTICE file
|
|
4
|
+
* distributed with this work for additional information
|
|
5
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
6
|
+
* to you under the Apache License, Version 2.0 (the
|
|
7
|
+
* "License"); you may not use this file except in compliance
|
|
8
|
+
* with the License. You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing,
|
|
13
|
+
* software distributed under the License is distributed on an
|
|
14
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
15
|
+
* KIND, either express or implied. See the License for the
|
|
16
|
+
* specific language governing permissions and limitations
|
|
17
|
+
* under the License.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
#include <catch2/catch.hpp>
|
|
21
|
+
|
|
22
|
+
#include "binomial_bounds.hpp"
|
|
23
|
+
|
|
24
|
+
namespace datasketches {
|
|
25
|
+
|
|
26
|
+
TEST_CASE("binomial_bounds: get_lower_bound", "[common]") {
|
|
27
|
+
|
|
28
|
+
SECTION("num_samples == 0") {
|
|
29
|
+
double result = binomial_bounds::get_lower_bound(0, 0.5, 1);
|
|
30
|
+
REQUIRE(result == 0.0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
SECTION("theta == 1.0") {
|
|
34
|
+
double result = binomial_bounds::get_lower_bound(100, 1.0, 1);
|
|
35
|
+
REQUIRE(result == 100.0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
SECTION("num_samples == 1") {
|
|
39
|
+
double result = binomial_bounds::get_lower_bound(1, 0.5, 1);
|
|
40
|
+
REQUIRE(result >= 0.0);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
SECTION("num_samples == 1, stddev=2") {
|
|
44
|
+
double result = binomial_bounds::get_lower_bound(1, 0.5, 2);
|
|
45
|
+
REQUIRE(result >= 0.0);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
SECTION("num_samples == 1, stddev=3") {
|
|
49
|
+
double result = binomial_bounds::get_lower_bound(1, 0.5, 3);
|
|
50
|
+
REQUIRE(result >= 0.0);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
SECTION("num_samples > 120") {
|
|
54
|
+
double result = binomial_bounds::get_lower_bound(121, 0.5, 1);
|
|
55
|
+
REQUIRE(result >= 0.0);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
SECTION("num_samples > 120, stddev=2") {
|
|
59
|
+
double result = binomial_bounds::get_lower_bound(200, 0.5, 2);
|
|
60
|
+
REQUIRE(result >= 0.0);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
SECTION("num_samples > 120, stddev=3") {
|
|
64
|
+
double result = binomial_bounds::get_lower_bound(500, 0.5, 3);
|
|
65
|
+
REQUIRE(result >= 0.0);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
SECTION("2 <= num_samples <= 120 AND theta > (1-1e-5)") {
|
|
69
|
+
double result = binomial_bounds::get_lower_bound(50, 1.0 - 1e-6, 1);
|
|
70
|
+
REQUIRE(std::abs(result - 50.0) < 50.0 * 0.01);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
SECTION("2 <= num_samples <= 120 AND theta > (1-1e-5), stddev=2") {
|
|
74
|
+
double result = binomial_bounds::get_lower_bound(50, 1.0 - 1e-6, 2);
|
|
75
|
+
REQUIRE(std::abs(result - 50.0) < 50.0 * 0.01);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
SECTION("2 <= num_samples <= 120 AND theta > (1-1e-5), stddev=3") {
|
|
79
|
+
double result = binomial_bounds::get_lower_bound(50, 1.0 - 1e-6, 3);
|
|
80
|
+
REQUIRE(std::abs(result - 50.0) < 50.0 * 0.01);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
SECTION("2 <= num_samples <= 120 AND theta < num_samples/360") {
|
|
84
|
+
double result = binomial_bounds::get_lower_bound(100, 0.001, 1);
|
|
85
|
+
REQUIRE(result >= 0.0);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
SECTION("2 <= num_samples <= 120 AND theta < num_samples/360, stddev=2") {
|
|
89
|
+
double result = binomial_bounds::get_lower_bound(100, 0.001, 2);
|
|
90
|
+
REQUIRE(result >= 0.0);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
SECTION("2 <= num_samples <= 120 AND theta < num_samples/360, stddev=3") {
|
|
94
|
+
double result = binomial_bounds::get_lower_bound(100, 0.001, 3);
|
|
95
|
+
REQUIRE(result >= 0.0);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
SECTION("2 <= num_samples <= 120 AND middle range theta (exact calculation)") {
|
|
99
|
+
double result = binomial_bounds::get_lower_bound(10, 0.5, 1);
|
|
100
|
+
REQUIRE(result >= 0.0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
SECTION("2 <= num_samples <= 120 AND middle range theta, stddev=2") {
|
|
104
|
+
double result = binomial_bounds::get_lower_bound(10, 0.5, 2);
|
|
105
|
+
REQUIRE(result >= 0.0);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
SECTION("2 <= num_samples <= 120 AND middle range theta, stddev=3") {
|
|
109
|
+
double result = binomial_bounds::get_lower_bound(10, 0.5, 3);
|
|
110
|
+
REQUIRE(result >= 0.0);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
SECTION("theta=0") {
|
|
114
|
+
REQUIRE_THROWS_AS(binomial_bounds::get_lower_bound(10, 0.0, 1), std::invalid_argument);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
SECTION("theta very close to 0") {
|
|
118
|
+
double result = binomial_bounds::get_lower_bound(10, 1e-10, 1);
|
|
119
|
+
REQUIRE(result >= 0.0);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
SECTION("num_samples=2 boundary") {
|
|
123
|
+
double result = binomial_bounds::get_lower_bound(2, 0.5, 1);
|
|
124
|
+
REQUIRE(result >= 0.0);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
SECTION("num_samples=120 boundary") {
|
|
128
|
+
double result = binomial_bounds::get_lower_bound(120, 0.5, 1);
|
|
129
|
+
REQUIRE(result >= 0.0);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
SECTION("estimate clamping case") {
|
|
133
|
+
double result = binomial_bounds::get_lower_bound(10, 0.9, 1);
|
|
134
|
+
double estimate = 10.0 / 0.9;
|
|
135
|
+
REQUIRE(result <= estimate);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
SECTION("invalid theta < 0") {
|
|
139
|
+
REQUIRE_THROWS_AS(binomial_bounds::get_lower_bound(100, -0.1, 1), std::invalid_argument);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
SECTION("invalid theta > 1") {
|
|
143
|
+
REQUIRE_THROWS_AS(binomial_bounds::get_lower_bound(100, 1.1, 1), std::invalid_argument);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
SECTION("invalid stddev = 0") {
|
|
147
|
+
REQUIRE_THROWS_AS(binomial_bounds::get_lower_bound(100, 0.5, 0), std::invalid_argument);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
SECTION("invalid stddev = 4") {
|
|
151
|
+
REQUIRE_THROWS_AS(binomial_bounds::get_lower_bound(100, 0.5, 4), std::invalid_argument);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
TEST_CASE("binomial_bounds: get_upper_bound", "[common]") {
|
|
156
|
+
|
|
157
|
+
SECTION("theta == 1.0") {
|
|
158
|
+
double result = binomial_bounds::get_upper_bound(100, 1.0, 1);
|
|
159
|
+
REQUIRE(result == 100.0);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
SECTION("num_samples == 0") {
|
|
163
|
+
double result = binomial_bounds::get_upper_bound(0, 0.5, 1);
|
|
164
|
+
REQUIRE(result > 0.0);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
SECTION("num_samples == 0, stddev=2") {
|
|
168
|
+
double result = binomial_bounds::get_upper_bound(0, 0.5, 2);
|
|
169
|
+
REQUIRE(result > 0.0);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
SECTION("num_samples == 0, stddev=3") {
|
|
173
|
+
double result = binomial_bounds::get_upper_bound(0, 0.5, 3);
|
|
174
|
+
REQUIRE(result > 0.0);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
SECTION("num_samples > 120") {
|
|
178
|
+
double result = binomial_bounds::get_upper_bound(121, 0.5, 1);
|
|
179
|
+
REQUIRE(result >= 0.0);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
SECTION("num_samples > 120, stddev=2") {
|
|
183
|
+
double result = binomial_bounds::get_upper_bound(200, 0.5, 2);
|
|
184
|
+
REQUIRE(result >= 0.0);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
SECTION("num_samples > 120, stddev=3") {
|
|
188
|
+
double result = binomial_bounds::get_upper_bound(500, 0.5, 3);
|
|
189
|
+
REQUIRE(result >= 0.0);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
SECTION("1 <= num_samples <= 120 AND theta > (1-1e-5)") {
|
|
193
|
+
double result = binomial_bounds::get_upper_bound(50, 1.0 - 1e-6, 1);
|
|
194
|
+
REQUIRE(result == 51.0);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
SECTION("1 <= num_samples <= 120 AND theta > (1-1e-5), stddev=2") {
|
|
198
|
+
double result = binomial_bounds::get_upper_bound(50, 1.0 - 1e-6, 2);
|
|
199
|
+
REQUIRE(result == 51.0);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
SECTION("1 <= num_samples <= 120 AND theta > (1-1e-5), stddev=3") {
|
|
203
|
+
double result = binomial_bounds::get_upper_bound(50, 1.0 - 1e-6, 3);
|
|
204
|
+
REQUIRE(result == 51.0);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
SECTION("1 <= num_samples <= 120 AND theta < num_samples/360") {
|
|
208
|
+
double result = binomial_bounds::get_upper_bound(100, 0.001, 1);
|
|
209
|
+
REQUIRE(result >= 0.0);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
SECTION("1 <= num_samples <= 120 AND theta < num_samples/360, stddev=2") {
|
|
213
|
+
double result = binomial_bounds::get_upper_bound(100, 0.001, 2);
|
|
214
|
+
REQUIRE(result >= 0.0);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
SECTION("1 <= num_samples <= 120 AND theta < num_samples/360, stddev=3") {
|
|
218
|
+
double result = binomial_bounds::get_upper_bound(100, 0.001, 3);
|
|
219
|
+
REQUIRE(result >= 0.0);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
SECTION("1 <= num_samples <= 120 AND middle range theta (exact calculation)") {
|
|
223
|
+
double result = binomial_bounds::get_upper_bound(10, 0.5, 1);
|
|
224
|
+
REQUIRE(result >= 0.0);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
SECTION("1 <= num_samples <= 120 AND middle range theta, stddev=2") {
|
|
228
|
+
double result = binomial_bounds::get_upper_bound(10, 0.5, 2);
|
|
229
|
+
REQUIRE(result >= 0.0);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
SECTION("1 <= num_samples <= 120 AND middle range theta, stddev=3") {
|
|
233
|
+
double result = binomial_bounds::get_upper_bound(10, 0.5, 3);
|
|
234
|
+
REQUIRE(result >= 0.0);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
SECTION("theta=0") {
|
|
238
|
+
REQUIRE_THROWS_AS(binomial_bounds::get_upper_bound(10, 0.0, 1), std::invalid_argument);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
SECTION("theta very close to 0") {
|
|
242
|
+
double result = binomial_bounds::get_upper_bound(10, 1e-10, 1);
|
|
243
|
+
REQUIRE(result >= 0.0);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
SECTION("num_samples=1 boundary") {
|
|
247
|
+
double result = binomial_bounds::get_upper_bound(1, 0.5, 1);
|
|
248
|
+
REQUIRE(result >= 0.0);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
SECTION("num_samples=120 boundary") {
|
|
252
|
+
double result = binomial_bounds::get_upper_bound(120, 0.5, 1);
|
|
253
|
+
REQUIRE(result >= 0.0);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
SECTION("estimate clamping case") {
|
|
257
|
+
double result = binomial_bounds::get_upper_bound(10, 0.9, 1);
|
|
258
|
+
double estimate = 10.0 / 0.9;
|
|
259
|
+
REQUIRE(result >= estimate);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
SECTION("invalid theta < 0") {
|
|
263
|
+
REQUIRE_THROWS_AS(binomial_bounds::get_upper_bound(100, -0.1, 1), std::invalid_argument);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
SECTION("invalid theta > 1") {
|
|
267
|
+
REQUIRE_THROWS_AS(binomial_bounds::get_upper_bound(100, 1.1, 1), std::invalid_argument);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
SECTION("invalid stddev = 0") {
|
|
271
|
+
REQUIRE_THROWS_AS(binomial_bounds::get_upper_bound(100, 0.5, 0), std::invalid_argument);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
SECTION("invalid stddev = 4") {
|
|
275
|
+
REQUIRE_THROWS_AS(binomial_bounds::get_upper_bound(100, 0.5, 4), std::invalid_argument);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
} /* namespace datasketches */
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
+
* or more contributor license agreements. See the NOTICE file
|
|
4
|
+
* distributed with this work for additional information
|
|
5
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
6
|
+
* to you under the Apache License, Version 2.0 (the
|
|
7
|
+
* "License"); you may not use this file except in compliance
|
|
8
|
+
* with the License. You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing,
|
|
13
|
+
* software distributed under the License is distributed on an
|
|
14
|
+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
15
|
+
* KIND, either express or implied. See the License for the
|
|
16
|
+
* specific language governing permissions and limitations
|
|
17
|
+
* under the License.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
#include <catch2/catch.hpp>
|
|
21
|
+
#include <sstream>
|
|
22
|
+
#include <vector>
|
|
23
|
+
|
|
24
|
+
// Include all affected sketch types
|
|
25
|
+
#include <quantiles_sketch.hpp>
|
|
26
|
+
#include <kll_sketch.hpp>
|
|
27
|
+
#include <req_sketch.hpp>
|
|
28
|
+
|
|
29
|
+
namespace datasketches {
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Test for fix of issue #477:
|
|
33
|
+
* BUG: SIGABRT in deserialize(): dereferencing empty std::optional (libc++ verbose_abort)
|
|
34
|
+
*
|
|
35
|
+
* These tests exercise the actual deserialization code path that contained the bug.
|
|
36
|
+
* With buggy code (&*tmp on empty optional) and hardening enabled, these will SIGABRT.
|
|
37
|
+
* With fixed code (aligned_storage), these pass normally.
|
|
38
|
+
*
|
|
39
|
+
* IMPORTANT: These tests actually call deserialize() on multi-item sketches, which
|
|
40
|
+
* exercises the buggy code path where min/max are deserialized.
|
|
41
|
+
*/
|
|
42
|
+
|
|
43
|
+
TEST_CASE("quantiles_sketch: deserialize multi-item sketch", "[deserialize_hardening]") {
|
|
44
|
+
// Create sketch with multiple items (so min/max are stored in serialization)
|
|
45
|
+
quantiles_sketch<double> sketch(128);
|
|
46
|
+
for (int i = 0; i < 1000; i++) {
|
|
47
|
+
sketch.update(static_cast<double>(i));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Serialize
|
|
51
|
+
auto bytes = sketch.serialize();
|
|
52
|
+
|
|
53
|
+
// Deserialize - WITH BUGGY CODE AND HARDENING, THIS WILL SIGABRT HERE
|
|
54
|
+
// The bug is: sd.deserialize(is, &*tmp, 1) where tmp is empty optional
|
|
55
|
+
auto sketch2 = quantiles_sketch<double>::deserialize(bytes.data(), bytes.size());
|
|
56
|
+
|
|
57
|
+
// Verify deserialization worked correctly
|
|
58
|
+
REQUIRE(sketch2.get_n() == sketch.get_n());
|
|
59
|
+
REQUIRE(sketch2.get_min_item() == sketch.get_min_item());
|
|
60
|
+
REQUIRE(sketch2.get_max_item() == sketch.get_max_item());
|
|
61
|
+
REQUIRE(sketch2.get_quantile(0.5) == sketch.get_quantile(0.5));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
TEST_CASE("quantiles_sketch: deserialize from stream", "[deserialize_hardening]") {
|
|
65
|
+
quantiles_sketch<float> sketch(256);
|
|
66
|
+
for (int i = 0; i < 2000; i++) {
|
|
67
|
+
sketch.update(static_cast<float>(i) * 0.5f);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Serialize to stream
|
|
71
|
+
std::stringstream ss;
|
|
72
|
+
sketch.serialize(ss);
|
|
73
|
+
|
|
74
|
+
// Deserialize from stream - exercises the buggy code path
|
|
75
|
+
auto sketch2 = quantiles_sketch<float>::deserialize(ss);
|
|
76
|
+
|
|
77
|
+
REQUIRE(sketch2.get_n() == sketch.get_n());
|
|
78
|
+
REQUIRE(sketch2.get_min_item() == sketch.get_min_item());
|
|
79
|
+
REQUIRE(sketch2.get_max_item() == sketch.get_max_item());
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
TEST_CASE("kll_sketch: deserialize multi-item sketch", "[deserialize_hardening]") {
|
|
83
|
+
kll_sketch<float> sketch(200);
|
|
84
|
+
for (int i = 0; i < 1500; i++) {
|
|
85
|
+
sketch.update(static_cast<float>(i));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
auto bytes = sketch.serialize();
|
|
89
|
+
|
|
90
|
+
// Deserialize - exercises buggy &*tmp code path
|
|
91
|
+
auto sketch2 = kll_sketch<float>::deserialize(bytes.data(), bytes.size());
|
|
92
|
+
|
|
93
|
+
REQUIRE(sketch2.get_n() == sketch.get_n());
|
|
94
|
+
REQUIRE(sketch2.get_min_item() == sketch.get_min_item());
|
|
95
|
+
REQUIRE(sketch2.get_max_item() == sketch.get_max_item());
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
TEST_CASE("kll_sketch: deserialize from stream", "[deserialize_hardening]") {
|
|
99
|
+
kll_sketch<int> sketch(400);
|
|
100
|
+
for (int i = 0; i < 3000; i++) {
|
|
101
|
+
sketch.update(i);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
std::stringstream ss;
|
|
105
|
+
sketch.serialize(ss);
|
|
106
|
+
|
|
107
|
+
// Deserialize from stream
|
|
108
|
+
auto sketch2 = kll_sketch<int>::deserialize(ss);
|
|
109
|
+
|
|
110
|
+
REQUIRE(sketch2.get_n() == sketch.get_n());
|
|
111
|
+
REQUIRE(sketch2.get_min_item() == sketch.get_min_item());
|
|
112
|
+
REQUIRE(sketch2.get_max_item() == sketch.get_max_item());
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
TEST_CASE("req_sketch: deserialize multi-level sketch", "[deserialize_hardening]") {
|
|
116
|
+
// REQ sketch only has the bug when num_levels > 1
|
|
117
|
+
// We need to add enough items to trigger multiple levels
|
|
118
|
+
req_sketch<float> sketch(12);
|
|
119
|
+
for (int i = 0; i < 10000; i++) {
|
|
120
|
+
sketch.update(static_cast<float>(i));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
auto bytes = sketch.serialize();
|
|
124
|
+
|
|
125
|
+
// Deserialize - exercises buggy code path when num_levels > 1
|
|
126
|
+
auto sketch2 = req_sketch<float>::deserialize(bytes.data(), bytes.size());
|
|
127
|
+
|
|
128
|
+
REQUIRE(sketch2.get_n() == sketch.get_n());
|
|
129
|
+
REQUIRE(sketch2.get_min_item() == sketch.get_min_item());
|
|
130
|
+
REQUIRE(sketch2.get_max_item() == sketch.get_max_item());
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
TEST_CASE("req_sketch: deserialize from stream", "[deserialize_hardening]") {
|
|
134
|
+
req_sketch<double> sketch(20);
|
|
135
|
+
for (int i = 0; i < 15000; i++) {
|
|
136
|
+
sketch.update(static_cast<double>(i) * 0.1);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
std::stringstream ss;
|
|
140
|
+
sketch.serialize(ss);
|
|
141
|
+
|
|
142
|
+
// Deserialize from stream
|
|
143
|
+
auto sketch2 = req_sketch<double>::deserialize(ss);
|
|
144
|
+
|
|
145
|
+
REQUIRE(sketch2.get_n() == sketch.get_n());
|
|
146
|
+
REQUIRE(sketch2.get_min_item() == sketch.get_min_item());
|
|
147
|
+
REQUIRE(sketch2.get_max_item() == sketch.get_max_item());
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
TEST_CASE("multiple sketch types: stress test", "[deserialize_hardening]") {
|
|
151
|
+
SECTION("quantiles with various sizes") {
|
|
152
|
+
for (int k : {64, 128, 256}) {
|
|
153
|
+
quantiles_sketch<int> sketch(k);
|
|
154
|
+
for (int i = 0; i < 5000; i++) {
|
|
155
|
+
sketch.update(i);
|
|
156
|
+
}
|
|
157
|
+
auto bytes = sketch.serialize();
|
|
158
|
+
auto sketch2 = quantiles_sketch<int>::deserialize(bytes.data(), bytes.size());
|
|
159
|
+
REQUIRE(sketch2.get_n() == sketch.get_n());
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
SECTION("kll with various sizes") {
|
|
164
|
+
for (int k : {100, 200, 400}) {
|
|
165
|
+
kll_sketch<double> sketch(k);
|
|
166
|
+
for (int i = 0; i < 4000; i++) {
|
|
167
|
+
sketch.update(static_cast<double>(i) / 10.0);
|
|
168
|
+
}
|
|
169
|
+
auto bytes = sketch.serialize();
|
|
170
|
+
auto sketch2 = kll_sketch<double>::deserialize(bytes.data(), bytes.size());
|
|
171
|
+
REQUIRE(sketch2.get_n() == sketch.get_n());
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
SECTION("req with various sizes") {
|
|
176
|
+
for (int k : {12, 20}) {
|
|
177
|
+
req_sketch<float> sketch(k);
|
|
178
|
+
for (int i = 0; i < 8000; i++) {
|
|
179
|
+
sketch.update(static_cast<float>(i));
|
|
180
|
+
}
|
|
181
|
+
auto bytes = sketch.serialize();
|
|
182
|
+
auto sketch2 = req_sketch<float>::deserialize(bytes.data(), bytes.size());
|
|
183
|
+
REQUIRE(sketch2.get_n() == sketch.get_n());
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
} // namespace datasketches
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
#define COUNT_MIN_HPP_
|
|
22
22
|
|
|
23
23
|
#include <iterator>
|
|
24
|
+
#include <type_traits>
|
|
25
|
+
#include <vector>
|
|
24
26
|
#include "common_defs.hpp"
|
|
25
27
|
|
|
26
28
|
namespace datasketches {
|
|
@@ -36,6 +38,7 @@ template <typename W,
|
|
|
36
38
|
typename Allocator = std::allocator<W>>
|
|
37
39
|
class count_min_sketch{
|
|
38
40
|
static_assert(std::is_arithmetic<W>::value, "Arithmetic type expected");
|
|
41
|
+
static_assert(!std::is_same<W, bool>::value, "Boolean weight type is not supported");
|
|
39
42
|
public:
|
|
40
43
|
using allocator_type = Allocator;
|
|
41
44
|
using const_iterator = typename std::vector<W, Allocator>::const_iterator;
|
|
@@ -326,6 +329,15 @@ public:
|
|
|
326
329
|
*/
|
|
327
330
|
void serialize(std::ostream& os) const;
|
|
328
331
|
|
|
332
|
+
/**
|
|
333
|
+
* This method serializes the sketch by passing binary fragments to a callback.
|
|
334
|
+
* The callback must be callable as write_bytes(const void* data, size_t size).
|
|
335
|
+
* The data pointer is valid only until the callback returns.
|
|
336
|
+
* @return size in bytes written to the callback
|
|
337
|
+
*/
|
|
338
|
+
template<typename Sink>
|
|
339
|
+
size_t serialize_to(Sink&& sink) const;
|
|
340
|
+
|
|
329
341
|
// This is a convenience alias for users
|
|
330
342
|
// The type returned by the following serialize method
|
|
331
343
|
using vector_bytes = std::vector<uint8_t, typename std::allocator_traits<Allocator>::template rebind_alloc<uint8_t>>;
|
|
@@ -389,12 +401,13 @@ private:
|
|
|
389
401
|
static void check_header_validity(uint8_t preamble_longs, uint8_t serial_version, uint8_t family_id, uint8_t flags_byte);
|
|
390
402
|
|
|
391
403
|
/*
|
|
392
|
-
*
|
|
393
|
-
* @param item pointer to the data item to be inserted into the sketch.
|
|
404
|
+
* Compute the hash locations for an input item
|
|
405
|
+
* @param item pointer to the data item to be inserted into or queried from the sketch.
|
|
394
406
|
* @param size of the data in bytes
|
|
395
|
-
* @
|
|
407
|
+
* @param callback function to invoke for each sketch array location
|
|
396
408
|
*/
|
|
397
|
-
|
|
409
|
+
template<typename F>
|
|
410
|
+
void foreach_hash_location(const void* item, size_t size, F callback) const;
|
|
398
411
|
|
|
399
412
|
};
|
|
400
413
|
|