mirror of
https://github.com/metabarcoding/obitools4.git
synced 2026-11-10 01:24:41 +00:00
Implement k-mer distance metrics and constrained generation
Adds support for Hamming distance, constrained k-mer generation, and optimized Longest Common Subsequence (LCS) calculations using scalar, batch, and SIMD methods. This includes new methods for k-mer distance calculation, structures for k-mer constraints, and SIMD-based batch processing for LCS to improve performance and correctness.
This commit is contained in:
1 parent
0012a55cad
commit
a0d8187fd6
11 files changed
+601
-19
No files matched your search
@@ -0,0 +1,85 @@
|
||||
package obikmer
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func collectConstrained(k int, c KmerConstraints) []uint64 {
|
||||
var out []uint64
|
||||
for km := range IterConstrainedKmers(k, c) {
|
||||
out = append(out, km)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func TestIterConstrainedKmersUnconstrained(t *testing.T) {
|
||||
got := collectConstrained(4, NoKmerConstraints())
|
||||
if len(got) != 256 {
|
||||
t.Fatalf("expected 256 k-mers, got %d", len(got))
|
||||
}
|
||||
for i, km := range got {
|
||||
if km != uint64(i) {
|
||||
t.Fatalf("not in increasing order at %d: %d", i, km)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIterConstrainedKmersNoG(t *testing.T) {
|
||||
c := NoKmerConstraints()
|
||||
c.MaxCount[2] = 0
|
||||
got := collectConstrained(5, c)
|
||||
if len(got) != 243 {
|
||||
t.Fatalf("expected 3^5 = 243 k-mers, got %d", len(got))
|
||||
}
|
||||
for _, km := range got {
|
||||
if strings.Contains(string(DecodeKmer(km, 5, nil)), "g") {
|
||||
t.Fatalf("k-mer %d contains G", km)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIterConstrainedKmersMaxRun(t *testing.T) {
|
||||
c := NoKmerConstraints()
|
||||
c.MaxRun = 2
|
||||
// a(n) = 3*(a(n-1)+a(n-2)), a(1)=4, a(2)=16
|
||||
want := map[int]int{3: 60, 4: 228}
|
||||
for k, n := range want {
|
||||
if got := len(collectConstrained(k, c)); got != n {
|
||||
t.Fatalf("k=%d: expected %d, got %d", k, n, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIterConstrainedKmersMaxCount(t *testing.T) {
|
||||
c := NoKmerConstraints()
|
||||
c.MaxCount[0] = 1 // at most one A
|
||||
for _, km := range collectConstrained(6, c) {
|
||||
if strings.Count(string(DecodeKmer(km, 6, nil)), "a") > 1 {
|
||||
t.Fatalf("k-mer %d has more than one A", km)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIterConstrainedKmersImpossible(t *testing.T) {
|
||||
c := KmerConstraints{MaxCount: [4]int{1, 1, 1, 0}}
|
||||
if got := collectConstrained(4, c); len(got) != 0 {
|
||||
t.Fatalf("expected no k-mer, got %d", len(got))
|
||||
}
|
||||
if got := collectConstrained(0, NoKmerConstraints()); len(got) != 0 {
|
||||
t.Fatalf("expected no k-mer for k=0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIterConstrainedKmersEarlyStop(t *testing.T) {
|
||||
n := 0
|
||||
for range IterConstrainedKmers(10, NoKmerConstraints()) {
|
||||
n++
|
||||
if n == 5 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if n != 5 {
|
||||
t.Fatalf("early stop failed: %d", n)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user