mod matrix;
mod reml;
use std::io::Write;
use std::path::Path;
use rsomics_common::{Result, RsomicsError};
pub use matrix::{read_design, read_expr};
pub struct Options<'a> {
pub expr: &'a Path,
pub design: &'a Path,
pub prior_n: f64,
pub maxiter: usize,
pub tol: f64,
}
pub struct Results {
pub samples: Vec<String>,
pub weights: Vec<f64>,
pub n_genes: usize,
pub iters: usize,
pub converged: bool,
}
pub fn run(opts: &Options) -> Result<Results> {
let expr = read_expr(opts.expr)?;
let design = read_design(opts.design)?;
if design.x.len() != expr.samples.len() {
return Err(RsomicsError::InvalidInput(format!(
"design has {} rows, expression has {} samples",
design.x.len(),
expr.samples.len()
)));
}
let fit = reml::array_weights(&expr.y, &design.x, opts.prior_n, opts.maxiter, opts.tol)?;
Ok(Results {
samples: expr.samples,
weights: fit.weights,
n_genes: expr.y.len(),
iters: fit.iters,
converged: fit.converged,
})
}
pub fn write_weights(res: &Results, out: &mut dyn Write) -> Result<()> {
let mut buf = ryu::Buffer::new();
writeln!(out, "sample\tweight").map_err(RsomicsError::Io)?;
for (s, w) in res.samples.iter().zip(&res.weights) {
writeln!(out, "{s}\t{}", buf.format(*w)).map_err(RsomicsError::Io)?;
}
Ok(())
}