Consolidate compare_sparse as example and clean up project artifacts

Restructure the project by moving the standalone compare_sparse utility into an example directory, removing Sankoff parameter configurations and benchmark scripts, updating version control ignores, and expanding the test suite with diagnostic checks and performance benchmarks.
This commit is contained in:
Eric Coissac
2026-08-20 12:48:42 +02:00
parent dc3d82f8db
commit dbd8af376c
13 changed files with 12 additions and 1184 deletions
+105
View File
@@ -0,0 +1,105 @@
//! Diagnostic tool: verify that a sparse-packed presence index (`pack --sparse`)
//! is bit-for-bit identical to the dense index it was compacted from.
//!
//! Usage: cargo run --example compare_sparse -p obikindex -- <sparse_root> <dense_root>
use obicompactvec::{PersistentBitMatrix, PersistentSparseBitMatrix};
use obikindex::KmerIndex;
fn main() -> anyhow::Result<()> {
let sparse_root = std::env::args().nth(1).expect("usage: compare_sparse <sparse_root> <dense_root>");
let dense_root = std::env::args().nth(2).expect("usage: compare_sparse <sparse_root> <dense_root>");
let sparse = KmerIndex::open(&sparse_root)?;
let dense = KmerIndex::open(&dense_root)?;
let n_parts = sparse.n_partitions();
let n_layers = sparse.n_layers_per_partition()?;
println!("index sparse: {} partitions, {} layers", sparse.n_partitions(), n_layers);
println!("index dense: {} partitions, {} layers", dense.n_partitions(), dense.n_layers_per_partition()?);
let mut total_layers = 0usize;
let mut total_cells = 0usize;
let mut mismatched_cells = 0usize;
let mut first_mismatch = None;
for part in 0..n_parts {
let part_dir_sparse = sparse.partition().part_dir(part);
let part_dir_dense = dense.partition().part_dir(part);
if !part_dir_sparse.join("index").exists() || !part_dir_dense.join("index").exists() {
continue;
}
for layer in 0..n_layers {
let layer_dir_sparse = part_dir_sparse.join("index").join(format!("layer_{layer}"));
let layer_dir_dense = part_dir_dense.join("index").join(format!("layer_{layer}"));
if !layer_dir_sparse.exists() || !layer_dir_dense.exists() {
continue;
}
let presence_sparse = layer_dir_sparse.join("presence");
let presence_dense = layer_dir_dense.join("presence");
if !presence_sparse.exists() || !presence_dense.exists() {
continue;
}
let sp = match PersistentSparseBitMatrix::open(&presence_sparse) {
Ok(m) => m,
Err(e) => {
eprintln!("ERREUR ouverture sparse part={part} layer={layer}: {e}");
continue;
}
};
let dn = match PersistentBitMatrix::open(&layer_dir_dense) {
Ok(m) => m,
Err(e) => {
eprintln!("ERREUR ouverture dense part={part} layer={layer}: {e}");
continue;
}
};
if dn.n_cols() != sp.n_cols() || dn.n() != sp.n() || dn.n() == 0 {
continue;
}
let n = dn.n();
let n_cols = dn.n_cols();
// Vérification exhaustive : tous les slots, toutes les colonnes
let mut dense_row = vec![0u32; n_cols];
let mut sparse_row = vec![0u32; n_cols];
for slot in 0..n {
dn.fill_row(slot, &mut dense_row);
sp.fill_row(slot, &mut sparse_row);
for c in 0..n_cols {
total_cells += 1;
if dense_row[c] != sparse_row[c] {
mismatched_cells += 1;
if first_mismatch.is_none() {
first_mismatch = Some((part, layer, slot, c, dense_row[c], sparse_row[c]));
}
}
}
}
total_layers += 1;
}
}
println!("Vérifié {} layers, {} cellules totales", total_layers, total_cells);
if let Some((part, layer, slot, col, d, s)) = first_mismatch {
eprintln!("PREMIER MISMATCH : part={part} layer={layer} slot={slot} col={col} dense={d} sparse={s}");
println!("MISMATCHES : {} cellules différentes", mismatched_cells);
} else {
println!("OK : toutes les {} cellules sont identiques entre dense et sparse.", total_cells);
}
Ok(())
}