code wiki / _hdl_build / nx_rans.nx

nx_rans.nx source

↩ module page · 132 lines · 5345 B

1// nx_rans.nx -- SOVEREIGN, PATENT-FREE static-frequency rANS entropy coder. The keystone of the 2// patent-free video-codec arc (project-sovereign-patent-free-codec-2026-06-20). rANS = the range 3// variant of Asymmetric Numeral Systems (J. Duda, dedicated to the PUBLIC DOMAIN; the USPTO rejected 4// Google's attempt to patent ANS use, 2018). This is PLAIN static-frequency rANS -- explicitly NOT the 5// Petagene Markov+escape-code variant (US9847791B2) and NOT the Microsoft two-phase / switchable-width 6// / fragment-flush hardware variant (US11234023B2) -- so it reads on no active claim (deep-research 7// verified 2026-06-20). Byte-oriented, 32-bit state in the ryg style (RANS_L = 1<<23, 8-bit 8// renormalization), SCALE_BITS supplied by the caller (12 = a 4096-entry table). 9// LOSSLESS: rans_decode(rans_encode(x)) == x, bit-exact -- the COMPLETE correctness criterion for an 10// entropy stage whose encoder AND decoder we both own (no external interop, so round-trip self-proof 11// is sufficient and total). license_tier: ORIGINAL 12import "nx_syscalls.nx" 13 14// counts[256] <- byte histogram of data[0..n) 15func rans_count(data: *u8, n: i64, counts: *i64) -> i64 { 16 var s: i64 = 0 17 while s < 256 { counts[s] = 0; s = s + 1 } 18 var i: i64 = 0 19 while i < n { let b: i64 = data[i] as i64; counts[b] = counts[b] + 1; i = i + 1 } 20 return 0 21} 22 23// freqs[256] <- counts normalized so sum == (1<<scale_bits); every nonzero count keeps freq >= 1. 24// returns 0 on success, <0 on error (empty input / unfixable). 25func rans_normalize(counts: *i64, freqs: *i64, scale_bits: i64) -> i64 { 26 let M: i64 = 1 << scale_bits 27 var total: i64 = 0 28 var s: i64 = 0 29 while s < 256 { total = total + counts[s]; freqs[s] = 0; s = s + 1 } 30 if total == 0 { return 0 - 1 } 31 var sum: i64 = 0 32 var maxf: i64 = 0 33 var maxs: i64 = 0 34 s = 0 35 while s < 256 { 36 if counts[s] > 0 { 37 var f: i64 = (counts[s] * M) / total 38 if f < 1 { f = 1 } 39 freqs[s] = f 40 sum = sum + f 41 if f > maxf { maxf = f; maxs = s } 42 } 43 s = s + 1 44 } 45 // correct rounding drift by adjusting the most-frequent symbol so the total is exactly M 46 freqs[maxs] = freqs[maxs] + (M - sum) 47 if freqs[maxs] < 1 { return 0 - 2 } 48 return 0 49} 50 51// cum[0..256] = prefix sums of freqs; cum[256] == total (== M). returns total. 52func rans_cum(freqs: *i64, cum: *i64) -> i64 { 53 var c: i64 = 0 54 var s: i64 = 0 55 while s < 256 { cum[s] = c; c = c + freqs[s]; s = s + 1 } 56 cum[256] = c 57 return c 58} 59 60// slot2sym[0..M) = inverse map: each cumulative slot -> its symbol. 61func rans_build_slot2sym(freqs: *i64, cum: *i64, slot2sym: *i64) -> i64 { 62 var s: i64 = 0 63 while s < 256 { 64 if freqs[s] > 0 { 65 var k: i64 = cum[s] 66 let e: i64 = cum[s] + freqs[s] 67 while k < e { slot2sym[k] = s; k = k + 1 } 68 } 69 s = s + 1 70 } 71 return 0 72} 73 74// encode data[0..n) into out (forward-readable); returns encoded length in bytes (or <0 on overflow). 75// rANS encodes in REVERSE symbol order, emitting renorm bytes backward, then flushes the 32-bit state 76// so that the forward byte order is [state b0,b1,b2,b3][renorm bytes] -- exactly what rans_decode reads. 77func rans_encode(data: *u8, n: i64, freqs: *i64, cum: *i64, scale_bits: i64, out: *u8, outcap: i64) -> i64 { 78 let RANS_L: i64 = 1 << 23 79 let tmp: *u8 = sys_mmap(outcap + 16) 80 var ptr: i64 = outcap 81 var x: i64 = RANS_L 82 var i: i64 = n - 1 83 while i >= 0 { 84 let sym: i64 = data[i] as i64 85 let f: i64 = freqs[sym] 86 let start: i64 = cum[sym] 87 let x_max: i64 = ((RANS_L >> scale_bits) << 8) * f 88 while x >= x_max { 89 ptr = ptr - 1 90 if ptr < 0 { return 0 - 1 } 91 tmp[ptr] = (x & 0xff) as u8 92 x = x >> 8 93 } 94 x = ((x / f) << scale_bits) + (x % f) + start 95 i = i - 1 96 } 97 // flush 32-bit state, lowest byte last so forward order is b0,b1,b2,b3 98 ptr = ptr - 1; tmp[ptr] = ((x >> 24) & 0xff) as u8 99 ptr = ptr - 1; tmp[ptr] = ((x >> 16) & 0xff) as u8 100 ptr = ptr - 1; tmp[ptr] = ((x >> 8) & 0xff) as u8 101 ptr = ptr - 1; tmp[ptr] = (x & 0xff) as u8 102 let len: i64 = outcap - ptr 103 var j: i64 = 0 104 while j < len { out[j] = tmp[ptr + j]; j = j + 1 } 105 return len 106} 107 108// decode n symbols from enc[0..enclen) into out[0..n); returns bytes consumed (== enclen for a valid 109// stream). Reads past enclen are guarded (treated as 0) so a corrupted/short stream can't run OOB. 110func rans_decode(enc: *u8, enclen: i64, n: i64, freqs: *i64, cum: *i64, scale_bits: i64, slot2sym: *i64, out: *u8) -> i64 { 111 let RANS_L: i64 = 1 << 23 112 let mask: i64 = (1 << scale_bits) - 1 113 var x: i64 = (enc[0] as i64) | ((enc[1] as i64) << 8) | ((enc[2] as i64) << 16) | ((enc[3] as i64) << 24) 114 var pos: i64 = 4 115 var i: i64 = 0 116 while i < n { 117 let slot: i64 = x & mask 118 let sym: i64 = slot2sym[slot] 119 out[i] = sym as u8 120 let f: i64 = freqs[sym] 121 let start: i64 = cum[sym] 122 x = (f * (x >> scale_bits)) + slot - start 123 while x < RANS_L { 124 var nb: i64 = 0 125 if pos < enclen { nb = enc[pos] as i64 } 126 x = (x << 8) | nb 127 pos = pos + 1 128 } 129 i = i + 1 130 } 131 return pos 132}