Скалярное произведение из проводов
Вы узнаете
Во что on_comb превращает спеку и как один неверный знак в tmul проявляется ровно в одном тесте.
on_comb в comb_ternary_dot.t27 комбинационный: сгенерированный Verilog подаёт result одним assign без регистра, и выход следует за входами. Он складывает tp по всем 27 дорожкам a и b, а tp вызывает tmul, который возвращает 0, если хоть один трит равен Z, +1 при совпадении и -1 иначе. Поэтому N на N даёт +1, и dot_all_n_x_all_n ждёт 27. Браузер пропускает все 4 теста, потому что пока не знает assert_eq; нативный t27c запускает все 4, все проходят, ни один не пустой. Запись меняет return -1 на return 1 в строке 22, и падает ровно один тест, dot_all_n_x_all_p, — тот, где N стоит против P. Каждый байт в записи напечатала команда; инсценирован только набор текста.
Попробуйте
Найдите в записи изменённую строку tmul и упавший тест; затем найдите в спеке dot_all_n_x_all_n и объясните, почему он ждёт 27, а не -27.

t27c on the t27c lab (Railway), spec at t27 5ff0ec512: 4 tests pass natively; tmul returning +1 for mismatched signs fails exactly one test, dot_all_n_x_all_p; git restores the spec.
specs/ternary/comb_ternary_dot.t27
module CombTernaryDot;
// #1764: a COMBINATIONAL spec-first datapath that synthesizes to real hardware.
//
// `on_comb` is the combinational counterpart of `on_clock`: its parameters
// become input data ports and its return is a continuously-driven `output wire
// result` (`assign result = on_comb(...)`). This is what makes the combinational
// half of the ternary stack real hardware -- without it, a bare `fn` result
// never reaches a module port, so a synthesizer dead-code-eliminates the whole
// design to zero cells (it was only ever exercised by testbenches that call the
// Verilog function hierarchically).
//
// Here `on_comb(a, b)` is the bit-exact 27-trit dot product (the same tmul/tp
// primitives verified vs an independent reference on 300 vectors, #1743). It
// synthesizes to a real Artix-7 LUT tree (yosys synth_xilinx: ~160 LUT6 + a
// CARRY4 reduction, no flip-flops -- pure combinational).
// Sign-only ternary multiply of two packed trits {N=0b00, Z=0b01, P=0b10}.
fn tmul(ta: u8, tb: u8) -> i8 {
if (ta == 1) { return 0; }
if (tb == 1) { return 0; }
if (ta == tb) { return 1; }
return -1;
}
// One trit position i of two 54-bit packed vectors (trit i at [2i+1:2i]).
fn tp(a: u64, b: u64, i: u32) -> i8 {
return tmul(((a >> (i << 1)) & 3) as u8, ((b >> (i << 1)) & 3) as u8);
}
// The combinational data interface: (a, b) input ports -> `result` output port.
fn on_comb(a: u64, b: u64) -> i8 {
return tp(a,b,0) + tp(a,b,1) + tp(a,b,2) + tp(a,b,3) + tp(a,b,4)
+ tp(a,b,5) + tp(a,b,6) + tp(a,b,7) + tp(a,b,8) + tp(a,b,9)
+ tp(a,b,10) + tp(a,b,11) + tp(a,b,12) + tp(a,b,13) + tp(a,b,14)
+ tp(a,b,15) + tp(a,b,16) + tp(a,b,17) + tp(a,b,18) + tp(a,b,19)
+ tp(a,b,20) + tp(a,b,21) + tp(a,b,22) + tp(a,b,23) + tp(a,b,24)
+ tp(a,b,25) + tp(a,b,26);
}
test dot_all_n_x_all_n { assert_eq(on_comb(0, 0), 27); }
test dot_all_n_x_all_p { assert_eq(on_comb(0, 12009599006321322), -27); }
test dot_all_p_x_all_p { assert_eq(on_comb(12009599006321322, 12009599006321322), 27); }
test dot_all_z { assert_eq(on_comb(6004799503160661, 6004799503160661), 0); }
endmodule
Все уроки
Модуль 1 · Лаборатория: наши исследования
Свой формат чисел, честная таблица результатов и таблицы модели, перемноженные на плате.
Модуль 2 · ИИ-числа: блок MX
Как ИИ-чипы хранят веса в нескольких битах: один общий масштаб на блок, сам байт масштаба и что один выброс делает с соседями.
Модуль 3 · Тернарные веса
Веса, которые бывают только минус масштаб, ноль или плюс масштаб, пять правил, которые должен пройти тернарный алфавит, и прогон тестов, который ничего не проверил.
Модуль 4 · Тернарный формат Ternary Network Float
Правило, которое компилятор проверяет до запуска любого теста, и 17-битное число с плавающей точкой, порядок которого — четыре сбалансированных трита.
Модуль 5 · Арифметика чисел со знаком
Умножить два числа со знаком, сложить их, когда знаки разные, и сделать то и другое сразу в умножении с накоплением.
Модуль 6 · Части нейрона
ReLU с изломом в нуле, степень двойки для softmax и argmax, который называет ответ.
Модуль 7 · Обучение на ошибке
Потеря, которая оценивает неверную догадку в битах, один шаг, который сдвигает вес против градиента, и скрытый слой, который нужен XOR.
Модуль 8 · BitNet: тернарные сети
Порог, который сжимает сумму обратно до трёх значений, один нейрон, который становится другой функцией при смене весов, и нейрон, который читает входы по 27 тритов за раз.
Модуль 9 · Тернарный MAC как чип
Скалярное произведение 27 тритов как провода без регистра, та же сумма, которую регистр копит на каждом такте, и небольшая целая сеть в конце курса.