Files
Eric Coissac a0d8187fd6 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.
2026-11-03 09:23:37 +11:00

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)
}
}