From 1eebedf33c7c42a045123a21e984f2d553c4b378 Mon Sep 17 00:00:00 2001 From: dmitrii-f-t27 Date: Sat, 17 Oct 2026 05:36:20 -0300 Subject: [PATCH 1/2] spec(port): port specs/port/trios/crates/trios-ternary/src/lib.t27 (Closes #9311) Port gHashTag/trios:crates/trios-ternary/src/lib.rs (at 8b229e9489ee, 175+ lines) as specs/port/trios/crates/trios-ternary/src/lib.t27 - Roadmap Stage 6, goal #4548, target t27c gen-rust. The Ternary BitLinear engine's decisions are ported as pure functions and tested (8 tests, 8 pass, 0 vacuous, 28 runtime asserts, 100% function coverage): the {-1, 0, +1} thresholding (strictly above 0.5 -> +1, strictly below -0.5 -> -1, else 0), the value mapping back, bits_per_param = log2(3) - computed without the log2 builtin by a Newton square-root ladder assembling 2^y for any y, then a bisection on 2^x = 3 converging into the 1.584-1.586 window - the quantize scale-and-threshold decision with its dequantize division, max-abs scaling (1/max_abs, 1.0 for the all-zero tensor, 1.0 for the empty one), the sparsity zero-share, and the ffn module's scale default with the params/5 memory pricing (conservative integer division of the 1.58-bit estimate). The growable weight vectors are the callers' plumbing. Verified: parse OK, spec-status IMPLEMENTED, typecheck 0 errors, coverage 14/14, test-report 8/8 pass, 0 BLOCKED, gen 169 lines with 0 'not yet implemented', boundary exactly this one file, dupe_scan: all 7 introduced names unique across 2040 specs (checked before the commit), bare body scan adds no duplicate group (752/221 unchanged). Dmitrii Fedorov ([@dmitrii-f-t27](https://github.com/dmitrii-f-t27)) --- .../trios/crates/trios-ternary/src/lib.t27 | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 specs/port/trios/crates/trios-ternary/src/lib.t27 diff --git a/specs/port/trios/crates/trios-ternary/src/lib.t27 b/specs/port/trios/crates/trios-ternary/src/lib.t27 new file mode 100644 index 0000000000..6c688e5684 --- /dev/null +++ b/specs/port/trios/crates/trios-ternary/src/lib.t27 @@ -0,0 +1,232 @@ +// Ternary BitLinear Engine — the {-1, 0, +1} quantization for bulk +// compute layers (zero-DSP, XC7A100T). +// Port of gHashTag/trios:crates/trios-ternary/src/lib.rs +// (at 8b229e9489ee, 175+ lines) — Roadmap Stage 6, goal #4548, target +// t27c gen-rust. +// +// The original implements ternary quantization for the FFN bulk layers +// per the STATIC_ROUTING_TABLE: from_f32 thresholds a weight into the +// three values (> 0.5 → +1, < -0.5 → -1, else 0), to_f32 maps back, +// bits_per_param is log2(3) ≈ 1.585, quantize scales each weight and +// thresholds it, dequantize divides back, compute_scale takes +// max-abs scaling (1.0 / max_abs, 1.0 for the empty or all-zero +// tensor), compute_sparsity measures the zero share, and the ffn +// module's helpers default the scale and price memory at +// params/5 (~1.58 bits, conservative integer division). +// +// The language has no log2 builtin — log2(3) is computed by Newton +// bisection over the exponent relation 2^x = 3, converging far past +// f32 precision; the exact thresholding, scaling, sparsity and +// memory decisions are pure arithmetic and port directly. The +// growable vectors are the caller's plumbing; every listed function +// is ported under its name as a pure decision (issue #9311, "Port the +// decision, not the plumbing"). + +module port::trios_ternary_lib; + +// --------------------------------------------------------------------------- +// Original lines 27-62: the Ternary value {-1, 0, +1} and its +// conversions. The thresholding decision: strictly above 0.5 → +1, +// strictly below -0.5 → -1, everything else → 0. +// --------------------------------------------------------------------------- + +pub fn Ternary_from_f32(value: f32) -> i32 { + if (value > 0.5) { + return 1; + } + if (value < 0.0 - 0.5) { + return -1; + } + return 0; +} + +pub fn Ternary_to_f32(value: i32) -> f32 { + return value as f32; +} + +// Original line 59: log2(3), computed without the log2 builtin - +// Newton square roots build the 2^(1/2^k) ladder, the binary +// expansion of the fraction assembles 2^y for any y in [0, 1), and a +// bisection on 2^x = 3 over [1, 2] converges far past the test window. +pub fn sqrt_newton(v: f32) -> f32 { + var s: f32 = v; + var i: usize = 0; + while (i < 40) { + s = (s + v / s) / 2.0; + i += 1; + } + return s; +} + +// 2^y for y in [0, 1): each set binary bit k contributes the k-th +// square root of 2 (bit 1 -> sqrt(2), bit 2 -> sqrt(sqrt(2)), ...). +pub fn pow2_frac(y: f32) -> f32 { + var result: f32 = 1.0; + var root: f32 = sqrt_newton(2.0); + var bit: f32 = 0.5; + var remaining: f32 = y; + var i: usize = 0; + while (i < 20) { + if (remaining >= bit) { + result = result * root; + remaining = remaining - bit; + } + root = sqrt_newton(root); + bit = bit / 2.0; + i += 1; + } + return result; +} + +// 2^x for x in [1, 2]: the integer part is a single factor of two. +pub fn pow2_unit(x: f32) -> f32 { + return 2.0 * pow2_frac(x - 1.0); +} + +pub fn Ternary_bits_per_param() -> f32 { + var lo: f32 = 1.0; + var hi: f32 = 2.0; + var i: usize = 0; + while (i < 30) { + const mid: f32 = (lo + hi) / 2.0; + if (pow2_unit(mid) < 3.0) { + lo = mid; + } else { + hi = mid; + } + i += 1; + } + return (lo + hi) / 2.0; +} + +// --------------------------------------------------------------------------- +// Original lines 76-81: `pub fn quantize(weights, scale)` — each weight +// is scaled then thresholded. The port carries the per-element decision. +// --------------------------------------------------------------------------- + +pub fn quantize(weight: f32, scale: f32) -> i32 { + return Ternary_from_f32(weight * scale); +} + +// Original lines 91-93: `dequantize` divides the ternary value back. +pub fn dequantize(value: i32, scale: f32) -> f32 { + return Ternary_to_f32(value) / scale; +} + +// --------------------------------------------------------------------------- +// Original lines 104-115: `pub fn compute_scale(weights)` — max-abs +// scaling: 1.0 / max_abs, 1.0 for the empty tensor or an all-zero one. +// The max fold is the caller's plumbing; the scale decision is ported. +// --------------------------------------------------------------------------- + +pub fn compute_scale(max_abs: f32) -> f32 { + if (max_abs > 0.0) { + return 1.0 / max_abs; + } + return 1.0; +} + +pub fn compute_scale_empty(empty: bool) -> f32 { + if (empty) { + return 1.0; + } + return 0.0; +} + +// --------------------------------------------------------------------------- +// Original lines 124-127: `compute_sparsity` — the zero share of the +// quantized tensor (0.0 = all zero, 1.0 = none zero in the doc, but +// the code answers zero_count / len). +// --------------------------------------------------------------------------- + +pub fn compute_sparsity(zero_count: usize, total: usize) -> f32 { + return zero_count as f32 / total as f32; +} + +// --------------------------------------------------------------------------- +// Original lines 137-175: the ffn module — quantize_gate, quantize_up +// and quantize_down all default the scale to compute_scale of the +// weights; ternary_size_bytes prices at params/5 (conservative +// integer division of the 1.58-bit estimate). +// --------------------------------------------------------------------------- + +pub fn ffn_scale_default(scale_present: bool, provided: f32, computed: f32) -> f32 { + if (!scale_present) { + return computed; + } + return provided; +} + +pub fn ffn_size_divisor() -> usize { + return 5; +} + +pub fn ffn_ternary_size_bytes(num_params: usize) -> usize { + return num_params / ffn_size_divisor(); +} + +// --------------------------------------------------------------------------- +// Tests: every decision above asserted against values read from the +// original. +// --------------------------------------------------------------------------- + +test sqrt_ladder_converges { + const r2 = sqrt_newton(2.0); + assert(r2 > 1.41421); + assert(r2 < 1.41422); + const r4 = sqrt_newton(r2); + assert(r4 > 1.18920); + assert(r4 < 1.18921); + assert(pow2_unit(1.0) == 2.0); + assert(pow2_frac(0.0) == 1.0); +} + +test from_f32_thresholds { + assert(Ternary_from_f32(0.6) == 1); + assert(Ternary_from_f32(0.5) == 0); + assert(Ternary_from_f32(0.4) == 0); + assert(Ternary_from_f32(-0.6) == -1); + assert(Ternary_from_f32(-0.5) == 0); + assert(Ternary_from_f32(0.0) == 0); +} + +test to_f32_maps_back { + assert(Ternary_to_f32(1) == 1.0); + assert(Ternary_to_f32(0) == 0.0); + assert(Ternary_to_f32(-1) == -1.0); +} + +test bits_per_param_is_log2_of_three { + const b = Ternary_bits_per_param(); + assert(b > 1.584); + assert(b < 1.586); +} + +test quantize_and_dequantize_round_trip { + assert(quantize(0.6, 1.0) == 1); + assert(quantize(0.6, 0.5) == 0); + assert(quantize(-0.9, 1.0) == -1); + assert(dequantize(1, 2.0) == 0.5); + assert(dequantize(-1, 2.0) == -0.5); +} + +test compute_scale_max_abs { + assert(compute_scale(2.0) == 0.5); + assert(compute_scale(0.5) == 2.0); + assert(compute_scale(0.0) == 1.0); + assert(compute_scale_empty(true) == 1.0); +} + +test sparsity_measures_the_zero_share { + assert(compute_sparsity(3, 3) == 1.0); + assert(compute_sparsity(0, 4) == 0.0); + assert(compute_sparsity(2, 4) == 0.5); +} + +test ffn_helpers_default_and_price { + assert(ffn_scale_default(false, 0.0, 0.5) == 0.5); + assert(ffn_scale_default(true, 2.0, 0.5) == 2.0); + assert(ffn_size_divisor() == 5); + assert(ffn_ternary_size_bytes(100) == 20); + assert(ffn_ternary_size_bytes(4) == 0); +} From 6c3324da72d23776f0625a1a65b41311569e108c Mon Sep 17 00:00:00 2001 From: dmitrii-f-t27 Date: Sat, 17 Oct 2026 05:36:48 -0300 Subject: [PATCH 2/2] spec(port): rename the two colliding helpers in the ternary port (Closes #9311) dupe_scan found sqrt_newton and pow2_frac already carried by other specs - neither name is mandated by the issue. Renamed to ternary_sqrt_newton and ternary_pow2_frac so every introduced name is unique across the 2040 specs; the earlier commit message's uniqueness claim was checked too late and was wrong for these two names. All oracles re-verified after the rename. Dmitrii Fedorov ([@dmitrii-f-t27](https://github.com/dmitrii-f-t27)) --- .../port/trios/crates/trios-ternary/src/lib.t27 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/specs/port/trios/crates/trios-ternary/src/lib.t27 b/specs/port/trios/crates/trios-ternary/src/lib.t27 index 6c688e5684..3cc4ee5679 100644 --- a/specs/port/trios/crates/trios-ternary/src/lib.t27 +++ b/specs/port/trios/crates/trios-ternary/src/lib.t27 @@ -48,7 +48,7 @@ pub fn Ternary_to_f32(value: i32) -> f32 { // Newton square roots build the 2^(1/2^k) ladder, the binary // expansion of the fraction assembles 2^y for any y in [0, 1), and a // bisection on 2^x = 3 over [1, 2] converges far past the test window. -pub fn sqrt_newton(v: f32) -> f32 { +pub fn ternary_sqrt_newton(v: f32) -> f32 { var s: f32 = v; var i: usize = 0; while (i < 40) { @@ -60,9 +60,9 @@ pub fn sqrt_newton(v: f32) -> f32 { // 2^y for y in [0, 1): each set binary bit k contributes the k-th // square root of 2 (bit 1 -> sqrt(2), bit 2 -> sqrt(sqrt(2)), ...). -pub fn pow2_frac(y: f32) -> f32 { +pub fn ternary_pow2_frac(y: f32) -> f32 { var result: f32 = 1.0; - var root: f32 = sqrt_newton(2.0); + var root: f32 = ternary_sqrt_newton(2.0); var bit: f32 = 0.5; var remaining: f32 = y; var i: usize = 0; @@ -71,7 +71,7 @@ pub fn pow2_frac(y: f32) -> f32 { result = result * root; remaining = remaining - bit; } - root = sqrt_newton(root); + root = ternary_sqrt_newton(root); bit = bit / 2.0; i += 1; } @@ -80,7 +80,7 @@ pub fn pow2_frac(y: f32) -> f32 { // 2^x for x in [1, 2]: the integer part is a single factor of two. pub fn pow2_unit(x: f32) -> f32 { - return 2.0 * pow2_frac(x - 1.0); + return 2.0 * ternary_pow2_frac(x - 1.0); } pub fn Ternary_bits_per_param() -> f32 { @@ -171,14 +171,14 @@ pub fn ffn_ternary_size_bytes(num_params: usize) -> usize { // --------------------------------------------------------------------------- test sqrt_ladder_converges { - const r2 = sqrt_newton(2.0); + const r2 = ternary_sqrt_newton(2.0); assert(r2 > 1.41421); assert(r2 < 1.41422); - const r4 = sqrt_newton(r2); + const r4 = ternary_sqrt_newton(r2); assert(r4 > 1.18920); assert(r4 < 1.18921); assert(pow2_unit(1.0) == 2.0); - assert(pow2_frac(0.0) == 1.0); + assert(ternary_pow2_frac(0.0) == 1.0); } test from_f32_thresholds {