mirror of
https://github.com/metabarcoding/obitools4.git
synced 2026-11-10 01:24:41 +00:00
Feature: Implement constrained k-mer generation and clique search
This commit introduces core functionality for oligonucleotide family tagging, constrained k-mer generation, and clique finding. It also includes updates to the Go language version and refactors the logic for k-mer dissimilarity metrics.
This commit is contained in:
1 parent
f76e7f03c6
commit
3087c70daa
17 files changed
+1791
-13
No files matched your search
@@ -0,0 +1,84 @@
|
||||
package obikmer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// KmerMetric selects the distance used to compare two k-mers.
|
||||
type KmerMetric int
|
||||
|
||||
const (
|
||||
// HammingMetric counts the positions at which two k-mers differ.
|
||||
HammingMetric KmerMetric = iota
|
||||
// LCSMetric is the alignment length minus the LCS length (see KmerLCS).
|
||||
LCSMetric
|
||||
)
|
||||
|
||||
// ParseKmerMetric converts "hamming" or "lcs" (case insensitive) to a KmerMetric.
|
||||
func ParseKmerMetric(name string) (KmerMetric, error) {
|
||||
switch strings.ToLower(name) {
|
||||
case "hamming":
|
||||
return HammingMetric, nil
|
||||
case "lcs":
|
||||
return LCSMetric, nil
|
||||
}
|
||||
return HammingMetric, fmt.Errorf("unknown distance type %q (expected hamming or lcs)", name)
|
||||
}
|
||||
|
||||
func (m KmerMetric) String() string {
|
||||
if m == LCSMetric {
|
||||
return "lcs"
|
||||
}
|
||||
return "hamming"
|
||||
}
|
||||
|
||||
type lcsScratch struct {
|
||||
partners []uint64
|
||||
results []KmerLCSResult
|
||||
}
|
||||
|
||||
// NewKmerDissimilarityFilter describes the graph whose vertices are kmers[i]
|
||||
// (k-mers of size k, 1 <= k <= 31) and where two vertices are linked when
|
||||
// their distance is at least dmin. The returned function has the signature of
|
||||
// obigraph.NeighborFilter: it appends to out[:0] the candidates (indices in
|
||||
// kmers) linked to v. It is safe for concurrent use.
|
||||
func NewKmerDissimilarityFilter(kmers []uint64, k int, metric KmerMetric, dmin int) func(v int32, candidates, out []int32) []int32 {
|
||||
if metric == HammingMetric {
|
||||
return func(v int32, candidates, out []int32) []int32 {
|
||||
q := kmers[v]
|
||||
out = out[:0]
|
||||
for _, c := range candidates {
|
||||
if HammingDistance(q, kmers[c], k) >= dmin {
|
||||
out = append(out, c)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
pool := sync.Pool{New: func() any { return new(lcsScratch) }}
|
||||
return func(v int32, candidates, out []int32) []int32 {
|
||||
s := pool.Get().(*lcsScratch)
|
||||
defer pool.Put(s)
|
||||
|
||||
s.partners = s.partners[:0]
|
||||
for _, c := range candidates {
|
||||
s.partners = append(s.partners, kmers[c])
|
||||
}
|
||||
if cap(s.results) < len(candidates) {
|
||||
s.results = make([]KmerLCSResult, len(candidates))
|
||||
}
|
||||
s.results = s.results[:len(candidates)]
|
||||
KmerLCSBatch(kmers[v], s.partners, k, s.results)
|
||||
|
||||
out = out[:0]
|
||||
for i, c := range candidates {
|
||||
if s.results[i].Distance() >= dmin {
|
||||
out = append(out, c)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user