use blr_active::active_learning::variance::{
posterior_std, posterior_std_grid, posterior_variance,
};
#[test]
fn test_variance_identity_cov_e1() {
let d = 4usize;
let sigma_cov: Vec<f64> = (0..d * d)
.map(|k| if k % (d + 1) == 0 { 1.0 } else { 0.0 })
.collect();
let phi = vec![1.0, 0.0, 0.0, 0.0];
let var = posterior_variance(1.0, &sigma_cov, d, &phi, 1);
assert!((var[0] - 2.0).abs() < 1e-10, "expected 2.0, got {}", var[0]);
}
#[test]
fn test_variance_scaled_identity_two_points() {
let d = 2usize;
let sigma_cov = vec![2.0, 0.0, 0.0, 2.0];
let phi_test = vec![1.0, 1.0, 0.0, 1.0]; let var = posterior_variance(2.0, &sigma_cov, d, &phi_test, 2);
assert!((var[0] - 4.5).abs() < 1e-10, "expected 4.5, got {}", var[0]);
assert!((var[1] - 2.5).abs() < 1e-10, "expected 2.5, got {}", var[1]);
}
#[test]
fn test_std_is_sqrt_of_variance() {
let d = 3usize;
let sigma_cov = vec![0.5, 0.1, 0.0, 0.1, 0.3, 0.0, 0.0, 0.0, 0.2];
let phi = vec![1.0, -0.5, 0.3];
let var = posterior_variance(1.5, &sigma_cov, d, &phi, 1);
let std = posterior_std(1.5, &sigma_cov, d, &phi, 1);
assert!(
(std[0] - var[0].sqrt()).abs() < 1e-12,
"std should be sqrt(var)"
);
}
#[test]
fn test_grid_length_matches_resolution() {
let d = 2usize;
let sigma_cov = vec![1.0, 0.0, 0.0, 1.0];
let feature_fn = |x: f64| vec![1.0, x];
let (grid, stds) = posterior_std_grid(1.0, &sigma_cov, d, 0.0, 10.0, 100, &feature_fn);
assert_eq!(grid.len(), 100);
assert_eq!(stds.len(), 100);
}
#[test]
fn test_grid_all_finite_nonneg() {
let d = 3usize;
let sigma_cov = vec![0.3, 0.0, 0.0, 0.0, 0.5, 0.1, 0.0, 0.1, 0.2];
let feature_fn = |x: f64| vec![1.0, x, x * x];
let (_, stds) = posterior_std_grid(2.0, &sigma_cov, d, -10.0, 10.0, 200, &feature_fn);
for (i, s) in stds.iter().enumerate() {
assert!(s.is_finite(), "grid[{i}] std is not finite: {s}");
assert!(*s >= 0.0, "grid[{i}] std is negative: {s}");
}
}
#[test]
fn test_performance_100_points_fast() {
let d = 8usize;
let sigma_cov: Vec<f64> = (0..d * d)
.map(|k| if k % (d + 1) == 0 { 0.1 } else { 0.0 })
.collect();
let feature_fn = |x: f64| {
vec![
1.0,
x,
x * x,
x.sin(),
x.cos(),
x.exp().min(1e6),
x.ln().abs(),
x * x * x,
]
};
let start = std::time::Instant::now();
let (_, _) = posterior_std_grid(1.0, &sigma_cov, d, 0.0, 1.0, 100, &feature_fn);
let elapsed = start.elapsed();
assert!(
elapsed.as_millis() < 100,
"100-point grid took {:?}",
elapsed
);
}
#[test]
fn test_degenerate_single_point_no_panic() {
let d = 2usize;
let sigma_cov = vec![1.0, 0.0, 0.0, 1.0];
let feature_fn = |_: f64| vec![0.0, 0.0];
let (grid, stds) = posterior_std_grid(1.0, &sigma_cov, d, 5.0, 5.0, 2, &feature_fn);
assert!(grid.len() >= 2);
for s in &stds {
assert!(s.is_finite());
}
}