1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
//! `HyperLogLog` distinct-count (cardinality) estimation.
//!
//! `HyperLogLog` (Flajolet, Fusy, Gandouet & Meunier, 2007) estimates the number of
//! **distinct** elements in a stream using a fixed, tiny amount of memory — `m`
//! one-byte registers — rather than the `O(distinct)` memory an exact `HashSet`
//! count needs. Each element is hashed to a 64-bit word; the leading `p` bits pick
//! one of `m = 2^p` registers, and the register keeps the maximum, over all
//! elements routed to it, of `1 + (leading zeros of the remaining bits)`. Many
//! distinct elements push some register's run of leading zeros high, and the
//! harmonic mean of `2^register` across the registers estimates the cardinality.
//!
//! The estimator implemented here is the original 2007 form with its three regimes:
//!
//! * the **raw** estimate `E = α_m · m² / Σ_j 2^(−register_j)`;
//! * a **small-range** correction — when `E ≤ 2.5·m` and some registers are still
//! zero, linear counting `m · ln(m / zeros)` is more accurate;
//! * a **large-range** correction near the 32-bit hash ceiling. This crate hashes
//! to a full 64-bit word, so that ceiling is astronomically far away and the
//! correction never fires in practice; it is implemented for completeness and
//! documented as inert at 64-bit width.
//!
//! ## Accuracy
//!
//! `HyperLogLog` is an *approximate* counter: its relative standard error is
//! `≈ 1.04 / √m`, so precision `p` trades memory (`m = 2^p` bytes) for accuracy.
//! At `p = 14` (16 KiB) the standard error is about `0.81 %`. There is **no**
//! canonical library bit-match to assert against — the equivalence suite instead
//! pins the estimate against the **exact** distinct count (a ground truth computed
//! with a `HashSet`) and checks it lands inside a small multiple of HLL's
//! theoretical standard error.
//!
//! ## Determinism
//!
//! For a given precision and input multiset the estimate is fully deterministic:
//! the hash is a fixed bijective finalizer, register updates are
//! order-independent maxima, and the estimator is a pure function of the registers.
//!
//! This base block backs the `CardinalityEstimation` computational method.
use estimate_from_registers;
use hash64;
/// Number of bits in the hash word the register index and run length are read from.
const HASH_BITS: u32 = 64;
/// Smallest supported `HyperLogLog` precision (register-index bit width).
///
/// Below `p = 4` the bias-correction constant `α_m` and the small-range regime are
/// not well defined, so the original paper treats `m = 16` as the floor.
const MIN_PRECISION: u8 = 4;
/// Largest supported `HyperLogLog` precision.
///
/// `p = 18` is `m = 262_144` registers (256 KiB); beyond this the memory cost
/// outweighs the accuracy gain for this crate's use, so it is the supported ceiling.
const MAX_PRECISION: u8 = 18;
/// Errors that prevent constructing or updating a `HyperLogLog` estimator.
///
/// Returned (never panicked) so callers stay clear of the crate's `unwrap`/`panic`
/// lint gate and can surface a clean diagnostic.
/// A `HyperLogLog` distinct-count estimator over `m = 2^precision` byte registers.
///
/// Construct with [`HyperLogLog::new`], feed elements with [`HyperLogLog::add`]
/// (or build directly with [`HyperLogLog::from_u64_iter`]), then read the estimated
/// cardinality with [`HyperLogLog::estimate`]. The struct holds only the precision
/// and the register array, so it is cheap to clone and fully deterministic.
/// Computes the `HyperLogLog` register rank `1 + leading_zeros` for a hash tail.
///
/// `tail` is the hash with its `p` index bits already shifted out to the left, so
/// its own leading zeros count the run of zeros in the original `64 - p` tail bits.
/// When `tail` is entirely zero (`leading_zeros == 64`) the run spans the whole
/// `64 - p`-bit tail, giving the maximal rank `64 - p + 1`; the `min` clamps to that
/// so a register never exceeds the representable maximum.
///
/// # Arguments
///
/// * `tail` — the hash left-shifted by `p` (index bits removed).
/// * `p` — the precision; the tail carries `64 - p` meaningful bits.
///
/// # Returns
///
/// The register rank, in `1..=(64 - p + 1)`, as a `u8` (always `< 64`).