refactor(gaussian): switch to natural-parameter storage (pi, tau)
Mul and Div become two f64 adds/subs with no sqrt in the hot path.
mu() and sigma() are computed on demand from stored pi/tau.
Key implementation notes:
- exclude() returns N00 when var <= 0 to avoid inf/inf = NaN when
two Gaussians have the same precision (ULP-level round-trip error
from the pi→sigma accessor).
- Mul<f64> by 0.0 returns N00 (point mass at 0), matching old behavior.
- from_ms(0, 0) == N00 {pi:inf, tau:0}; from_ms(0, inf) == N_INF {pi:0, tau:0}.
Golden values in test_1vs1vs1_draw updated: nat-param arithmetic
rounds mu to 25.0 (was 24.999999) and shifts sigma by ~3e-7.
Both differences are bounded and validated against the original Python
reference values.
Part of T0 engine redesign.
This commit is contained in:
14
src/lib.rs
14
src/lib.rs
@@ -203,9 +203,9 @@ fn trunc(mu: f64, sigma: f64, margin: f64, tie: bool) -> (f64, f64) {
|
||||
}
|
||||
|
||||
pub(crate) fn approx(n: Gaussian, margin: f64, tie: bool) -> Gaussian {
|
||||
let (mu, sigma) = trunc(n.mu, n.sigma, margin, tie);
|
||||
let (mu, sigma) = trunc(n.mu(), n.sigma(), margin, tie);
|
||||
|
||||
Gaussian { mu, sigma }
|
||||
Gaussian::from_ms(mu, sigma)
|
||||
}
|
||||
|
||||
pub(crate) fn tuple_max(v1: (f64, f64), v2: (f64, f64)) -> (f64, f64) {
|
||||
@@ -245,10 +245,10 @@ pub(crate) fn sort_time(xs: &[i64], reverse: bool) -> Vec<usize> {
|
||||
|
||||
pub(crate) fn evidence(d: &[DiffMessage], margin: &[f64], tie: &[bool], e: usize) -> f64 {
|
||||
if tie[e] {
|
||||
cdf(margin[e], d[e].prior.mu, d[e].prior.sigma)
|
||||
- cdf(-margin[e], d[e].prior.mu, d[e].prior.sigma)
|
||||
cdf(margin[e], d[e].prior.mu(), d[e].prior.sigma())
|
||||
- cdf(-margin[e], d[e].prior.mu(), d[e].prior.sigma())
|
||||
} else {
|
||||
1.0 - cdf(margin[e], d[e].prior.mu, d[e].prior.sigma)
|
||||
1.0 - cdf(margin[e], d[e].prior.mu(), d[e].prior.sigma())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,13 +266,13 @@ pub fn quality(rating_groups: &[&[Gaussian]], beta: f64) -> f64 {
|
||||
let mut mean_matrix = Matrix::new(length, 1);
|
||||
|
||||
for (i, rating) in flatten_ratings.iter().enumerate() {
|
||||
mean_matrix[(i, 0)] = rating.mu;
|
||||
mean_matrix[(i, 0)] = rating.mu();
|
||||
}
|
||||
|
||||
let mut variance_matrix = Matrix::new(length, length);
|
||||
|
||||
for (i, rating) in flatten_ratings.iter().enumerate() {
|
||||
variance_matrix[(i, i)] = rating.sigma.powi(2);
|
||||
variance_matrix[(i, i)] = rating.sigma().powi(2);
|
||||
}
|
||||
|
||||
let mut rotated_a_matrix = Matrix::new(rating_groups.len() - 1, length);
|
||||
|
||||
Reference in New Issue
Block a user