Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions specs/port/trios/crates/trios-model/src/lib.t27
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
// trios-model (M) — the IGLA-GF16 hybrid-precision model architecture
// (Φ5.1).
// Port of gHashTag/trios:crates/trios-model/src/lib.rs
// (at 8b229e9489ee, 250+ lines) — Roadmap Stage 6, goal #4548, target
// t27c gen-rust.
//
// The original is the hybrid precision model: GF16 for the critical
// layers (embedding, attention QKV, FFN down — representation learning,
// attention fragility, projection precision) and Ternary for the bulk
// compute layers (FFN gate, FFN up — zero-DSP, massive expansion), per
// the STATIC_ROUTING_TABLE. `new` builds the model empty; `forward` is
// the documented stub answering no logits until the full pass lands;
// `load_weights` replaces all five layers; `num_parameters` sums the
// five; `size_bytes` prices the quantization — GF16 at 2 bytes per
// parameter, Ternary at ~0.2 bytes (the byte count divided by 5); and
// Default delegates to new.
//
// The weight vectors are growable — the caller's plumbing; the
// decisions — the five-layer routing, the empty start, the stub
// forward, the parameter sum, the size formula with its two rates, and
// the default delegation — are ported here as pure functions and
// tested, including the original's own size-window test (issue #9449,
// "Port the decision, not the plumbing").

module port::trios_model_lib;

// ---------------------------------------------------------------------------
// Original lines 50-61: `pub struct IglaModel` — five layers. The
// routing decision is which precision each layer rides.
// ---------------------------------------------------------------------------

pub fn layer_count() -> usize {
return 5;
}

pub fn gf16_layer_count() -> usize {
return 3;
}

pub fn ternary_layer_count() -> usize {
return 2;
}

pub fn layer_precision(layer_index: usize) -> str {
if (layer_index == 0) { return "gf16"; }
if (layer_index == 1) { return "gf16"; }
if (layer_index == 2) { return "ternary"; }
if (layer_index == 3) { return "ternary"; }
if (layer_index == 4) { return "gf16"; }
return "";
}

pub fn layer_name(layer_index: usize) -> str {
if (layer_index == 0) { return "embedding"; }
if (layer_index == 1) { return "attention_qkv"; }
if (layer_index == 2) { return "ffn_gate"; }
if (layer_index == 3) { return "ffn_up"; }
if (layer_index == 4) { return "ffn_down"; }
return "";
}

// ---------------------------------------------------------------------------
// Original lines 77-85: `pub fn new() -> Self` — the empty model: all
// five layers start with no weights; load_weights populates them.
// ---------------------------------------------------------------------------

pub struct ModelWeights {
embedding: usize,
attention_qkv: usize,
ffn_gate: usize,
ffn_up: usize,
ffn_down: usize,
}

pub fn IglaModel_new() -> ModelWeights {
return ModelWeights {
embedding: 0,
attention_qkv: 0,
ffn_gate: 0,
ffn_up: 0,
ffn_down: 0,
};
}

// Original lines 106-113: `pub fn forward(&self, _input)` — the
// documented stub: the full pass (GF16 embedding lookup, GF16 attention,
// Ternary FFN gate/up, GF16 FFN down, GF16 output projection) has not
// landed, so the stub answers no logits.
pub fn IglaModel_forward(input_len: usize) -> usize {
return 0;
}

// Original lines 142-155: `pub fn load_weights(...)` — the five
// replacements; the growable vectors are the caller's plumbing, the
// port carries the loaded counts.
pub fn IglaModel_load_weights(embedding: usize, attention_qkv: usize, ffn_gate: usize, ffn_up: usize, ffn_down: usize) -> ModelWeights {
return ModelWeights {
embedding: embedding,
attention_qkv: attention_qkv,
ffn_gate: ffn_gate,
ffn_up: ffn_up,
ffn_down: ffn_down,
};
}

// Original lines 171-177: `pub fn num_parameters(&self)` — the sum of
// all five layers.
pub fn IglaModel_num_parameters(model: ModelWeights) -> usize {
return model.embedding + model.attention_qkv + model.ffn_gate + model.ffn_up + model.ffn_down;
}

// ---------------------------------------------------------------------------
// Original lines 206-210: `pub fn size_bytes(&self)` — the quantization
// pricing: GF16 at 2 bytes per parameter across its three layers, the
// Ternary pair's byte count divided by 5 (~0.2 bytes, the 1.58-bit
// packing).
// ---------------------------------------------------------------------------

pub fn gf16_bytes_per_parameter() -> usize {
return 2;
}

pub fn ternary_byte_divisor() -> usize {
return 5;
}

pub fn IglaModel_size_bytes(model: ModelWeights) -> usize {
const gf16_params: usize = model.embedding + model.attention_qkv + model.ffn_down;
const ternary_params: usize = model.ffn_gate + model.ffn_up;
return gf16_params * gf16_bytes_per_parameter() + ternary_params / ternary_byte_divisor();
}

// Original lines 213-217: `impl Default` — the delegation to new.
pub fn IglaModel_default() -> ModelWeights {
return IglaModel_new();
}

// ---------------------------------------------------------------------------
// Tests: every decision above asserted against values read from the
// original's own tests (lines 227+), including the 100x5 size window.
// ---------------------------------------------------------------------------

test new_model_is_empty {
const model = IglaModel_new();
assert(IglaModel_num_parameters(model) == 0);
assert(model.embedding == 0);
assert(model.ffn_up == 0);
}

test forward_stub_answers_no_logits {
assert(IglaModel_forward(4) == 0);
assert(IglaModel_forward(0) == 0);
}

test load_weights_carries_the_counts {
const model = IglaModel_load_weights(1, 1, 1, 1, 1);
assert(model.embedding == 1);
assert(model.attention_qkv == 1);
assert(model.ffn_gate == 1);
assert(model.ffn_up == 1);
assert(model.ffn_down == 1);
assert(IglaModel_num_parameters(model) == 5);
}

test num_parameters_sums_all_layers {
const model = IglaModel_load_weights(100, 200, 300, 400, 500);
assert(IglaModel_num_parameters(model) == 1500);
}

test size_bytes_prices_the_quantization {
const balanced = IglaModel_load_weights(100, 100, 100, 100, 100);
const size = IglaModel_size_bytes(balanced);
assert(size > 600);
assert(size < 800);
assert(size == 640);
const empty = IglaModel_size_bytes(IglaModel_new());
assert(empty == 0);
}

test default_delegates_to_new {
const model = IglaModel_default();
assert(IglaModel_num_parameters(model) == 0);
}

test precision_routing_table {
assert(layer_count() == 5);
assert(gf16_layer_count() == 3);
assert(ternary_layer_count() == 2);
assert(layer_precision(0) == "gf16");
assert(layer_precision(1) == "gf16");
assert(layer_precision(2) == "ternary");
assert(layer_precision(3) == "ternary");
assert(layer_precision(4) == "gf16");
assert(layer_name(0) == "embedding");
assert(layer_name(1) == "attention_qkv");
assert(layer_name(2) == "ffn_gate");
assert(layer_name(3) == "ffn_up");
assert(layer_name(4) == "ffn_down");
assert(gf16_bytes_per_parameter() == 2);
assert(ternary_byte_divisor() == 5);
}
Loading