use crate::limma::lm_fit::LmFitResult;
use crate::prelude::*;
#[derive(Clone, Debug)]
pub struct MArrayLm {
pub n_genes: usize,
pub n_samples: usize,
pub n_coef: usize,
pub coefficients: Vec<f64>,
pub stdev_unscaled: Vec<f64>,
pub sigma: Vec<f64>,
pub df_residual: Vec<f64>,
pub cov_coefficients: Vec<f64>,
pub pivot: Vec<usize>,
pub rank: usize,
pub design: Vec<f64>,
pub amean: Option<Vec<f64>>,
pub contrasts: Option<Vec<f64>>,
pub df_prior: Option<Vec<f64>>,
pub s2_prior: Option<Vec<f64>>,
pub var_prior: Option<Vec<f64>>,
pub proportion: Option<f64>,
pub s2_post: Option<Vec<f64>>,
pub t: Option<Vec<f64>>,
pub df_total: Option<Vec<f64>>,
pub p_value: Option<Vec<f64>>,
pub lods: Option<Vec<f64>>,
pub f_stat: Option<Vec<f64>>,
pub f_p_value: Option<Vec<f64>>,
}
impl MArrayLm {
pub fn from_lm_fit(
fit: LmFitResult,
design: &[f64],
n_coef: usize,
n_samples: usize,
amean: Option<Vec<f64>>,
) -> Result<Self, EdgeErrors> {
if n_coef == 0 {
return Err(EdgeErrors::MustBePositive("n_coef".to_string()));
}
let n_genes = fit.sigma.len();
if fit.coefficients.len() != n_genes * n_coef {
return Err(EdgeErrors::LengthMismatch {
name: "coefficients",
expected: n_genes * n_coef,
got: fit.coefficients.len(),
});
}
if design.len() != n_samples * n_coef {
return Err(EdgeErrors::LengthMismatch {
name: "design",
expected: n_samples * n_coef,
got: design.len(),
});
}
if let Some(a) = amean.as_ref()
&& a.len() != n_genes
{
return Err(EdgeErrors::LengthMismatch {
name: "amean",
expected: n_genes,
got: a.len(),
});
}
Ok(Self {
n_genes,
n_samples,
n_coef,
coefficients: fit.coefficients,
stdev_unscaled: fit.stdev_unscaled,
sigma: fit.sigma,
df_residual: fit.df_residual,
cov_coefficients: fit.cov_coefficients,
pivot: fit.pivot,
rank: fit.rank,
design: design.to_vec(),
amean,
contrasts: None,
df_prior: None,
s2_prior: None,
var_prior: None,
proportion: None,
s2_post: None,
t: None,
df_total: None,
p_value: None,
lods: None,
f_stat: None,
f_p_value: None,
})
}
pub(crate) fn clear_tests(&mut self) {
self.df_prior = None;
self.s2_prior = None;
self.var_prior = None;
self.proportion = None;
self.s2_post = None;
self.t = None;
self.df_total = None;
self.p_value = None;
self.lods = None;
self.f_stat = None;
self.f_p_value = None;
}
}
#[cfg(test)]
mod tests {
use super::*;
fn fit(n_genes: usize, n_coef: usize) -> LmFitResult {
LmFitResult {
coefficients: vec![0.0; n_genes * n_coef],
stdev_unscaled: vec![1.0; n_genes * n_coef],
sigma: vec![1.0; n_genes],
df_residual: vec![3.0; n_genes],
fitted: vec![0.0; n_genes * 5],
cov_coefficients: vec![1.0; n_coef * n_coef],
pivot: (0..n_coef).collect(),
rank: n_coef,
}
}
#[test]
fn test_from_lm_fit_carries_the_shape() {
let m = MArrayLm::from_lm_fit(fit(4, 2), &[1.0; 10], 2, 5, None).unwrap();
assert_eq!(m.n_genes, 4);
assert_eq!(m.n_coef, 2);
assert!(m.t.is_none());
}
#[test]
fn test_from_lm_fit_rejects_a_bad_amean() {
let e = MArrayLm::from_lm_fit(fit(4, 2), &[1.0; 10], 2, 5, Some(vec![0.0; 3]));
assert!(e.is_err());
}
#[test]
fn test_from_lm_fit_rejects_a_bad_design() {
assert!(MArrayLm::from_lm_fit(fit(4, 2), &[1.0; 8], 2, 5, None).is_err());
}
#[test]
fn test_clear_tests_empties_every_ebayes_field() {
let mut m = MArrayLm::from_lm_fit(fit(4, 2), &[1.0; 10], 2, 5, None).unwrap();
m.t = Some(vec![1.0; 8]);
m.f_stat = Some(vec![1.0; 4]);
m.clear_tests();
assert!(m.t.is_none());
assert!(m.f_stat.is_none());
}
}