feat(SNNBot): recency-weighted exemplars for fast re-acquisition
Exponential decay (0.95^age) makes newest exemplars dominate the weighted mean. Old stale exemplars fade naturally, so re-learning after target movement is always fast regardless of buffer history. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@ proc initBinaryAimer*(): BinaryAimer =
|
|||||||
|
|
||||||
proc forward*(aimer: var BinaryAimer, input: BitVec80): float =
|
proc forward*(aimer: var BinaryAimer, input: BitVec80): float =
|
||||||
## Kernel regression: weighted circular mean over active exemplars.
|
## Kernel regression: weighted circular mean over active exemplars.
|
||||||
|
## Weights by similarity^2 and exponential recency decay (0.95^age).
|
||||||
## Returns angle in [0,360) degrees, or -1.0 sentinel when cold (no weight).
|
## Returns angle in [0,360) degrees, or -1.0 sentinel when cold (no weight).
|
||||||
var sinSum = 0.0
|
var sinSum = 0.0
|
||||||
var cosSum = 0.0
|
var cosSum = 0.0
|
||||||
@@ -37,7 +38,9 @@ proc forward*(aimer: var BinaryAimer, input: BitVec80): float =
|
|||||||
sim += popcount(input[w] and aimer.exemplars[i].pattern[w]).int
|
sim += popcount(input[w] and aimer.exemplars[i].pattern[w]).int
|
||||||
let excess = sim - MIN_SIM
|
let excess = sim - MIN_SIM
|
||||||
if excess <= 0: continue
|
if excess <= 0: continue
|
||||||
let weight = float(excess * excess)
|
let age = (aimer.nextSlot - 1 - i + MAX_K) mod MAX_K
|
||||||
|
let recency = pow(0.95, age.float)
|
||||||
|
let weight = float(excess * excess) * recency
|
||||||
let rad = degToRad(aimer.exemplars[i].angle)
|
let rad = degToRad(aimer.exemplars[i].angle)
|
||||||
sinSum += weight * sin(rad)
|
sinSum += weight * sin(rad)
|
||||||
cosSum += weight * cos(rad)
|
cosSum += weight * cos(rad)
|
||||||
|
|||||||
Reference in New Issue
Block a user