Expand description
N-gram embedding id math — LongCat-Flash-Lite / Qwen3.8-Flash-Next family.
Host-side, kernel-independent core of the n-gram embedding path (arxiv
2601.21204): the polynomial-rolling-hash ids that select rows in the
K * (N-1) giant lookup tables. Split from the (future) GPU module so
the integer math has a pure unit-test surface — the Rust ids are checked
BIT-EXACT against the Python reference via
bench/ngram_ref/ngram_id_fixtures.json (generated by
bench/ngram_ref/make_fixtures.py from the line-faithful numpy port of
the HF modeling_longcat_ngram.py).
Mechanism (table index = (i-2)*K + j for n-gram size i, split j):
T = ratio * vocab_size + 2*index + 1 (table row count)
mods = [V^1 mod T, V^2 mod T, ..., V^(i-1) mod T]
id_t = ( x_t + Σ_{d=1..i-1} shift_d(x)_t * mods[d-1] ) mod Twhere shift_d is a right-shift by d that RESETS at document
boundaries: a position within d tokens of a segment start (segments
end at an EOS token, inclusive) contributes token id 0 instead of
crossing the boundary. Ids depend ONLY on token ids — never on hidden
state — which is what makes the lookups deterministic, prefetchable and
speculative-decode-friendly.
Overflow contract: x * mod < 2^17 * 2^24 < 2^41 and at most N-1 terms
accumulate, so the running sum fits comfortably in i64/u64 WITHOUT
intermediate reduction at LongCat scale (V=131072, T≈10.2M). The
per-term products must still be computed in 64-bit — 32-bit would
overflow — and mods themselves must be built with 64-bit modmul.
Structs§
- Ngram
Dims - The n-gram trio + derived dims, extracted from
ModelConfig. - Ngram
Embedding - GPU n-gram embedding: base word embedding fused with the K*(N-1)
hashed-table lookups, composed entirely from existing kernels
(
batched_embedgathers +dense_gemm_bf16_pipelinedprojections +bf16_scaled_addaccumulation). A fused single-kernel version is a later optimization; per-token cost here is 1+T gathers, T tiny GEMMs and T+1 scaled adds (T = 12 for LongCat-Lite) — negligible next to a
Enums§
- Ngram
Table - One n-gram lookup table on device: BF16 as shipped, or FP8-quantized at load (per-row E4M3 + f32 scale — halves the ~63 GB table footprint; embeddings tolerate this well and the gather dequantizes on read).
Functions§
- ngram_
ids - Compute the row ids for EVERY table over
ctx(the n-1 cached context tokens followed by the new tokens). Returnsnum_tablesvectors ofctx.len()ids each, table-major in reference index order ((ngram-2)*K + split); callers slice the lastseq_lenentries.