mirror of
https://github.com/metabarcoding/obitools4.git
synced 2026-03-25 13:30:52 +00:00
509 lines
16 KiB
Markdown
509 lines
16 KiB
Markdown
|
|
# Plan de refonte du package obikmer : index disk-based par partitions minimizer
|
|||
|
|
|
|||
|
|
## Constat
|
|||
|
|
|
|||
|
|
Les roaring64 bitmaps ne sont pas adaptés au stockage de 10^10 k-mers
|
|||
|
|
(k=31) dispersés sur un espace de 2^62. L'overhead structurel (containers
|
|||
|
|
roaring par high key 32 bits) dépasse la taille des données elles-mêmes,
|
|||
|
|
et les opérations `Or()` entre bitmaps fragmentés ne terminent pas en
|
|||
|
|
temps raisonnable.
|
|||
|
|
|
|||
|
|
## Principe de la nouvelle architecture
|
|||
|
|
|
|||
|
|
Un `KmerSet` est un ensemble trié de k-mers canoniques (uint64) stocké
|
|||
|
|
sur disque, partitionné par minimizer. Chaque partition est un fichier
|
|||
|
|
binaire contenant des uint64 triés, compressés par delta-varint.
|
|||
|
|
|
|||
|
|
Un `KmerSetGroup` est un répertoire contenant N ensembles partitionnés
|
|||
|
|
de la même façon (même k, même m, même P).
|
|||
|
|
|
|||
|
|
Un `KmerSet` est un `KmerSetGroup` de taille 1 (singleton).
|
|||
|
|
|
|||
|
|
Les opérations ensemblistes se font partition par partition, en merge
|
|||
|
|
streaming, sans charger l'index complet en mémoire.
|
|||
|
|
|
|||
|
|
## Cycle de vie d'un index
|
|||
|
|
|
|||
|
|
L'index a deux phases distinctes :
|
|||
|
|
|
|||
|
|
1. **Phase de construction (mutable)** : on ouvre un index, on y ajoute
|
|||
|
|
des séquences. Pour chaque séquence, les super-kmers sont extraits
|
|||
|
|
et écrits de manière compacte (2 bits/base) dans le fichier
|
|||
|
|
temporaire de partition correspondant (`minimizer % P`). Les
|
|||
|
|
super-kmers sont une représentation compressée naturelle des k-mers
|
|||
|
|
chevauchants : un super-kmer de longueur L encode L-k+1 k-mers en
|
|||
|
|
ne stockant que ~L/4 bytes au lieu de (L-k+1) × 8 bytes.
|
|||
|
|
|
|||
|
|
2. **Phase de clôture (optimisation)** : on ferme l'index, ce qui
|
|||
|
|
déclenche le traitement **partition par partition** (indépendant,
|
|||
|
|
parallélisable) :
|
|||
|
|
- Charger les super-kmers de la partition
|
|||
|
|
- En extraire tous les k-mers canoniques
|
|||
|
|
- Trier le tableau de k-mers
|
|||
|
|
- Dédupliquer (et compter si FrequencyFilter)
|
|||
|
|
- Delta-encoder et écrire le fichier .kdi final
|
|||
|
|
Après clôture, l'index est statique et immuable.
|
|||
|
|
|
|||
|
|
3. **Phase de lecture (immutable)** : opérations ensemblistes,
|
|||
|
|
Jaccard, Quorum, Contains, itération. Toutes en streaming.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Format sur disque
|
|||
|
|
|
|||
|
|
### Index finalisé
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
index_dir/
|
|||
|
|
metadata.toml
|
|||
|
|
set_0/
|
|||
|
|
part_0000.kdi
|
|||
|
|
part_0001.kdi
|
|||
|
|
...
|
|||
|
|
part_{P-1}.kdi
|
|||
|
|
set_1/
|
|||
|
|
part_0000.kdi
|
|||
|
|
...
|
|||
|
|
...
|
|||
|
|
set_{N-1}/
|
|||
|
|
...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Fichiers temporaires pendant la construction
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
index_dir/
|
|||
|
|
.build/
|
|||
|
|
set_0/
|
|||
|
|
part_0000.skm # super-kmers encodés 2 bits/base
|
|||
|
|
part_0001.skm
|
|||
|
|
...
|
|||
|
|
set_1/
|
|||
|
|
...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Le répertoire `.build/` est supprimé après Close().
|
|||
|
|
|
|||
|
|
### metadata.toml
|
|||
|
|
|
|||
|
|
```toml
|
|||
|
|
id = "mon_index"
|
|||
|
|
k = 31
|
|||
|
|
m = 13
|
|||
|
|
partitions = 1024
|
|||
|
|
type = "KmerSetGroup" # ou "KmerSet" (N=1)
|
|||
|
|
size = 3 # nombre de sets (N)
|
|||
|
|
sets_ids = ["genome_A", "genome_B", "genome_C"]
|
|||
|
|
|
|||
|
|
[user_metadata]
|
|||
|
|
organism = "Triticum aestivum"
|
|||
|
|
|
|||
|
|
[sets_metadata]
|
|||
|
|
# métadonnées individuelles par set si nécessaire
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Fichier .kdi (Kmer Delta Index)
|
|||
|
|
|
|||
|
|
Format binaire :
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
[magic: 4 bytes "KDI\x01"]
|
|||
|
|
[count: uint64 little-endian] # nombre de k-mers dans cette partition
|
|||
|
|
[first: uint64 little-endian] # premier k-mer (valeur absolue)
|
|||
|
|
[delta_1: varint] # arr[1] - arr[0]
|
|||
|
|
[delta_2: varint] # arr[2] - arr[1]
|
|||
|
|
...
|
|||
|
|
[delta_{count-1}: varint] # arr[count-1] - arr[count-2]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Varint : encoding unsigned, 7 bits utiles par byte, bit de poids fort
|
|||
|
|
= continuation (identique au varint protobuf).
|
|||
|
|
|
|||
|
|
Fichier vide (partition sans k-mer) : magic + count=0.
|
|||
|
|
|
|||
|
|
### Fichier .skm (Super-Kmer temporaire)
|
|||
|
|
|
|||
|
|
Format binaire, séquence de super-kmers encodés :
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
[len: uint16 little-endian] # longueur du super-kmer en bases
|
|||
|
|
[sequence: ceil(len/4) bytes] # séquence encodée 2 bits/base, packed
|
|||
|
|
...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**Compression par rapport au stockage de k-mers bruts** :
|
|||
|
|
|
|||
|
|
Un super-kmer de longueur L contient L-k+1 k-mers.
|
|||
|
|
- Stockage super-kmer : 2 + ceil(L/4) bytes
|
|||
|
|
- Stockage k-mers bruts : (L-k+1) × 8 bytes
|
|||
|
|
|
|||
|
|
Exemple avec k=31, super-kmer typique L=50 :
|
|||
|
|
- Super-kmer : 2 + 13 = 15 bytes → encode 20 k-mers
|
|||
|
|
- K-mers bruts : 20 × 8 = 160 bytes
|
|||
|
|
- **Facteur de compression : ~10×**
|
|||
|
|
|
|||
|
|
Pour un génome de 10 Gbases (~10^10 k-mers bruts) :
|
|||
|
|
- K-mers bruts : ~80 Go par set temporaire
|
|||
|
|
- Super-kmers : **~8 Go** par set temporaire
|
|||
|
|
|
|||
|
|
Avec FrequencyFilter et couverture 30× :
|
|||
|
|
- K-mers bruts : ~2.4 To
|
|||
|
|
- Super-kmers : **~240 Go**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## FrequencyFilter
|
|||
|
|
|
|||
|
|
Le FrequencyFilter n'est plus un type de données séparé. C'est un
|
|||
|
|
**mode de construction** du builder. Le résultat est un KmerSetGroup
|
|||
|
|
standard.
|
|||
|
|
|
|||
|
|
### Principe
|
|||
|
|
|
|||
|
|
Pendant la construction, tous les super-kmers sont écrits dans les
|
|||
|
|
fichiers temporaires .skm, y compris les doublons (chaque occurrence
|
|||
|
|
de chaque séquence est écrite).
|
|||
|
|
|
|||
|
|
Pendant Close(), pour chaque partition :
|
|||
|
|
1. Charger tous les super-kmers de la partition
|
|||
|
|
2. Extraire tous les k-mers canoniques dans un tableau []uint64
|
|||
|
|
3. Trier le tableau
|
|||
|
|
4. Parcourir linéairement : les k-mers identiques sont consécutifs
|
|||
|
|
5. Compter les occurrences de chaque k-mer
|
|||
|
|
6. Si count >= minFreq → écrire dans le .kdi final (une seule fois)
|
|||
|
|
7. Sinon → ignorer
|
|||
|
|
|
|||
|
|
### Dimensionnement
|
|||
|
|
|
|||
|
|
Pour un génome de 10 Gbases avec couverture 30× :
|
|||
|
|
- N_brut ≈ 3×10^11 k-mers bruts
|
|||
|
|
- Espace temporaire .skm ≈ 240 Go (compressé super-kmer)
|
|||
|
|
- RAM par partition pendant Close() :
|
|||
|
|
Avec P=1024 : ~3×10^8 k-mers/partition × 8 = **~2.4 Go**
|
|||
|
|
Avec P=4096 : ~7.3×10^7 k-mers/partition × 8 = **~600 Mo**
|
|||
|
|
|
|||
|
|
Le choix de P détermine le compromis nombre de fichiers vs RAM par
|
|||
|
|
partition.
|
|||
|
|
|
|||
|
|
### Sans FrequencyFilter (déduplication simple)
|
|||
|
|
|
|||
|
|
Pour de la déduplication simple (chaque k-mer écrit une fois), le
|
|||
|
|
builder peut dédupliquer au niveau des buffers en RAM avant flush.
|
|||
|
|
Cela réduit significativement l'espace temporaire car les doublons
|
|||
|
|
au sein d'un même buffer (provenant de séquences proches) sont
|
|||
|
|
éliminés immédiatement.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## API publique visée
|
|||
|
|
|
|||
|
|
### Structures
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// KmerSetGroup est l'entité de base.
|
|||
|
|
// Un KmerSet est un KmerSetGroup avec Size() == 1.
|
|||
|
|
type KmerSetGroup struct {
|
|||
|
|
// champs internes : path, k, m, P, N, metadata, état
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// KmerSetGroupBuilder construit un KmerSetGroup mutable.
|
|||
|
|
type KmerSetGroupBuilder struct {
|
|||
|
|
// champs internes : buffers I/O par partition et par set,
|
|||
|
|
// fichiers temporaires .skm, paramètres (minFreq, etc.)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Construction
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// NewKmerSetGroupBuilder crée un builder pour un nouveau KmerSetGroup.
|
|||
|
|
// directory : répertoire de destination
|
|||
|
|
// k : taille des k-mers (1-31)
|
|||
|
|
// m : taille des minimizers (-1 pour auto = ceil(k/2.5))
|
|||
|
|
// n : nombre de sets dans le groupe
|
|||
|
|
// P : nombre de partitions (-1 pour auto)
|
|||
|
|
// options : options de construction (FrequencyFilter, etc.)
|
|||
|
|
func NewKmerSetGroupBuilder(directory string, k, m, n, P int,
|
|||
|
|
options ...BuilderOption) (*KmerSetGroupBuilder, error)
|
|||
|
|
|
|||
|
|
// WithMinFrequency active le mode FrequencyFilter.
|
|||
|
|
// Seuls les k-mers vus >= minFreq fois sont conservés dans l'index
|
|||
|
|
// final. Les super-kmers sont écrits avec leurs doublons pendant
|
|||
|
|
// la construction ; le comptage exact se fait au Close().
|
|||
|
|
func WithMinFrequency(minFreq int) BuilderOption
|
|||
|
|
|
|||
|
|
// AddSequence extrait les super-kmers d'une séquence et les écrit
|
|||
|
|
// dans les fichiers temporaires de partition du set i.
|
|||
|
|
func (b *KmerSetGroupBuilder) AddSequence(setIndex int, seq *obiseq.BioSequence)
|
|||
|
|
|
|||
|
|
// AddSuperKmer écrit un super-kmer dans le fichier temporaire de
|
|||
|
|
// sa partition pour le set i.
|
|||
|
|
func (b *KmerSetGroupBuilder) AddSuperKmer(setIndex int, sk SuperKmer)
|
|||
|
|
|
|||
|
|
// Close finalise la construction :
|
|||
|
|
// - flush des buffers d'écriture
|
|||
|
|
// - pour chaque partition de chaque set (parallélisable) :
|
|||
|
|
// - charger les super-kmers depuis le .skm
|
|||
|
|
// - extraire les k-mers canoniques
|
|||
|
|
// - trier, dédupliquer (compter si freq filter)
|
|||
|
|
// - delta-encoder et écrire le .kdi
|
|||
|
|
// - écrire metadata.toml
|
|||
|
|
// - supprimer le répertoire .build/
|
|||
|
|
// Retourne le KmerSetGroup en lecture seule.
|
|||
|
|
func (b *KmerSetGroupBuilder) Close() (*KmerSetGroup, error)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Lecture et opérations
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// OpenKmerSetGroup ouvre un index finalisé en lecture seule.
|
|||
|
|
func OpenKmerSetGroup(directory string) (*KmerSetGroup, error)
|
|||
|
|
|
|||
|
|
// --- Métadonnées (API inchangée) ---
|
|||
|
|
func (ksg *KmerSetGroup) K() int
|
|||
|
|
func (ksg *KmerSetGroup) M() int // nouveau : taille du minimizer
|
|||
|
|
func (ksg *KmerSetGroup) Partitions() int // nouveau : nombre de partitions
|
|||
|
|
func (ksg *KmerSetGroup) Size() int
|
|||
|
|
func (ksg *KmerSetGroup) Id() string
|
|||
|
|
func (ksg *KmerSetGroup) SetId(id string)
|
|||
|
|
func (ksg *KmerSetGroup) HasAttribute(key string) bool
|
|||
|
|
func (ksg *KmerSetGroup) GetAttribute(key string) (interface{}, bool)
|
|||
|
|
func (ksg *KmerSetGroup) SetAttribute(key string, value interface{})
|
|||
|
|
// ... etc (toute l'API attributs actuelle est conservée)
|
|||
|
|
|
|||
|
|
// --- Opérations ensemblistes ---
|
|||
|
|
// Toutes produisent un nouveau KmerSetGroup singleton sur disque.
|
|||
|
|
// Opèrent partition par partition en streaming.
|
|||
|
|
|
|||
|
|
func (ksg *KmerSetGroup) Union(outputDir string) (*KmerSetGroup, error)
|
|||
|
|
func (ksg *KmerSetGroup) Intersect(outputDir string) (*KmerSetGroup, error)
|
|||
|
|
func (ksg *KmerSetGroup) Difference(outputDir string) (*KmerSetGroup, error)
|
|||
|
|
func (ksg *KmerSetGroup) QuorumAtLeast(q int, outputDir string) (*KmerSetGroup, error)
|
|||
|
|
func (ksg *KmerSetGroup) QuorumExactly(q int, outputDir string) (*KmerSetGroup, error)
|
|||
|
|
func (ksg *KmerSetGroup) QuorumAtMost(q int, outputDir string) (*KmerSetGroup, error)
|
|||
|
|
|
|||
|
|
// --- Opérations entre deux KmerSetGroups ---
|
|||
|
|
// Les deux groupes doivent avoir les mêmes k, m, P.
|
|||
|
|
|
|||
|
|
func (ksg *KmerSetGroup) UnionWith(other *KmerSetGroup, outputDir string) (*KmerSetGroup, error)
|
|||
|
|
func (ksg *KmerSetGroup) IntersectWith(other *KmerSetGroup, outputDir string) (*KmerSetGroup, error)
|
|||
|
|
|
|||
|
|
// --- Métriques (résultat en mémoire, pas de sortie disque) ---
|
|||
|
|
|
|||
|
|
func (ksg *KmerSetGroup) JaccardDistanceMatrix() *obidist.DistMatrix
|
|||
|
|
func (ksg *KmerSetGroup) JaccardSimilarityMatrix() *obidist.DistMatrix
|
|||
|
|
|
|||
|
|
// --- Accès individuel ---
|
|||
|
|
|
|||
|
|
func (ksg *KmerSetGroup) Len(setIndex ...int) uint64
|
|||
|
|
func (ksg *KmerSetGroup) Contains(setIndex int, kmer uint64) bool
|
|||
|
|
func (ksg *KmerSetGroup) Iterator(setIndex int) iter.Seq[uint64]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Implémentation interne
|
|||
|
|
|
|||
|
|
### Primitives bas niveau
|
|||
|
|
|
|||
|
|
**`varint.go`** : encode/decode varint uint64
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
func EncodeVarint(w io.Writer, v uint64) (int, error)
|
|||
|
|
func DecodeVarint(r io.Reader) (uint64, error)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Format .kdi
|
|||
|
|
|
|||
|
|
**`kdi_writer.go`** : écriture d'un fichier .kdi à partir d'un flux
|
|||
|
|
trié de uint64 (delta-encode au vol).
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
type KdiWriter struct { ... }
|
|||
|
|
func NewKdiWriter(path string) (*KdiWriter, error)
|
|||
|
|
func (w *KdiWriter) Write(kmer uint64) error
|
|||
|
|
func (w *KdiWriter) Close() error
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**`kdi_reader.go`** : lecture streaming d'un fichier .kdi (décode
|
|||
|
|
les deltas au vol).
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
type KdiReader struct { ... }
|
|||
|
|
func NewKdiReader(path string) (*KdiReader, error)
|
|||
|
|
func (r *KdiReader) Next() (uint64, bool)
|
|||
|
|
func (r *KdiReader) Count() uint64
|
|||
|
|
func (r *KdiReader) Close() error
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Format .skm
|
|||
|
|
|
|||
|
|
**`skm_writer.go`** : écriture de super-kmers encodés 2 bits/base.
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
type SkmWriter struct { ... }
|
|||
|
|
func NewSkmWriter(path string) (*SkmWriter, error)
|
|||
|
|
func (w *SkmWriter) Write(sk SuperKmer) error
|
|||
|
|
func (w *SkmWriter) Close() error
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**`skm_reader.go`** : lecture de super-kmers depuis un fichier .skm.
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
type SkmReader struct { ... }
|
|||
|
|
func NewSkmReader(path string) (*SkmReader, error)
|
|||
|
|
func (r *SkmReader) Next() (SuperKmer, bool)
|
|||
|
|
func (r *SkmReader) Close() error
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Merge streaming
|
|||
|
|
|
|||
|
|
**`kdi_merge.go`** : k-way merge de plusieurs flux triés.
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
type KWayMerge struct { ... }
|
|||
|
|
func NewKWayMerge(readers []*KdiReader) *KWayMerge
|
|||
|
|
func (m *KWayMerge) Next() (kmer uint64, count int, ok bool)
|
|||
|
|
func (m *KWayMerge) Close() error
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Builder
|
|||
|
|
|
|||
|
|
**`kmer_set_builder.go`** : construction d'un KmerSetGroup.
|
|||
|
|
|
|||
|
|
Le builder gère :
|
|||
|
|
- P × N écrivains .skm bufferisés (un par partition × set)
|
|||
|
|
- À la clôture : traitement partition par partition
|
|||
|
|
(parallélisable sur plusieurs cores)
|
|||
|
|
|
|||
|
|
Gestion mémoire des buffers d'écriture :
|
|||
|
|
- Chaque SkmWriter a un buffer I/O de taille raisonnable (~64 Ko)
|
|||
|
|
- Avec P=1024 et N=1 : 1024 × 64 Ko = 64 Mo de buffers
|
|||
|
|
- Avec P=1024 et N=10 : 640 Mo de buffers
|
|||
|
|
- Pas de buffer de k-mers en RAM : tout est écrit sur disque
|
|||
|
|
immédiatement via les super-kmers
|
|||
|
|
|
|||
|
|
RAM pendant Close() (tri d'une partition) :
|
|||
|
|
- Charger les super-kmers → extraire les k-mers → tableau []uint64
|
|||
|
|
- Avec P=1024 et 10^10 k-mers/set : ~10^7 k-mers/partition × 8 = ~80 Mo
|
|||
|
|
- Avec FrequencyFilter (doublons) et couverture 30× :
|
|||
|
|
~3×10^8/partition × 8 = ~2.4 Go (ajustable via P)
|
|||
|
|
|
|||
|
|
### Structure disk-based
|
|||
|
|
|
|||
|
|
**`kmer_set_disk.go`** : KmerSetGroup en lecture seule.
|
|||
|
|
|
|||
|
|
**`kmer_set_disk_ops.go`** : opérations ensemblistes par merge
|
|||
|
|
streaming partition par partition.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Ce qui change par rapport à l'API actuelle
|
|||
|
|
|
|||
|
|
### Changements de sémantique
|
|||
|
|
|
|||
|
|
| Aspect | Ancien (roaring) | Nouveau (disk-based) |
|
|||
|
|
|---|---|---|
|
|||
|
|
| Stockage | En mémoire (roaring64.Bitmap) | Sur disque (.kdi delta-encoded) |
|
|||
|
|
| Temporaire construction | En mémoire | Super-kmers sur disque (.skm 2 bits/base) |
|
|||
|
|
| Mutabilité | Mutable à tout moment | Builder → Close() → immutable |
|
|||
|
|
| Opérations ensemblistes | Résultat en mémoire | Résultat sur disque (nouveau répertoire) |
|
|||
|
|
| Contains | O(1) roaring lookup | O(log n) recherche binaire sur .kdi |
|
|||
|
|
| Itération | Roaring iterator | Streaming décodage delta-varint |
|
|||
|
|
|
|||
|
|
### API conservée (signatures identiques ou quasi-identiques)
|
|||
|
|
|
|||
|
|
- `KmerSetGroup` : `K()`, `Size()`, `Id()`, `SetId()`
|
|||
|
|
- Toute l'API attributs
|
|||
|
|
- `JaccardDistanceMatrix()`, `JaccardSimilarityMatrix()`
|
|||
|
|
- `Len()`, `Contains()`
|
|||
|
|
|
|||
|
|
### API modifiée
|
|||
|
|
|
|||
|
|
- `Union()`, `Intersect()`, etc. : ajout du paramètre `outputDir`
|
|||
|
|
- `QuorumAtLeast()`, etc. : idem
|
|||
|
|
- Construction : `NewKmerSetGroupBuilder()` + `AddSequence()` + `Close()`
|
|||
|
|
au lieu de manipulation directe
|
|||
|
|
|
|||
|
|
### API supprimée
|
|||
|
|
|
|||
|
|
- `KmerSet` comme type distinct (remplacé par KmerSetGroup singleton)
|
|||
|
|
- `FrequencyFilter` comme type distinct (mode du Builder)
|
|||
|
|
- Tout accès direct à `roaring64.Bitmap`
|
|||
|
|
- `KmerSet.Copy()` (copie de répertoire à la place)
|
|||
|
|
- `KmerSet.Union()`, `.Intersect()`, `.Difference()` (deviennent méthodes
|
|||
|
|
de KmerSetGroup avec outputDir)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Fichiers à créer / modifier dans pkg/obikmer
|
|||
|
|
|
|||
|
|
### Nouveaux fichiers
|
|||
|
|
|
|||
|
|
| Fichier | Contenu |
|
|||
|
|
|---|---|
|
|||
|
|
| `varint.go` | Encode/Decode varint uint64 |
|
|||
|
|
| `kdi_writer.go` | Écrivain de fichiers .kdi (delta-encoded) |
|
|||
|
|
| `kdi_reader.go` | Lecteur streaming de fichiers .kdi |
|
|||
|
|
| `skm_writer.go` | Écrivain de super-kmers encodés 2 bits/base |
|
|||
|
|
| `skm_reader.go` | Lecteur de super-kmers depuis .skm |
|
|||
|
|
| `kdi_merge.go` | K-way merge streaming de flux triés |
|
|||
|
|
| `kmer_set_builder.go` | KmerSetGroupBuilder (construction) |
|
|||
|
|
| `kmer_set_disk.go` | KmerSetGroup disk-based (lecture, métadonnées) |
|
|||
|
|
| `kmer_set_disk_ops.go` | Opérations ensemblistes streaming |
|
|||
|
|
|
|||
|
|
### Fichiers à supprimer
|
|||
|
|
|
|||
|
|
| Fichier | Raison |
|
|||
|
|
|---|---|
|
|||
|
|
| `kmer_set.go` | Remplacé par kmer_set_disk.go |
|
|||
|
|
| `kmer_set_group.go` | Idem |
|
|||
|
|
| `kmer_set_attributes.go` | Intégré dans kmer_set_disk.go |
|
|||
|
|
| `kmer_set_persistence.go` | L'index est nativement sur disque |
|
|||
|
|
| `kmer_set_group_quorum.go` | Intégré dans kmer_set_disk_ops.go |
|
|||
|
|
| `frequency_filter.go` | Mode du Builder, plus de type séparé |
|
|||
|
|
| `kmer_index_builder.go` | Remplacé par kmer_set_builder.go |
|
|||
|
|
|
|||
|
|
### Fichiers conservés tels quels
|
|||
|
|
|
|||
|
|
| Fichier | Contenu |
|
|||
|
|
|---|---|
|
|||
|
|
| `encodekmer.go` | Encodage/décodage k-mers |
|
|||
|
|
| `superkmer.go` | Structure SuperKmer |
|
|||
|
|
| `superkmer_iter.go` | IterSuperKmers, IterCanonicalKmers |
|
|||
|
|
| `encodefourmer.go` | Encode4mer |
|
|||
|
|
| `counting.go` | Count4Mer |
|
|||
|
|
| `kmermap.go` | KmerMap (usage indépendant) |
|
|||
|
|
| `debruijn.go` | Graphe de de Bruijn |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Ordre d'implémentation
|
|||
|
|
|
|||
|
|
1. `varint.go` + tests
|
|||
|
|
2. `skm_writer.go` + `skm_reader.go` + tests
|
|||
|
|
3. `kdi_writer.go` + `kdi_reader.go` + tests
|
|||
|
|
4. `kdi_merge.go` + tests
|
|||
|
|
5. `kmer_set_builder.go` + tests (construction + Close)
|
|||
|
|
6. `kmer_set_disk.go` (structure, métadonnées, Open)
|
|||
|
|
7. `kmer_set_disk_ops.go` + tests (Union, Intersect, Quorum, Jaccard)
|
|||
|
|
8. Adaptation de `pkg/obitools/obikindex/`
|
|||
|
|
9. Suppression des anciens fichiers roaring
|
|||
|
|
10. Adaptation des tests existants
|
|||
|
|
|
|||
|
|
Chaque étape est testable indépendamment.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Dépendances externes
|
|||
|
|
|
|||
|
|
### Supprimées
|
|||
|
|
|
|||
|
|
- `github.com/RoaringBitmap/roaring` : plus nécessaire pour les
|
|||
|
|
index k-mers (vérifier si d'autres packages l'utilisent encore)
|
|||
|
|
|
|||
|
|
### Ajoutées
|
|||
|
|
|
|||
|
|
- Aucune. Varint, delta-encoding, merge, encodage 2 bits/base :
|
|||
|
|
tout est implémentable en Go standard.
|