1use crate::quant::{f16_to_f32, f32_to_f16};
25
26pub const BLR_MAGIC: u8 = 0x4C;
27pub const BLR_VERSION: u8 = 1;
28pub const BLR_HEADER: usize = 16;
29
30#[derive(Clone, Copy, Debug, PartialEq, Eq)]
32pub struct BlrHeader {
33 pub paths: usize,
34 pub rank: usize,
35 pub d_out: usize,
36 pub d_in: usize,
37}
38
39#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41pub struct BlrPathOffsets {
42 pub h: usize,
43 pub g: usize,
44 pub l: usize,
45 pub u: usize,
46 pub v: usize,
47}
48
49pub fn blr_path_bytes(d_out: usize, d_in: usize, r: usize) -> usize {
51 2 * (d_out + d_in + r) + d_out * (r / 8) + r * (d_in / 8)
52}
53
54pub fn blr_payload_len(paths: usize, r: usize, d_out: usize, d_in: usize) -> usize {
56 BLR_HEADER + paths * blr_path_bytes(d_out, d_in, r)
57}
58
59pub fn blr_bits(d_out: usize, d_in: usize, r: usize, paths: usize) -> u64 {
62 paths as u64 * (r as u64 * (d_out + d_in) as u64 + 16 * (d_out + d_in) as u64 + 16 * r as u64)
63}
64
65pub fn blr_rank(d_out: usize, d_in: usize, b: f64, paths: usize, mult: f64) -> usize {
69 let (m, n) = (d_out as f64, d_in as f64);
70 let s = if paths == 2 {
71 (b * m * n - 32.0 * (m + n)) / (2.0 * (m + n + 16.0))
72 } else {
73 (b * m * n - 16.0 * (m + n)) / (m + n + 16.0)
74 };
75 let r = ((s * mult / 8.0).floor() * 8.0).max(8.0) as usize;
76 let cap = (d_out.min(d_in) / 8) * 8;
77 r.min(cap.max(8))
78}
79
80pub fn blr_parse_header(bytes: &[u8]) -> Result<BlrHeader, String> {
82 if bytes.len() < BLR_HEADER {
83 return Err(format!("blr payload {} bytes < 16-byte header", bytes.len()));
84 }
85 if bytes[0] != BLR_MAGIC {
86 return Err(format!("blr magic {:#04x} != 0x4c", bytes[0]));
87 }
88 if bytes[1] != BLR_VERSION {
89 return Err(format!("blr version {} unsupported (want 1)", bytes[1]));
90 }
91 let paths = bytes[2] as usize;
92 if !(1..=2).contains(&paths) {
93 return Err(format!("blr paths {paths} not in {{1,2}}"));
94 }
95 if bytes[3] != 0 {
96 return Err("blr reserved byte must be 0".into());
97 }
98 let rd = |o: usize| u32::from_le_bytes(bytes[o..o + 4].try_into().unwrap()) as usize;
99 Ok(BlrHeader {
100 paths,
101 rank: rd(4),
102 d_out: rd(8),
103 d_in: rd(12),
104 })
105}
106
107pub fn blr_path_offsets(h: &BlrHeader, p: usize) -> BlrPathOffsets {
109 let base = BLR_HEADER + p * blr_path_bytes(h.d_out, h.d_in, h.rank);
110 let hh = base;
111 let g = hh + 2 * h.d_out;
112 let l = g + 2 * h.d_in;
113 let u = l + 2 * h.rank;
114 let v = u + h.d_out * (h.rank / 8);
115 BlrPathOffsets { h: hh, g, l, u, v }
116}
117
118pub fn validate_blr(shape: &[usize], bytes: &[u8]) -> Result<BlrHeader, String> {
121 if shape.len() != 2 {
122 return Err(format!("blr tensor must be 2-D, got {shape:?}"));
123 }
124 let h = blr_parse_header(bytes)?;
125 if h.d_out != shape[0] || h.d_in != shape[1] {
126 return Err(format!(
127 "blr header dims {}x{} != shape {shape:?}",
128 h.d_out, h.d_in
129 ));
130 }
131 if h.d_out == 0 || h.d_in == 0 || h.d_in % 8 != 0 {
132 return Err(format!(
133 "blr d_in {} must be a positive multiple of 8",
134 h.d_in
135 ));
136 }
137 if h.rank < 8 || h.rank % 8 != 0 || h.rank > h.d_out.min(h.d_in) {
138 return Err(format!(
139 "blr rank {} must be a multiple of 8 in [8, min({}, {})]",
140 h.rank, h.d_out, h.d_in
141 ));
142 }
143 let want = blr_payload_len(h.paths, h.rank, h.d_out, h.d_in);
144 if bytes.len() != want {
145 return Err(format!(
146 "blr payload length {} != computed {want} (P {} r {} {}x{})",
147 bytes.len(),
148 h.paths,
149 h.rank,
150 h.d_out,
151 h.d_in
152 ));
153 }
154 Ok(h)
155}
156
157pub fn blr_f16s(bytes: &[u8], off: usize, n: usize) -> Vec<f32> {
159 (0..n)
160 .map(|i| {
161 f16_to_f32(u16::from_le_bytes([
162 bytes[off + 2 * i],
163 bytes[off + 2 * i + 1],
164 ]))
165 })
166 .collect()
167}
168
169#[inline]
170fn bit(bytes: &[u8], off: usize, idx: usize) -> bool {
171 (bytes[off + idx / 8] >> (idx % 8)) & 1 == 1
172}
173
174pub fn dequant_blr(bytes: &[u8], rows: usize, cols: usize, dst: &mut [f32]) -> Result<(), String> {
176 let h = validate_blr(&[rows, cols], bytes)?;
177 if dst.len() != rows * cols {
178 return Err(format!("blr dst len {} != {}", dst.len(), rows * cols));
179 }
180 dst.iter_mut().for_each(|v| *v = 0.0);
181 let r = h.rank;
182 let mut vg = vec![0f32; r * cols];
183 for p in 0..h.paths {
184 let o = blr_path_offsets(&h, p);
185 let hv = blr_f16s(bytes, o.h, rows);
186 let gv = blr_f16s(bytes, o.g, cols);
187 let lv = blr_f16s(bytes, o.l, r);
188 for k in 0..r {
189 let row = &mut vg[k * cols..(k + 1) * cols];
190 for j in 0..cols {
191 let s = if bit(bytes, o.v + k * (cols / 8), j) {
192 1.0
193 } else {
194 -1.0
195 };
196 row[j] = s * gv[j];
197 }
198 }
199 let mut acc = vec![0f32; cols];
200 for i in 0..rows {
201 acc.iter_mut().for_each(|v| *v = 0.0);
202 for k in 0..r {
203 let s = if bit(bytes, o.u + i * (r / 8), k) {
204 lv[k]
205 } else {
206 -lv[k]
207 };
208 let src = &vg[k * cols..(k + 1) * cols];
209 for j in 0..cols {
210 acc[j] += s * src[j];
211 }
212 }
213 let d = &mut dst[i * cols..(i + 1) * cols];
214 for j in 0..cols {
215 d[j] += hv[i] * acc[j];
216 }
217 }
218 }
219 Ok(())
220}
221
222pub struct BlrPathIn<'a> {
225 pub h: &'a [f32],
226 pub g: &'a [f32],
227 pub l: &'a [f32],
228 pub su: &'a [bool],
229 pub sv: &'a [bool],
230}
231
232pub fn encode_blr(d_out: usize, d_in: usize, r: usize, paths: &[BlrPathIn]) -> Vec<u8> {
235 assert!(matches!(paths.len(), 1 | 2));
236 assert!(r % 8 == 0 && r >= 8 && d_in % 8 == 0);
237 let mut out = Vec::with_capacity(blr_payload_len(paths.len(), r, d_out, d_in));
238 out.push(BLR_MAGIC);
239 out.push(BLR_VERSION);
240 out.push(paths.len() as u8);
241 out.push(0);
242 out.extend_from_slice(&(r as u32).to_le_bytes());
243 out.extend_from_slice(&(d_out as u32).to_le_bytes());
244 out.extend_from_slice(&(d_in as u32).to_le_bytes());
245 for p in paths {
246 assert_eq!(p.h.len(), d_out);
247 assert_eq!(p.g.len(), d_in);
248 assert_eq!(p.l.len(), r);
249 assert_eq!(p.su.len(), d_out * r);
250 assert_eq!(p.sv.len(), d_in * r);
251 for v in p.h.iter().chain(p.g).chain(p.l) {
252 out.extend_from_slice(&f32_to_f16(*v).to_le_bytes());
253 }
254 for i in 0..d_out {
255 for kb in 0..r / 8 {
256 let mut b = 0u8;
257 for t in 0..8 {
258 if p.su[i * r + kb * 8 + t] {
259 b |= 1 << t;
260 }
261 }
262 out.push(b);
263 }
264 }
265 for k in 0..r {
266 for jb in 0..d_in / 8 {
267 let mut b = 0u8;
268 for t in 0..8 {
269 if p.sv[(jb * 8 + t) * r + k] {
270 b |= 1 << t;
271 }
272 }
273 out.push(b);
274 }
275 }
276 }
277 debug_assert_eq!(out.len(), blr_payload_len(paths.len(), r, d_out, d_in));
278 out
279}
280
281#[cfg(test)]
282mod tests {
283 use super::*;
284
285 struct Rng(u64);
286 impl Rng {
287 fn next(&mut self) -> u64 {
288 self.0 = self.0.wrapping_add(0x9E3779B97F4A7C15);
289 let mut z = self.0;
290 z = (z ^ (z >> 30)).wrapping_mul(0xBF58476D1CE4E5B9);
291 z = (z ^ (z >> 27)).wrapping_mul(0x94D049BB133111EB);
292 z ^ (z >> 31)
293 }
294 fn f(&mut self) -> f32 {
295 (self.next() >> 40) as f32 / (1u64 << 24) as f32
296 }
297 }
298
299 #[test]
300 fn rank_rule_anchors() {
301 assert_eq!(blr_rank(4096, 4096, 0.55, 2, 1.0), 544);
302 assert_eq!(blr_rank(4096, 11008, 0.10, 2, 1.0), 128);
303 assert_eq!(blr_rank(2048, 1024, 1.0, 2, 1.0), 320);
305 assert_eq!(blr_rank(1024, 1024, 1.0, 2, 1.0), 232);
306 assert_eq!(blr_rank(3072, 1024, 1.0, 2, 1.0), 360);
307 assert_eq!(blr_rank(2048, 1024, 0.55, 2, 1.0), 168);
308 assert_eq!(blr_rank(1024, 1024, 0.55, 2, 1.0), 120);
309 assert_eq!(blr_rank(1024, 3072, 0.55, 2, 1.0), 192);
310 assert_eq!(blr_rank(1024, 1024, 0.55, 2, 4.0), 488);
311 assert_eq!(blr_rank(1024, 1024, 0.1, 2, 1.0), 8);
312 assert_eq!(blr_rank(64, 64, 8.0, 2, 1.0), 64);
314 let b = blr_bits(4096, 4096, 544, 2) as f64 / (4096.0 * 4096.0);
315 assert!((b - 0.5479).abs() < 1e-4, "{b}");
316 }
317
318 fn random_paths(
319 rng: &mut Rng,
320 d_out: usize,
321 d_in: usize,
322 r: usize,
323 p: usize,
324 ) -> Vec<(Vec<f32>, Vec<f32>, Vec<f32>, Vec<bool>, Vec<bool>)> {
325 (0..p)
326 .map(|_| {
327 let h: Vec<f32> = (0..d_out).map(|_| 0.5 + rng.f()).collect();
328 let g: Vec<f32> = (0..d_in).map(|_| 0.5 + rng.f()).collect();
329 let l: Vec<f32> = (0..r).map(|_| 0.01 + 0.1 * rng.f()).collect();
330 let su: Vec<bool> = (0..d_out * r).map(|_| rng.next() & 1 == 1).collect();
331 let sv: Vec<bool> = (0..d_in * r).map(|_| rng.next() & 1 == 1).collect();
332 (h, g, l, su, sv)
333 })
334 .collect()
335 }
336
337 #[test]
338 fn encode_dequant_roundtrip() {
339 let mut rng = Rng(7);
340 for &(d_out, d_in, r, p) in &[
341 (24usize, 16usize, 8usize, 1usize),
342 (40, 32, 16, 2),
343 (16, 48, 16, 2),
344 ] {
345 let ps = random_paths(&mut rng, d_out, d_in, r, p);
346 let ins: Vec<BlrPathIn> = ps
347 .iter()
348 .map(|(h, g, l, su, sv)| BlrPathIn { h, g, l, su, sv })
349 .collect();
350 let bytes = encode_blr(d_out, d_in, r, &ins);
351 assert_eq!(bytes.len(), blr_payload_len(p, r, d_out, d_in));
352 let mut w = vec![0f32; d_out * d_in];
353 dequant_blr(&bytes, d_out, d_in, &mut w).unwrap();
354 let q = |x: f32| f16_to_f32(f32_to_f16(x));
355 for i in 0..d_out {
356 for j in 0..d_in {
357 let mut want = 0f64;
358 for (h, g, l, su, sv) in &ps {
359 let mut s = 0f64;
360 for k in 0..r {
361 let a = if su[i * r + k] { 1.0 } else { -1.0 };
362 let b = if sv[j * r + k] { 1.0 } else { -1.0 };
363 s += a * b * q(l[k]) as f64;
364 }
365 want += q(h[i]) as f64 * q(g[j]) as f64 * s;
366 }
367 let got = w[i * d_in + j] as f64;
368 assert!(
369 (got - want).abs() <= 1e-5 * (1.0 + want.abs()),
370 "{i},{j}: {got} vs {want}"
371 );
372 }
373 }
374 }
375 }
376
377 #[test]
378 fn validate_rejects_each_field() {
379 let mut rng = Rng(3);
380 let (d_out, d_in, r) = (32usize, 32usize, 16usize);
381 let ps = random_paths(&mut rng, d_out, d_in, r, 2);
382 let ins: Vec<BlrPathIn> = ps
383 .iter()
384 .map(|(h, g, l, su, sv)| BlrPathIn { h, g, l, su, sv })
385 .collect();
386 let good = encode_blr(d_out, d_in, r, &ins);
387 assert!(validate_blr(&[d_out, d_in], &good).is_ok());
388 assert!(validate_blr(&[d_out, d_in + 8], &good).is_err());
389 assert!(validate_blr(&[d_out * d_in], &good).is_err());
390 assert!(validate_blr(&[d_out, d_in], &good[..good.len() - 1]).is_err());
391 let mut long = good.clone();
392 long.push(0);
393 assert!(validate_blr(&[d_out, d_in], &long).is_err());
394 assert!(validate_blr(&[d_out, d_in], &good[..10]).is_err());
395 let set = |at: usize, v: u8| {
396 let mut b = good.clone();
397 b[at] = v;
398 b
399 };
400 assert!(validate_blr(&[d_out, d_in], &set(0, 0x4D)).is_err()); assert!(validate_blr(&[d_out, d_in], &set(1, 2)).is_err()); assert!(validate_blr(&[d_out, d_in], &set(2, 3)).is_err()); assert!(validate_blr(&[d_out, d_in], &set(2, 1)).is_err()); assert!(validate_blr(&[d_out, d_in], &set(3, 1)).is_err()); assert!(validate_blr(&[d_out, d_in], &set(4, 12)).is_err()); assert!(validate_blr(&[d_out, d_in], &set(4, 40)).is_err()); assert!(validate_blr(&[d_out, d_in], &set(8, 33)).is_err()); assert!(validate_blr(&[d_out, d_in], &set(12, 33)).is_err()); }
410
411 #[test]
415 fn generic_codec_entry_points_handle_blr() {
416 use crate::format::TensorEntry;
417 use crate::types::TensorDtype;
418 let mut rng = Rng(5);
419 let (d_out, d_in, r) = (48usize, 64usize, 16usize);
420 let ps = random_paths(&mut rng, d_out, d_in, r, 2);
421 let ins: Vec<BlrPathIn> = ps
422 .iter()
423 .map(|(h, g, l, su, sv)| BlrPathIn { h, g, l, su, sv })
424 .collect();
425 let bytes = encode_blr(d_out, d_in, r, &ins);
426 let d = TensorDtype::BinaryLowRank;
427 assert_eq!(TensorDtype::from_id(19), Some(d));
428 assert_eq!(d.id(), 19);
429 assert_eq!(d.name(), "blr");
430 assert!(d.is_supported());
431 assert_eq!(crate::quant::expected_nbytes(d, &[d_out, d_in]), None);
432 assert!(crate::quant::validate_payload(d, &[d_out, d_in], &bytes).is_ok());
433 assert!(crate::quant::validate_payload(d, &[d_out, d_in], &bytes[1..]).is_err());
434 let entry = TensorEntry {
435 name: "model.layers.0.mlp.down_proj.weight".into(),
436 dtype: d,
437 shape: vec![d_out, d_in],
438 off: 0,
439 nbytes: bytes.len() as u64,
440 shard: 0,
441 hash: 0,
442 };
443 let mut a = vec![0f32; d_out * d_in];
444 let mut b = vec![0f32; d_out * d_in];
445 crate::quant::dequant_tensor(&entry, &bytes, &mut a).unwrap();
446 dequant_blr(&bytes, d_out, d_in, &mut b).unwrap();
447 assert_eq!(a, b);
448 }
449}