feat: add sparse on-disk format for presence matrices
The index packing API now accepts a `sparse` parameter to generate `PersistentSparseBitMatrix` files alongside existing dense matrices. The sibling cache automatically detects this format via an `is_multi.prsb` marker file and routes queries identically to the dense variant. A new `--sparse` CLI flag exposes the option, with tests verifying end-to-end pipeline correctness and storage equivalence.
This commit is contained in:
@@ -122,7 +122,7 @@ impl KmerIndex {
|
||||
fs::File::create(output.join(SENTINEL_INDEXED)).map_err(OKIError::Io)?;
|
||||
let idx = KmerIndex::open(output)?;
|
||||
let t_pack = Stage::start("pack");
|
||||
idx.pack_matrices()?;
|
||||
idx.pack_matrices(false)?;
|
||||
rep.push(t_pack.stop());
|
||||
Ok(idx)
|
||||
}
|
||||
@@ -274,8 +274,14 @@ impl KmerIndex {
|
||||
///
|
||||
/// Reduces per-query file-open overhead from O(n_genomes) to O(1) per partition.
|
||||
/// Column files are kept in place; packed files take priority when opening.
|
||||
pub fn pack_matrices(&self) -> OKIResult<()> {
|
||||
use obicompactvec::{pack_bit_matrix, pack_compact_int_matrix};
|
||||
///
|
||||
/// If `sparse` is set, presence matrices go one step further, from the
|
||||
/// dense `.pbmx` form into `obicompactvec::PersistentSparseBitMatrix`'s
|
||||
/// on-disk format (see `docmd/architecture/siblings.md`) — count
|
||||
/// matrices are unaffected, sparse count matrices aren't implemented
|
||||
/// (see the sparse-matrix design plan's "Explicitly deferred").
|
||||
pub fn pack_matrices(&self, sparse: bool) -> OKIResult<()> {
|
||||
use obicompactvec::{pack_bit_matrix, pack_compact_int_matrix, pack_sparse_bit_matrix};
|
||||
use obilayeredmap::meta::PartitionMeta;
|
||||
|
||||
let n = self.n_partitions();
|
||||
@@ -292,7 +298,13 @@ impl KmerIndex {
|
||||
let layer_dir = index_dir.join(format!("layer_{l}"));
|
||||
let presence_dir = layer_dir.join("presence");
|
||||
let counts_dir = layer_dir.join("counts");
|
||||
if presence_dir.exists() { pack_bit_matrix(&presence_dir).map_err(OKIError::Io)?; }
|
||||
if presence_dir.exists() {
|
||||
if sparse {
|
||||
pack_sparse_bit_matrix(&presence_dir).map_err(OKIError::Io)?;
|
||||
} else {
|
||||
pack_bit_matrix(&presence_dir).map_err(OKIError::Io)?;
|
||||
}
|
||||
}
|
||||
if counts_dir.exists() { pack_compact_int_matrix(&counts_dir).map_err(OKIError::Io)?; }
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -249,7 +249,7 @@ impl KmerIndex {
|
||||
let pb = spinner("pack");
|
||||
pb.set_message("consolidating column files …");
|
||||
let dst2 = KmerIndex::open(output)?;
|
||||
dst2.pack_matrices()?;
|
||||
dst2.pack_matrices(false)?;
|
||||
pb.finish_and_clear();
|
||||
rep.push(t.stop());
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ impl KmerIndex {
|
||||
self.meta.write(&self.root_path)?;
|
||||
|
||||
let t_pack = Stage::start("pack");
|
||||
self.pack_matrices()?;
|
||||
self.pack_matrices(false)?;
|
||||
rep.push(t_pack.stop());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user