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,62 @@
|
||||
//go:build goexperiment.simd && arm64
|
||||
|
||||
package obikmer
|
||||
|
||||
import "simd/archsimd"
|
||||
|
||||
// neonLanes is the number of 16-bit lanes of a NEON 128-bit register.
|
||||
const neonLanes = 8
|
||||
|
||||
// kmerLCSBatchNEON is kmerLCSBatch written directly on archsimd NEON types
|
||||
// (see kmer_lcs_simd.go for the cell encoding and recurrence).
|
||||
func kmerLCSBatchNEON(query uint64, partners []uint64, k int, out []KmerLCSResult) {
|
||||
var qbase [32]uint16
|
||||
for i := 0; i < k; i++ {
|
||||
qbase[i] = uint16(query>>(2*uint(k-1-i))) & 3
|
||||
}
|
||||
|
||||
pbase := make([]uint16, k*neonLanes)
|
||||
row := make([]uint16, (k+1)*neonLanes)
|
||||
one := archsimd.BroadcastUint16x8(1)
|
||||
bonus := archsimd.BroadcastUint16x8(lcsScoreUnit)
|
||||
|
||||
for start := 0; start < len(partners); start += neonLanes {
|
||||
chunk := partners[start:min(start+neonLanes, len(partners))]
|
||||
|
||||
for lane, p := range chunk {
|
||||
for j := 0; j < k; j++ {
|
||||
pbase[j*neonLanes+lane] = uint16(p>>(2*uint(k-1-j))) & 3
|
||||
}
|
||||
}
|
||||
|
||||
for j := 0; j <= k; j++ {
|
||||
archsimd.BroadcastUint16x8(uint16(lcsLenBase - j)).Store(row[j*neonLanes:])
|
||||
}
|
||||
|
||||
for i := 1; i <= k; i++ {
|
||||
qv := archsimd.BroadcastUint16x8(qbase[i-1])
|
||||
diag := archsimd.LoadUint16x8(row)
|
||||
left := archsimd.BroadcastUint16x8(uint16(lcsLenBase - i))
|
||||
left.Store(row)
|
||||
|
||||
for j := 1; j <= k; j++ {
|
||||
up := archsimd.LoadUint16x8(row[j*neonLanes:])
|
||||
pv := archsimd.LoadUint16x8(pbase[(j-1)*neonLanes:])
|
||||
match := qv.Equal(pv)
|
||||
best := diag.Add(bonus.Masked(match)).Max(up).Max(left).Sub(one)
|
||||
best.Store(row[j*neonLanes:])
|
||||
diag = up
|
||||
left = best
|
||||
}
|
||||
}
|
||||
|
||||
last := row[k*neonLanes:]
|
||||
for lane := range chunk {
|
||||
v := int(last[lane])
|
||||
out[start+lane] = KmerLCSResult{
|
||||
LCS: v / lcsScoreUnit,
|
||||
AlignLen: lcsLenBase - v%lcsScoreUnit,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user