pub mod hlm;
pub mod params;
pub mod pmd;
pub mod refine;
use faer::MatRef;
use crate::prelude::*;
pub use hlm::{DialogueStep2Result, GeneAssociation};
pub use params::{Averaging, DialogueParams, HlmParams, PmdParams, RefineParams, parse_averaging};
pub use pmd::{DialogueStep1Result, ProgrammeSignature};
pub use refine::{DialogueResult, GeneVerdict};
use pmd::CellTypeView;
#[allow(clippy::too_many_arguments)]
pub fn dialogue_run<S: SingleCellReading>(
reader: &S,
cell_type_indices: &[Vec<usize>],
features: &[MatRef<f64>],
sample_ids: &[usize],
cell_quality: &[f64],
genes: &[usize],
params: &DialogueParams,
verbose: usize,
) -> Result<DialogueResult, BixverseErrors> {
let n_types = cell_type_indices.len();
params.validate(n_types)?;
if features.len() != n_types {
return Err(BixverseErrors::InvalidArgument(format!(
"got {n_types} cell types but {} feature matrices.",
features.len()
)));
}
for (i, (cells, feature)) in cell_type_indices.iter().zip(features.iter()).enumerate() {
if feature.nrows() != cells.len() {
return Err(BixverseErrors::ShapeMismatch {
expected: (cells.len(), feature.ncols()),
got: (feature.nrows(), feature.ncols()),
});
}
if feature.ncols() < 2 {
return Err(BixverseErrors::InvalidArgument(format!(
"cell type {i} has {} feature columns; DIALOGUE needs at least 2.",
feature.ncols()
)));
}
}
let total_cells = reader.get_header().total_cells;
for cells in cell_type_indices.iter() {
if let Some(&bad) = cells.iter().find(|&&c| c >= total_cells) {
return Err(BixverseErrors::InvalidArgument(format!(
"cell index {bad} is outside the store's {total_cells} cells."
)));
}
}
let views: Vec<CellTypeView> = cell_type_indices
.iter()
.map(|cells| CellTypeView::new(cells, sample_ids, cell_quality))
.collect::<Result<_, _>>()?;
let step1 = pmd::dialogue_step1_run(reader, &views, features, genes, params, verbose)?;
let step2 = hlm::run_step2(reader, &views, &step1, params, verbose)?;
refine::run_step3(reader, &views, &step1, &step2, params, verbose)
}