t27.aiРусский

Back to three values

You will learn

How a threshold turns a neuron's sum back into a trit, and why each edge of the dead band needs its own test.

A neuron in a ternary network adds up products of trits, and the sum can be any small integer. quantize in activation_quantizer.t27 squeezes it back: above the threshold it returns 2 (P), below minus the threshold 0 (N), and in between 1 (Z). The on_comb at the end makes it combinational: no register, the output follows the inputs. The browser skips all 7 tests because its runner does not know assert_eq yet; the native t27c runs all 7, all pass, none vacuous. The recording changes > to >= on line 6, so a sum equal to the threshold already counts as P. Exactly one test fails, quantize_boundary_hi, which asks quantize(10, 10) for Z. Every byte in the recording was printed by the command; only the typing is staged.

Try it

In the recording, find the changed line and the test that fails; then in the spec frame find quantize_boundary_lo and work out which one-character change on line 7 it would catch.

Open the interactive lesson →

t27c on activation_quantizer.t27 -- Quantize at the edge, native
t27c on activation_quantizer.t27 -- Quantize at the edge, native ↗

t27c on the t27c lab (Railway), spec at t27 5ff0ec512: 7 tests pass natively; one > in the quantizer becoming >= fails exactly one test, quantize_boundary_hi; git restores the spec.

specs/ternary/activation_quantizer.t27

module ActivationQuantizer;
// Ternary activation quantizer for the BitNet engine: re-ternarize a signed
// accumulator to a packed trit {N=0b00, Z=0b01, P=0b10} using a symmetric
// threshold. v > +t -> P, v < -t -> N, else Z.
pub fn quantize(v: i16, threshold: i16) -> u8 {
    if (v > threshold) { return 2; }
    if (v < -threshold) { return 0; }
    return 1;
}

test quantize_positive { assert_eq(quantize(100, 10), 2); }
test quantize_negative { assert_eq(quantize(-100, 10), 0); }
test quantize_zero_band { assert_eq(quantize(5, 10), 1); }
test quantize_boundary_hi { assert_eq(quantize(10, 10), 1); }
test quantize_boundary_lo { assert_eq(quantize(-10, 10), 1); }
test quantize_just_over { assert_eq(quantize(11, 10), 2); }
test quantize_just_under { assert_eq(quantize(-11, 10), 0); }

// W696: the hardware boundary, DERIVED -- not chosen.
//
// T187 measured an exact equivalence over 617 specs: a module gets a data
// port iff the spec declares `on_comb` or `on_clock`. Without one the
// compiler emits `NO DATA PORTS -- this module cannot move a value across
// its boundary`, and synthesis optimises the whole thing away.
//
// The standing rule is that the default must NOT be guessed. Here no guess
// was made: `t27c entry-points` found exactly ONE function in this spec that
// takes a parameter, returns a value, has a body, and whose types all have a
// known width. With one candidate the choice is forced, so this forwards and
// invents nothing. 11 of 387 port-less specs qualified.
fn on_comb(v: i16, threshold: i16) -> u8 { return quantize(v, threshold); }

endmodule

Open the lesson's spec in the player ↗

All lessons