//! 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 -- use obicompactvec::{PersistentBitMatrix, PersistentSparseBitMatrix}; use obikindex::KmerIndex; fn main() -> anyhow::Result<()> { let sparse_root = std::env::args().nth(1).expect("usage: compare_sparse "); let dense_root = std::env::args().nth(2).expect("usage: compare_sparse "); 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(()) }