mirror of
https://github.com/metabarcoding/obitools4.git
synced 2026-11-09 09:24:41 +00:00
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.
86 lines
2.0 KiB
Go
86 lines
2.0 KiB
Go
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)
|
|
}
|
|
}
|