nx_ngram.nx
buildroot/runtime/nx_ngram.nx
about
nx_ngram.nx -- n-gram extraction + frequency + dispersion.
Second brick of the corpus-linguistics S-class substrate per cardinal
feedback-corpus-linguistics-s-class-substrate-sketch-engine-displacement.
=== What this primitive answers ====================================
Given a stream of token IDs and N (unigram / bigram / trigram / ...),
produce:
- extraction of every n-gram in the stream
- hash-interned IDs for each n-gram (FNV-1a over the token-ID sequence)
- frequency count per n-gram
- dispersion: how evenly the n-gram is distributed across the corpus
(Juilland's D — close to 1 = uniform, close to 0 = clumped)
- top-K most-frequent extraction
=== Composition ====================================================
nx_string_ops.nx (nx_str_hash_fnv1a) -- token-sequence interning
nx_essentials.nx (nx_log2_floor) -- log2 for dispersion
nx_tier.nx -- nx_int alias
=== Sealed-enum frequency bands ====================================
Per dual-reading cardinal: every primitive emits BOTH a quantitative
count AND a qualitative sealed-enum band derived from log-rank.
log2(freq) buckets:
0..3 -> SINGLETON_RARE (hapax / once or twice)
3..7 -> RARE (3-127)
7..12 -> COMMON (128-4095)
12.. -> VERY_COMMON (4096+)
=== Dispersion bands ===============================================
Juilland's D in Q10:
0..256 -> CLUMPED (very uneven; <25% uniform)
256..614 -> MODERATELY_SPREAD
614..870 -> WELL_SPREAD
870..1024 -> EVEN
dependencies 1 imports · 3 importers
imports: nx_string_ops.nx
imported by: nx_ngram_test.nxnx_word_sketch.nxnx_word_sketch_test.nx
structs
| none |
consts
| 58 | const NX_MAGIC_4096: i64 = 4096 |
| 60 | const NX_NG_Q: nx_int = 1024 // Q10 fixed-point base |
| 64 | const NX_NG_FREQ_SINGLETON_RARE: nx_int = 0 // freq <= 7 |
| 65 | const NX_NG_FREQ_RARE: nx_int = 1 // 8..127 |
| 66 | const NX_NG_FREQ_COMMON: nx_int = 2 // 128..4095 |
| 67 | const NX_NG_FREQ_VERY_COMMON: nx_int = 3 // 4096+ |
| 68 | const NX_NG_FREQ_N_BANDS: nx_int = 4 |
| 85 | const NX_NG_DISP_CLUMPED: nx_int = 0 // D < 0.25 |
| 86 | const NX_NG_DISP_MODERATELY_SPREAD: nx_int = 1 // D < 0.60 |
| 87 | const NX_NG_DISP_WELL_SPREAD: nx_int = 2 // D < 0.85 |
| 88 | const NX_NG_DISP_EVEN: nx_int = 3 // D >= 0.85 |
| 89 | const NX_NG_DISP_N_BANDS: nx_int = 4 |
functions
| 70 | func nx_ng_freq_band_is_valid(b: nx_int) -> nx_int called by 1: main |
| 76 | func nx_ng_classify_freq(freq: nx_int) -> nx_int called by 1: main |
| 91 | func nx_ng_disp_band_is_valid(b: nx_int) -> nx_int called by 1: main |
| 97 | func nx_ng_classify_disp(d_q10: nx_int) -> nx_int called by 1: main |
| 116 | func nx_ng_hash(tokens: *i64, n: nx_int) -> nx_int |
| 147 | func nx_ng_extract(stream: *i64, stream_len: nx_int, n: nx_int, |
| 193 | func nx_ng_count(hashes: *i64, n_hashes: nx_int, called by 1: main |
| 234 | func nx_ng_lookup(h: nx_int, called by 1: main |
| 263 | func _ng_isqrt(n: nx_int) -> nx_int called by 1: nx_ng_dispersion_q10 |
| 283 | func nx_ng_dispersion_q10(parts: *i64, k: nx_int) -> nx_int |
| 325 | func nx_ng_top_k(table_keys: *i64, table_counts: *i64, cap: nx_int, called by 1: main |