Files
obikmer/Le_bug_des_A.md
Eric Coissac 1f9c6388eb Introduce compare_sparse CLI tool to verify index consistency
Adds a new binary that validates bit-level consistency between dense and sparse K-mer index representations by sampling slots across partitions and reporting discrepancies. Refactors sibling cache matrix initialization into a centralized factory method to simplify control flow and standardize error handling. Introduces diagnostic configurations, benchmark scripts, and an ignored test case to support k-mer resolution analysis.
2026-08-17 11:16:42 +02:00

4.1 KiB
Raw Permalink Blame History

Voici la version corrigée :


Bug : dans base_pair_tally, toutes les transitions/comptes depuis/vers A valent 0 dans _sankoff_params.yaml, alors que C/G/T sont corrects.

Contexte : obikmer, pipeline phylogénétique --sankoff. Lindex est construit sur 20 génomes bactériens. Même symptôme sur un jeu de 100 génomes de plantes : A est toujours à 0.

Fichier clé : src/obikphylo/src/siblings/sankoff_bundle.rs (Pass A + Pass B).

Ce qui a été vérifié :

  • Le fichier de sortie _sankoff_params.yaml montre bien composition_transitions avec A à 0 partout.
  • Lindex contient bien des familles avec A (mask.has(0) == true), et même des familles où A co-existe avec dautres bases (mask == 0b0011 par ex.).
  • Un k-mer propriétaire de famille avec mask == 0b0001 (A seul) a été identifié : forward GAACAAGAGATCTCGATCTTGTCTACAAGGA, revcomp TCCTTGTAGACAAGATCGAGATCTCTTGTTC.
  • Le diagnostic CLI sur lindex réel donne :
    • Pass A : a_pairs=623342 a_snp=623342 a_shared=0 a_both_a=0
    • Pass B : families_with_a=22965521 a_single_form_genomes=22913238 a_included_pairs=0 a_same_incremented=0 bp_same=[0, 96389, 222720, 277909] bp_counts[0]=[0, 0, 0, 0]

Interprétation : A est fréquemment en single_form (mask == 1) chez certains génomes, mais jamais simultanément chez deux génomes différents dans la même famille. Donc toutes les paires “avec A” sont 100% SNP → ratio = 1.0 > ratio_ceiling=0.5 → toutes exclues par le filtre included. Cest pourquoi bp_same[0] et bp_counts[0][*] restent à 0.

Point crucial : le bug napparaît que sur lindex compacté sparse. Sur le même index avant compaction (matrice dense matrix.pbmx), --sankoff produit des tallies corrects pour A. Dès quon compacte avec pack --sparse, A disparaît.

Vérifications supplémentaires (diagnostic sparse) :

  • La compaction pack --sparse produit une matrice PersistentSparseBitMatrix dont le contenu est strictement identique à la matrice dense d'origine : vérification exhaustive coordonnée par coordonnée sur 1 804 774 880 cellules (512 partitions × 2 layers), zéro différence.
  • fill_row et fill_sub_matrix (les deux chemins de lecture utilisés par le pipeline phylogénétique) restituent les mêmes bits sur dense et sparse.
  • Conclusion : le bug n'est pas dans la compaction sparse elle-même, ni dans les chemins de lecture individuels. La structure stocke correctement A, C, G, T.

Conséquence logique : Si les matrices sont identiques mais que le résultat final diffère, le bug se situe dans l'intersection des informations — c'est-à-dire dans le code qui combine les lectures des deux matrices (ou qui transforme les résultats bruts en tallies). Deux endroits possibles :

  1. Le scan sankoff_bundle (family_scan.rs + sankoff_bundle.rs) : la boucle qui lit les matrices, construit genome_mask, et accumule bp_counts / same. C'est l'étape d'intersection proprement dite.
  2. La conversion des tallies en YAML (obikmer/src/cmd/phylo/sankoff.rs) : moins probable, mais possible si quelque chose sélectionne/filtre les transitions avant écriture.

Hypothèse la plus probable : bug dans la résolution cross-partition lors de la construction de l'annex sibling (build_sibling_annex). A (bit 0) serait systématiquement manquant ou mal résolu quand on interroge les variants d'une famille depuis une partition différente. À vérifier dans src/obikphylo/src/siblings/build.rs et src/obikphylo/src/siblings/cache.rs (PartitionCache::find / find_presence_batch).

Prochaine étape logique :

  1. Inspecter build_sibling_annex pour voir si les variants avec base A sont bien générés et bien recherchés dans cache.find.
  2. Vérifier PartitionCache::find et resolve_layer_hits pour un éventuel biais contre le bit 0.
  3. Si besoin, ajouter un diagnostic ciblé (compteurs par base) uniquement dans cache.rs ou build.rs, pas dans sankoff_bundle.rs qui est déjà propre.

Contraintes :

  • Ne pas modifier sankoff_bundle.rs davantage.
  • Ne pas toucher à git.
  • Faire des diagnostics minimaux et ciblés.