feat: add col_weights API and refactor obikstats to use Algorithm trait

Added a `col_weights` method to index layers for computing per-genome column sums or presence k-mer counts. Refactored `obikstats` to implement the `Algorithm` trait with a two-phase `new`/`run` model, replacing manual layer resolution with `IndexCache` for eager file I/O. Simplified per-genome counting logic and updated public exports and dependencies accordingly.
This commit is contained in:
Eric Coissac
2026-08-22 17:28:51 +02:00
parent fba9c65b1a
commit 23812d1af8
6 changed files with 137 additions and 109 deletions
+10
View File
@@ -217,6 +217,16 @@ impl KmerLayer {
}
}
/// Per-genome column weights — count sum or presence k-mer count,
/// depending on content (see `obicompactvec::ColumnWeights`).
pub fn col_weights(&self) -> ndarray::Array1<u64> {
match self {
KmerLayer::Count { layer, .. } => layer.col_weights(),
KmerLayer::Presence { layer, .. } => layer.col_weights(),
KmerLayer::Empty { .. } => panic!("Layer::col_weights() called on an Empty layer"),
}
}
/// Batch, genome-major "carries" for a set of `slots` — `out[g][i]` =
/// whether genome `g` (0..`out.len()`) carries `slots[i]`. `out` must
/// have one entry per genome column, each resized to `slots.len()`.
+14 -1
View File
@@ -364,6 +364,12 @@ impl TypedLayer<PersistentCompactIntMatrix> {
pub fn fill_sub_matrix(&self, slots: &[usize], out: &mut [Vec<u32>]) {
self.data.fill_sub_matrix(slots, out)
}
/// Per-genome column weights — for counts, the sum of values in each
/// column (see `obicompactvec::ColumnWeights::col_weights`).
pub fn col_weights(&self) -> ndarray::Array1<u64> {
obicompactvec::ColumnWeights::col_weights(&self.data)
}
}
// ── Mode 3 — presence/absence matrix ─────────────────────────────────────────
@@ -379,7 +385,7 @@ impl TypedLayer<PersistentCompactIntMatrix> {
// below: sparse matrices aren't built column-by-column, they're built
// row-by-row from an already-built dense layer
// (`PersistentSparseBitMatrixBuilder::build_from_dense`).
impl<D: LayerData<Item = Box<[bool]>> + BinaryMatrix> TypedLayer<D> {
impl<D: LayerData<Item = Box<[bool]>> + BinaryMatrix + obicompactvec::ColumnWeights> TypedLayer<D> {
/// Number of genome columns in this layer's presence matrix — see
/// `PersistentBitMatrix::n_cols`'s docs for the `Implicit` mono-genome
/// special case (always reports `1`, regardless of the index's real
@@ -408,6 +414,13 @@ impl<D: LayerData<Item = Box<[bool]>> + BinaryMatrix> TypedLayer<D> {
pub fn fill_sub_matrix(&self, slots: &[usize], out: &mut [Vec<bool>]) {
self.data.fill_sub_matrix(slots, out)
}
/// Per-genome column weights — for presence/absence, the number of
/// k-mers each genome carries (see
/// `obicompactvec::ColumnWeights::col_weights`).
pub fn col_weights(&self) -> ndarray::Array1<u64> {
obicompactvec::ColumnWeights::col_weights(&self.data)
}
}
impl TypedLayer<PersistentBitMatrix> {