use pharmsol::data::error_model::AssayErrorModel;
use pharmsol::*;
#[test]
fn test_particle_filter_likelihood() {
let subject = data::Subject::builder("id1")
.bolus(0.0, 20.0, "dose")
.observation(0.2, 16.6434, "cp")
.observation(0.4, 14.3233, "cp")
.observation(0.6, 9.8468, "cp")
.observation(0.8, 9.4177, "cp")
.observation(1.0, 7.5170, "cp")
.build();
let sde = equation::SDE::new(
|x, p, _t, dx, _rateiv, _cov| {
dx[0] = -x[0] * x[1]; dx[1] = -x[1] + p[0]; },
|_p, d| {
d[0] = 1.0;
d[1] = 0.01;
},
|_p, _t, _cov| lag! {},
|_p, _t, _cov| fa! {},
|_p, _t, _cov, x| x[1] = 1.0,
|x, _p, _t, _cov, y| {
y[0] = x[0];
},
10000,
)
.with_nstates(2)
.with_ndrugs(1)
.with_nout(1);
let sde = sde
.with_metadata(
equation::metadata::new("particle_filter_test")
.kind(equation::ModelKind::Sde)
.parameters(["ke0"])
.states(["central", "ke_latent"])
.outputs(["cp"])
.route(
equation::Route::bolus("dose")
.to_state("central")
.inject_input_to_destination(),
)
.particles(10000),
)
.expect("particle filter metadata should validate");
let ems = AssayErrorModels::default()
.add(
0,
AssayErrorModel::additive(ErrorPoly::new(0.5, 0.0, 0.0, 0.0), 0.0),
)
.unwrap();
const NUM_RUNS: usize = 10;
let mut likelihoods = Vec::with_capacity(NUM_RUNS);
for i in 0..NUM_RUNS {
let parameters = Parameters::with_model(&sde, [("ke0", 1.0)])
.expect("particle filter parameters should validate");
let ll = sde
.estimate_log_likelihood(&subject, ¶meters, &ems)
.unwrap()
.exp();
println!("Run {}: likelihood = {}", i + 1, ll);
likelihoods.push(ll);
}
let mean: f64 = likelihoods.iter().sum::<f64>() / NUM_RUNS as f64;
let variance: f64 =
likelihoods.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / NUM_RUNS as f64;
let std_dev = variance.sqrt();
println!("\n=== Particle Filter Likelihood Statistics ===");
println!("Number of runs: {}", NUM_RUNS);
println!("Likelihoods: {:?}", likelihoods);
println!("Mean likelihood: {}", mean);
println!("Std deviation: {}", std_dev);
println!(
"Min: {}",
likelihoods.iter().cloned().fold(f64::INFINITY, f64::min)
);
println!(
"Max: {}",
likelihoods
.iter()
.cloned()
.fold(f64::NEG_INFINITY, f64::max)
);
assert!(mean.is_finite(), "Mean likelihood should be finite");
}