laddu_extensions/lib.rs
1//! # laddu-extensions
2//!
3//! This is an internal crate used by `laddu`.
4#![warn(clippy::perf, clippy::style, missing_docs)]
5
6/// Experimental extensions to the `laddu` ecosystem
7///
8/// <div class="warning">
9///
10/// This module contains experimental code which may be untested or unreliable. Use at your own
11/// risk! The features contained here may eventually be moved into the standard crate modules.
12///
13/// </div>
14pub mod experimental;
15
16/// A module containing the `laddu` interface with the [`ganesh`] library
17pub mod ganesh_ext;
18
19/// Extended maximum likelihood cost functions with support for additive terms
20pub mod likelihoods;
21
22// pub use ganesh_ext::{MCMCOptions, MinimizerOptions};
23pub use likelihoods::{
24 LikelihoodEvaluator, LikelihoodExpression, LikelihoodID, LikelihoodManager, LikelihoodScalar,
25 NLL,
26};
27
28use fastrand::Rng;
29use rapidhash::{HashSetExt, RapidHashSet};
30
31/// An extension to [`Rng`] which allows for sampling from a subset of the integers `[0..n)`
32/// without replacement.
33pub trait RngSubsetExtension {
34 /// Draw a random subset of `m` indices between `0` and `n`.
35 fn subset(&mut self, m: usize, n: usize) -> Vec<usize>;
36}
37
38// Nice write-up here:
39// https://www.nowherenearithaca.com/2013/05/robert-floyds-tiny-and-beautiful.html
40fn floyd_sample(m: usize, n: usize, rng: &mut Rng) -> RapidHashSet<usize> {
41 let mut set = RapidHashSet::with_capacity(m * 2);
42 for j in (n - m)..n {
43 let t = rng.usize(..=j);
44 if !set.insert(t) {
45 set.insert(j);
46 }
47 }
48 set
49}
50
51impl RngSubsetExtension for Rng {
52 fn subset(&mut self, m: usize, n: usize) -> Vec<usize> {
53 assert!(m < n);
54 if m > n / 2 {
55 let k = n - m;
56 let exclude = floyd_sample(k, n, self);
57 let mut res = Vec::with_capacity(m);
58 for i in 0..n {
59 if !exclude.contains(&i) {
60 res.push(i);
61 }
62 }
63 return res;
64 }
65 floyd_sample(m, n, self).into_iter().collect()
66 }
67}