Beta's `set_alpha` and `set_beta` violate invariants
Beta is defined as
pub struct Beta {
alpha: f64,
beta: f64,
#[cfg_attr(feature = "serde1", serde(skip))]
/// Cached ln(Beta(a, b))
ln_beta_ab: OnceLock<f64>,
}
The OnceLock means the ln_beta_ab field can be written once, after which it's immutable. This is great, except that there are also set_alpha and set_beta methods. These can change the parameters, but are left with no way to update the cached ln_beta_ab.
Say we do
// Start with a Beta
let a1 = rng.gen::<f64>().inv();
let b1 = rng.gen::<f64>().inv();
let mut beta1 = Beta::new(a1, b1).unwrap();
// Any value in the unit interval
let x: f64 = rng.gen();
// Evaluate the pdf to force computation of `ln_beta_ab`
let _ = beta1.pdf(&x);
// Next we'll `set_alpha` and `set_beta` to these, and compare this with a fresh Beta
let a2 = rng.gen::<f64>().inv();
let b2 = rng.gen::<f64>().inv();
// Setting the new values
if let Ok(_) = beta1.set_alpha(a2) {};
if let Ok(_) = beta1.set_beta(b2) {};
// ... and here's the fresh version
let beta2 = Beta::new(a2, b2).unwrap();
// These results should match
println!("beta1 pdf at x = {:?} is {:?}", x, beta1.pdf(&x));
println!("beta2 pdf at x = {:?} is {:?}", x, beta2.pdf(&x));
Running this gives results like
beta1 pdf at x = 0.186023700091557 is 6.787374697139961
beta2 pdf at x = 0.186023700091557 is 1.624002035952952
We'd expect these results to match, but they don't.
To fix this we need to have ln_beta_ab under... maybe a RwLock? Whatever we do, we need to be sure it's updated when calling set_alpha or set_beta.