use std::str::FromStr;
use nalgebra::DMatrix;
use num_traits::ToPrimitive;
use strafe_testing::{
r::{RGenerator, RString, RTester},
r_assert_relative_equal,
};
use crate::regression::glm::{family::core::Family, link::core::Link};
pub fn family_option_string(family_option: &str) -> String {
match family_option {
"Binomial" => "binomial()".to_string(),
"Gamma" => "Gamma()".to_string(),
"Gaussian" => "gaussian()".to_string(),
"InverseGaussian" => "inverse.gaussian()".to_string(),
"Poisson" => "poisson()".to_string(),
"Quasi(Constant)" => "quasi(variance = 'constant')".to_string(),
"Quasi(Mu)" => "quasi(variance = 'mu')".to_string(),
"Quasi(MuSqrd)" => "quasi(variance = 'mu^2')".to_string(),
"Quasi(MuCubed)" => "quasi(variance = 'mu^3')".to_string(),
"Quasi(MuOneMinusMu)" => "quasi(variance = 'mu(1-mu)')".to_string(),
"QuasiBinomial" => "quasibinomial()".to_string(),
"QuasiPoisson" => "quasipoisson()".to_string(),
_ => unimplemented!(),
}
}
pub fn family_test_inner<L: Link, F: Family<L>>(
seed: u16,
num_rows: f64,
family: F,
family_string: &str,
) {
let num_rows = num_rows.to_usize().unwrap();
let ys = RTester::new()
.set_seed(seed)
.set_display(&RString::from_string(format!("runif({}, 0, 1)", num_rows,)))
.run()
.expect("R error")
.as_f64_vec()
.expect("R array error");
let mut weights = RGenerator::new()
.set_seed(seed + 1)
.generate_uniform_matrix(num_rows, 1, (0, 10));
let mut y = DMatrix::from_iterator(ys.len(), 1, ys.iter().copied());
let library = RString::from_library_name("stats");
let r_n = RTester::new()
.add_library(&library)
.set_script(&RString::from_string(format!(
"y={0};etastart={0};weights={1};nobs={2};eval({3}$initialize);",
RString::from_f64_slice(&ys),
RString::from_f64_matrix(&weights),
RString::from_f64(ys.len()),
RString::from_str(&family_string).unwrap(),
)))
.set_display(&RString::from_str("n").unwrap())
.run()
.expect("R error")
.as_f64_vec()
.expect("Could not read vector");
let r_mu_start = RTester::new()
.add_library(&library)
.set_script(&RString::from_string(format!(
"y={0};etastart={0};weights={1};nobs={2};eval({3}$initialize);",
RString::from_f64_slice(&ys),
RString::from_f64_matrix(&weights),
RString::from_f64(ys.len()),
RString::from_str(&family_string).unwrap(),
)))
.set_display(&RString::from_str("mustart").unwrap())
.run()
.expect("R error")
.as_f64_matrix()
.expect("Could not read matrix");
let (rust_n, rust_mu_start) = family.initialize(&mut y, &mut weights);
for (&r_val, &rust_val) in r_n.iter().zip(rust_n.iter()) {
r_assert_relative_equal!(r_val, rust_val, 1e-4);
}
for (&r_val, &rust_val) in r_mu_start.iter().zip(rust_mu_start.iter()) {
r_assert_relative_equal!(r_val, rust_val, 1e-4);
}
let r_variance = RTester::new()
.add_library(&library)
.set_script(&RString::from_string(format!(
"mu={};fam={};",
RString::from_f64_matrix(&rust_mu_start),
RString::from_str(&family_string).unwrap(),
)))
.set_display(&RString::from_str("fam$variance(mu)").unwrap())
.run()
.expect("R error")
.as_f64_matrix()
.expect("Could not read matrix");
let rust_variance = family.variance(&rust_mu_start);
for (&r_val, &rust_val) in r_variance.iter().zip(rust_variance.iter()) {
r_assert_relative_equal!(r_val, rust_val, 1e-4);
}
let r_valid_mu = RTester::new()
.add_library(&library)
.set_script(&RString::from_string(format!(
"mu={};fam={};",
RString::from_f64_matrix(&rust_mu_start),
RString::from_str(&family_string).unwrap(),
)))
.set_display(&RString::from_str("fam$validmu(mu)").unwrap())
.run()
.expect("R error")
.as_bool()
.expect("Could not read bool");
let rust_valid_mu = family.valid_mu(&rust_mu_start);
assert_eq!(r_valid_mu, rust_valid_mu);
let r_residual_deviance = RTester::new()
.add_library(&library)
.set_script(&RString::from_string(format!(
"y={};mu={};w={};fam={};",
RString::from_f64_slice(&ys),
RString::from_f64_matrix(&rust_mu_start),
RString::from_f64_matrix(&weights),
RString::from_str(&family_string).unwrap(),
)))
.set_display(&RString::from_str("fam$dev.resids(y,mu,w)").unwrap())
.run()
.expect("R error")
.as_f64_vec()
.expect("Could not read vec");
let rust_residual_deviance = family.residual_deviance(&y, &rust_mu_start, &weights);
for (&r_val, &rust_val) in r_residual_deviance
.iter()
.zip(rust_residual_deviance.iter())
{
r_assert_relative_equal!(r_val, rust_val, 1e-4);
}
let r_aic = RTester::new()
.add_library(&library)
.set_script(&RString::from_string(format!(
"y={};n={};mu={};w={};dev={};fam={};",
RString::from_f64_slice(&ys),
RString::from_f64_matrix(&rust_n),
RString::from_f64_matrix(&rust_mu_start),
RString::from_f64_matrix(&weights),
RString::from_f64(rust_residual_deviance.sum()),
RString::from_str(&family_string).unwrap(),
)))
.set_display(&RString::from_str("fam$aic(y,n,mu,w,dev)").unwrap())
.run()
.expect("R error")
.as_f64()
.expect("Could not read float");
let rust_aic = family.aic(
y.as_slice(),
rust_n.as_slice(),
rust_mu_start.as_slice(),
weights.as_slice(),
rust_residual_deviance.sum(),
);
r_assert_relative_equal!(r_aic, rust_aic, 1e-4);
}