core/generate/salience.py
Shay aadaf11612
Add ADR-0008 salience attention
Add salience and attention operators, wire salience-gated candidate selection into generation, expose vault/salience trace telemetry, and add tests proving non-placeholder salience behavior.
2026-05-13 22:40:36 -07:00

52 lines
1.9 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
import numpy as np
from algebra.backend import cga_inner
from field.state import FieldState
from vocab.manifold import VocabManifold
@dataclass(frozen=True, slots=True)
class SalienceMap:
indices: np.ndarray
scores: np.ndarray
budget: int
def __post_init__(self) -> None:
object.__setattr__(self, "indices", np.asarray(self.indices, dtype=np.int64).copy())
object.__setattr__(self, "scores", np.asarray(self.scores, dtype=np.float32).copy())
object.__setattr__(self, "budget", int(self.budget))
class SalienceOperator:
"""
Compute geometric salience of manifold points relative to current FieldState.
Salience is field-relative CGA activation:
salience(v_i) = |cga_inner(F, v_i)| / (||F|| * ||v_i||)
No learned weights. No softmax. Pure geometry routed through algebra.backend,
which uses core_rs when active.
"""
def compute(self, field: FieldState, vocab: VocabManifold, top_k: int = 16) -> SalienceMap:
if top_k <= 0:
return SalienceMap(indices=np.asarray([], dtype=np.int64), scores=np.asarray([], dtype=np.float32), budget=0)
if len(vocab) == 0:
return SalienceMap(indices=np.asarray([], dtype=np.int64), scores=np.asarray([], dtype=np.float32), budget=0)
query = np.asarray(field.F, dtype=np.float32)
query_norm = max(float(np.linalg.norm(query)), 1e-8)
scores: list[float] = []
for idx in range(len(vocab)):
v = vocab.get_versor_at(idx)
denom = query_norm * max(float(np.linalg.norm(v)), 1e-8)
scores.append(abs(float(cga_inner(query, v))) / denom)
scores_arr = np.asarray(scores, dtype=np.float32)
k = min(int(top_k), len(vocab))
order = np.argsort(-scores_arr, kind="stable")[:k]
return SalienceMap(indices=order.astype(np.int64), scores=scores_arr[order], budget=k)