/** * @copyright Sister Software * @license AGPL-3.0 * @author Teffen Ellis, et al. * * Linear-chain CRF Viterbi decoder in TypeScript. * * Replaces per-token argmax in the classifier when transition scores are available. Mirrors the * Python training-time / eval-time path so JS runtime decode agrees with the model card's * metrics. * * Two transition matrix modes: * * 1. **Structural-only** (no weights changes required) — build from the BIO label vocabulary using * `buildBIOTransitionMask()`. Forbids `O → I-X`, `B-X → I-Y` (X ≠ Y), and sequence-start → * `I-X`. Permits everything else. This alone prevents orphan-I decoding ("Saint Petersburg → * Petersburg" bug) at runtime — a strict improvement over argmax. * 2. **Learned** (requires a future weights release that ships `crf-transitions.json`) — load the * trained transition matrix from the model card. Adds learned soft priors on top of the * structural mask. Currently not exported from the training-side ONNX bundle. */ /** * Build the BIO structural transition mask given the label vocabulary in order. * * Rules: * * - `X → O` always permitted (0) * - `X → B-Y` always permitted (0) * - `X → I-Y` permitted only if `X` is `B-Y` or `I-Y` (0); otherwise -inf * * Returns a `numLabels × numLabels` matrix where `mask[from][to]` is the additive log-score (0 for permitted, NEG_INF * for forbidden). */ export declare function buildBIOTransitionMask(labels: readonly string[]): number[][]; /** * Returns the per-label vector of valid start-of-sequence transitions (0 or -inf). */ export declare function buildBIOStartMask(labels: readonly string[]): number[]; /** * End-of-sequence transitions. By default all labels are valid endings (returns zeros). Override if the trained model * has learned end transitions. */ export declare function buildBIOEndMask(labels: readonly string[]): number[]; /** * A position-scoped transition bonus (TRANSITION-BETA build, 2026-07-24): `+bonus` on every transition INTO `toLabel` * at exactly `timestep` — from ANY predecessor label (at `timestep === 0` the "predecessor" is the sequence start, so * the bonus lands on the start transition instead). The placetype-pair prior emits one per pair hit at the child span's * first piece when its index header carries `transitionBeta`; the hook itself is generic — a sparse list of * adjustments, no knowledge of who produced them. * * Because the bonus is predecessor-independent, it cannot change WHICH predecessor wins for `toLabel` at `timestep` — * it changes whether paths ENTERING `toLabel` there outscore paths that stay fused through a competing run (the task-8 * probe's path-fusion mechanism: a locally-winning emission bias can still lose globally when the forced * `I-`/fresh-`B-` continuation costs more than the local win recovers; a transition-entry bonus pays that structural * toll directly). */ interface ViterbiTransitionAdjustment { /** * Timestep whose INCOMING transition is adjusted. */ timestep: number; /** * Label index (into the emission row / transition matrix axes) the adjusted transition lands on. */ toLabel: number; /** * Additive bonus (log-score units, like the transition matrix itself). */ bonus: number; } export interface ViterbiInput { /** * `emissions[t][k]` — log-emission for label k at timestep t. Pass raw logits or log-softmaxes. */ emissions: number[][]; /** * `transitions[from][to]` — additive log-score. Use `buildBIOTransitionMask` if unsure. */ transitions: number[][]; /** * Per-label log-score for being the FIRST label. */ startTransitions?: number[]; /** * Per-label log-score for being the LAST label. */ endTransitions?: number[]; /** * Position-scoped transition bonuses (see {@link ViterbiTransitionAdjustment}). Omitted/empty = the exact * pre-TRANSITION-BETA decode — no behavioral term is added anywhere. */ transitionAdjustments?: ReadonlyArray; } export interface ViterbiResult { /** * Best label index per timestep. */ path: number[]; /** * Total path score (log-prob). */ score: number; } /** * Viterbi decode: find the highest-scoring label sequence under the CRF. * * Time: O(seq_len × num_labels²). Space: O(seq_len × num_labels) for the backpointer table. */ export declare function viterbi(input: ViterbiInput): ViterbiResult; /** * Convenience: argmax over per-token softmax (existing behavior). Provided so callers can opt in to Viterbi only when * transitions are available, falling back to this cleanly. */ export declare function perTokenArgmax(emissions: readonly number[][]): number[]; /** * Softmax of a logit row (returns probabilities summing to 1). * * Used to compute per-token confidence after Viterbi picks the label sequence — the confidence is the softmax * probability of the Viterbi-chosen label at that timestep. */ export declare function softmax(row: readonly number[]): number[]; export {}; //# sourceMappingURL=viterbi.d.ts.map