Skip to content

Commit a935a2c

Browse files
giacomocavalierilpil
authored andcommitted
fix sampling algorithm
1 parent c98404b commit a935a2c

File tree

1 file changed

+29
-31
lines changed

1 file changed

+29
-31
lines changed

src/gleam/list.gleam

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2329,12 +2329,40 @@ pub fn sample(from list: List(a), up_to n: Int) -> List(a) {
23292329
True -> []
23302330
False -> {
23312331
let w = float.exponential(log_random() /. int.to_float(n))
2332-
sample_loop(list, reservoir, n, n, w) |> dict.values
2332+
dict.values(sample_loop(list, reservoir, n, w))
23332333
}
23342334
}
23352335
}
23362336
}
23372337

2338+
fn sample_loop(
2339+
list: List(a),
2340+
reservoir: Dict(Int, a),
2341+
k: Int,
2342+
w: Float,
2343+
) -> Dict(Int, a) {
2344+
let skip = {
2345+
let assert Ok(log) = float.logarithm(1.0 -. w)
2346+
float.round(float.floor(log_random() /. log))
2347+
}
2348+
2349+
case drop(list, skip) {
2350+
[] -> reservoir
2351+
[first, ..rest] -> {
2352+
let reservoir = dict.insert(reservoir, int.random(k), first)
2353+
let w = w *. float.exponential(log_random() /. int.to_float(k))
2354+
sample_loop(rest, reservoir, k, w)
2355+
}
2356+
}
2357+
}
2358+
2359+
const min_positive = 2.2250738585072014e-308
2360+
2361+
fn log_random() -> Float {
2362+
let assert Ok(random) = float.logarithm(float.random() +. min_positive)
2363+
random
2364+
}
2365+
23382366
/// Builds the initial reservoir used by Algorithm L.
23392367
/// This is a dictionary with keys ranging from `0` up to `n - 1` where each
23402368
/// value is the corresponding element at that position in `list`.
@@ -2367,33 +2395,3 @@ fn build_reservoir_loop(
23672395
}
23682396
}
23692397
}
2370-
2371-
fn sample_loop(
2372-
list: List(a),
2373-
reservoir: Dict(Int, a),
2374-
k: Int,
2375-
index: Int,
2376-
w: Float,
2377-
) -> Dict(Int, a) {
2378-
let skip = {
2379-
let assert Ok(log_result) = float.logarithm(1.0 -. w)
2380-
log_random() /. log_result |> float.floor |> float.round
2381-
}
2382-
2383-
let index = index + skip + 1
2384-
2385-
case drop(list, skip) {
2386-
[] -> reservoir
2387-
[first, ..rest] -> {
2388-
let reservoir = dict.insert(reservoir, int.random(k), first)
2389-
let w = w *. float.exponential(log_random() /. int.to_float(k))
2390-
sample_loop(rest, reservoir, k, index, w)
2391-
}
2392-
}
2393-
}
2394-
2395-
fn log_random() -> Float {
2396-
let min_positive = 2.2250738585072014e-308
2397-
let assert Ok(random) = float.logarithm(float.random() +. min_positive)
2398-
random
2399-
}

0 commit comments

Comments
 (0)