ggml: add block_dt3, the dual-plane ternary block

DT3 stores w_i = d[0]*t0_i + d[1]*t1_i with t in {-1,0,+1}, two ternary
planes over a 128-element block: 56 bytes, 3.5 bpw exactly.

Each plane uses the tq1_0 base-3 packing with every constant halved for
the smaller block (qs 48->24 B, qh 4->2 B, qs passes over 16 then 8
bytes instead of 32 then 16), which tiles 128 with no leftover bytes.
Reducing tq1_0 to 128 without halving the passes does not tile: with a
24-byte qs the first pass covers nothing and the second overruns.
This commit is contained in:
Millaguie
2026-08-10 23:33:13 +02:00
parent 030ebb558a
commit 5c175d940f
+20
View File
@@ -287,6 +287,26 @@ typedef struct {
} block_tq2_0;
static_assert(sizeof(block_tq2_0) == sizeof(ggml_half) + QK_K / 4, "wrong tq2_0 block size/padding");
//
// Dual-plane ternary quantization (DT3)
//
// w_i = d[0]*t0_i + d[1]*t1_i, with t in {-1, 0, +1}. Two ternary planes buy
// back most of the quality a single one loses, at 3.5 bpw instead of 1.6875.
//
// Each plane is packed exactly like tq1_0 with every constant halved, since the
// block is 128 elements instead of QK_K: qs 48 -> 24 bytes, qh 4 -> 2 bytes,
// and the two qs passes go over 16 and then 8 bytes instead of 32 and 16.
//
#define QK_DT3 128
// 3.5 bpw
typedef struct {
uint8_t qs[2][(QK_DT3 - 4 * QK_DT3 / 64) / 5]; // 2 planes, 5 elements per byte (3^5 = 243 < 256)
uint8_t qh[2][QK_DT3 / 64]; // 2 planes, 4 elements per byte
ggml_half d[2]; // one scale per plane
} block_dt3;
static_assert(sizeof(block_dt3) == 2 * (sizeof(ggml_half) + QK_DT3 / 64 + (QK_DT3 - 4 * QK_DT3 / 64) / 5), "wrong dt3 block size/padding");
//
// Super-block quantization structures
//