// SPDX-License-Identifier: Apache-2.0
; specs/widgets/nn-positions.t27 -- sinusoidal positional encoding: stripes and clocks
; Source of truth for public/widgets/nn-positions/ (gHashTag/trinity): scripts/widget-pages-from-spec.mjs
; compiles this file, checks its constants, evaluates the tests below and writes the page; the page
; hands every constant to tool.js as window.T27_WIDGET. tool.js holds no English and NO FORMULA of
; its own: every value it draws comes from public/widgets/nn-positions/logic.js -- the fn bodies of
; gHashTag/t27 specs/ml/transformer/positional_encoding.t27 compiled to wasm, beside its copy logic.t27.
; Lesson 25 of the course neural-networks. ASCII only (L3), English only (LANG-EN).
; Numbers are integers (the schema reads no float): a K_ name ending in _C is in hundredths.

; WHAT IT DOES: the reader drags the position from 0 to 200. Every stripe, hand and value is pe(pos,
; dim) of the spec at d_model 8; the speeds are inv_freq(pair, 8).

; WHAT IT DOES NOT CLAIM: d_model 8 shows the pattern; a real model uses hundreds of dimensions, and
; many now learn or rotate positions instead.
; phi^2 + 1/phi^2 = 3 | TRINITY

module widget_nn_positions;

pub const KIND : str = "widget-tool";
pub const ID : str = "nn-positions";
pub const TITLE : str = "Positional encoding: how a transformer knows word order";
pub const DESCRIPTION : str = "Every position gets 8 numbers, sines and cosines at frequencies falling by 10 per pair. Drag the position: the fast clock spins, the slow ones barely move, and the stripes show all 48 rows.";
pub const IMAGE_ALT : str = "Positional-encoding card at position 5: four clocks with coloured hands, the fastest turned far round, the slowest still pointing up. Below, a stripe chart of 48 positions by 8 dimensions in pink and green: the left columns flicker fast, the right ones barely change. Tiles read the 8 values and the 4 speeds 1, 0.1, 0.01, 0.001.";
pub const HOOK : str = "Position 5 is (-0.959, 0.284, 0.479, 0.878, 0.050, 0.999, 0.005, 1.000). Four clocks at speeds 1, 0.1, 0.01 and 0.001 give each position its own reading.";
pub const CATEGORY : str = "compiler";
pub const DATA_SOURCES : [2]str = ["gHashTag/t27 specs/ml/transformer/positional_encoding.t27 (t27 master 239b4b059): every value on the page is its fn bodies, compiled to wasm (logic.js)", "Course 10 of t27.ai, neural-networks (gHashTag/trinity#1695): lesson 25 opens this widget"];
pub const READS_LOCAL_FILES : bool = false;
pub const SENDS_NOTHING : bool = true;

pub const K_CARD_WIDTH : u16 = 1200;
pub const K_CARD_HEIGHT : u16 = 630;

; --- Numbers: ranges, presets, and fixtures the spec holds (held equal by the tests below)
pub const K_D_MODEL : u8 = 8;
pub const K_ROWS : u8 = 48;
pub const K_POS_HI : u8 = 200;
pub const K_PRESET_POS : [4]u8 = [5, 0, 1, 37];
pub const K_START_PRESET : u8 = 0;

; --- Words on screen ------------------------------------------------------------------------
pub const SAY_PRESETS_LABEL : str = "Start from";
pub const SAY_PRESET_NAMES : [4]str = ["Position 5", "Position 0", "Position 1", "Position 37"];
pub const SAY_ASK : str = "Attention sees a set of words. How does it know their order?";
pub const SAY_POS : str = "position";
pub const SAY_STRIPES_LABEL : str = "pe(pos, dim) for positions 0 to 47 (rows) and the 8 dimensions";
pub const SAY_CLOCKS_LABEL : str = "Each sin and cos pair as a clock hand, and its speed";
pub const SAY_PAIR : str = "pair";
pub const SAY_VECTOR : str = "the 8 numbers";
pub const SAY_FAST : str = "fastest pair";
pub const SAY_SLOW : str = "slowest pair";
pub const SAY_FREQS : str = "speeds";
pub const SAY_NOTE : str = "A shift by k positions turns every clock by its own fixed angle, so the distance between two positions is visible to a dot product. Position 0 is (0, 1, 0, 1, ...).";
pub const SAY_SOURCE : str = "Logic: t27 spec ml/transformer/positional_encoding.t27, compiled";

test the_card_is_the_share_size {
    assert K_CARD_WIDTH == 1200;
    assert K_CARD_HEIGHT == 630;
    assert K_CARD_WIDTH * 21 == K_CARD_HEIGHT * 40;
}

test eight_dimensions_four_clocks {
    assert K_D_MODEL == 8;
    assert K_D_MODEL % 2 == 0;
}

test the_presets_stay_in_range {
    assert K_PRESET_POS[3] < K_ROWS;
    assert K_PRESET_POS[1] == 0;
    assert K_POS_HI > K_ROWS;
}
