use std::collections::BTreeMap;
use std::path::Path;
use crate::FOCR_MODEL_LICENSE_NOTICE;
use crate::error::{FocrError, FocrResult};
use crate::native_engine::model_arch;
use super::int4::VALID_GROUP_SIZES;
pub const FOCRQ_MAGIC: &[u8; 6] = b"FOCRQ\0";
pub const FOCRQ_FORMAT_VERSION: u32 = 1;
const ALIGN: usize = 64;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WriteDType {
F32,
F16,
Bf16,
QInt8PerChan,
QInt4PerGroup,
}
impl WriteDType {
#[must_use]
fn as_json_str(self) -> &'static str {
match self {
WriteDType::F32 => "F32",
WriteDType::F16 => "F16",
WriteDType::Bf16 => "BF16",
WriteDType::QInt8PerChan => "QInt8PerChan",
WriteDType::QInt4PerGroup => "QInt4PerGroup",
}
}
#[must_use]
fn is_quantized(self) -> bool {
matches!(self, WriteDType::QInt8PerChan | WriteDType::QInt4PerGroup)
}
fn expected_byte_len(self, name: &str, shape: &[usize], numel: usize) -> FocrResult<usize> {
match self {
WriteDType::F32 => checked_mul(name, numel, 4, "shape*dtype bytes"),
WriteDType::F16 | WriteDType::Bf16 => checked_mul(name, numel, 2, "shape*dtype bytes"),
WriteDType::QInt8PerChan => Ok(numel),
WriteDType::QInt4PerGroup => {
if !numel.is_multiple_of(2) {
return Err(FocrError::FormatMismatch(format!(
"tensor {name:?}: QInt4 shape {shape:?} has odd element count {numel}"
)));
}
Ok(numel / 2)
}
}
}
}
fn checked_numel(name: &str, shape: &[usize]) -> FocrResult<usize> {
shape.iter().copied().try_fold(1usize, |acc, dim| {
acc.checked_mul(dim).ok_or_else(|| {
FocrError::FormatMismatch(format!(
"tensor {name:?}: shape {shape:?} element count overflows usize"
))
})
})
}
fn checked_mul(name: &str, lhs: usize, rhs: usize, expression: &str) -> FocrResult<usize> {
lhs.checked_mul(rhs).ok_or_else(|| {
FocrError::FormatMismatch(format!(
"tensor {name:?}: {expression} overflows usize ({lhs} * {rhs})"
))
})
}
#[derive(Debug, Clone)]
struct PendingTensor {
dtype: WriteDType,
shape: Vec<usize>,
data: Vec<u8>,
scales: Vec<u8>,
group_size: usize,
tier: u8,
}
impl PendingTensor {
#[allow(dead_code)]
fn numel(&self) -> usize {
self.shape
.iter()
.copied()
.fold(1usize, usize::saturating_mul)
}
}
#[derive(Debug, Clone)]
pub struct FocrqBuilder {
arch_target: u8,
source_sha256: [u8; 32],
license_notice: String,
provenance_json: Option<String>,
model_config_json: Option<String>,
packing_manifest_json: Option<String>,
model_id: Option<String>,
align: bool,
tensors: BTreeMap<String, PendingTensor>,
}
impl Default for FocrqBuilder {
fn default() -> Self {
Self::new()
}
}
impl FocrqBuilder {
#[must_use]
pub fn new() -> Self {
Self {
arch_target: 0,
source_sha256: [0u8; 32],
license_notice: FOCR_MODEL_LICENSE_NOTICE.to_string(),
provenance_json: None,
model_config_json: None,
packing_manifest_json: None,
model_id: None,
align: false,
tensors: BTreeMap::new(),
}
}
#[must_use]
pub fn with_arch_target(mut self, arch: u8) -> Self {
self.arch_target = arch;
self
}
#[must_use]
pub fn with_source_sha256(mut self, sha: [u8; 32]) -> Self {
self.source_sha256 = sha;
self
}
#[must_use]
pub fn with_license_notice(mut self, notice: impl Into<String>) -> Self {
self.license_notice = notice.into();
self
}
#[must_use]
pub fn with_provenance_json(mut self, json: impl Into<String>) -> Self {
self.provenance_json = Some(json.into());
self
}
#[must_use]
pub fn with_model_config_json(mut self, json: impl Into<String>) -> Self {
self.model_config_json = Some(json.into());
self
}
#[must_use]
pub fn with_packing_manifest_json(mut self, json: impl Into<String>) -> Self {
self.packing_manifest_json = Some(json.into());
self
}
#[must_use]
pub fn with_model_id(mut self, id: impl Into<String>) -> Self {
self.model_id = Some(id.into());
self
}
#[must_use]
pub fn with_alignment(mut self, on: bool) -> Self {
self.align = on;
self
}
pub fn add_tensor(
&mut self,
name: impl Into<String>,
dtype: WriteDType,
shape: Vec<usize>,
bytes: Vec<u8>,
) -> FocrResult<()> {
let name = name.into();
if dtype.is_quantized() {
return Err(FocrError::FormatMismatch(format!(
"add_tensor: {name:?} is a quantized dtype {:?}; use add_quantized",
dtype
)));
}
self.insert_checked(name, dtype, shape, bytes, Vec::new(), 0, 0)
}
#[allow(clippy::too_many_arguments)]
pub fn add_quantized(
&mut self,
name: impl Into<String>,
dtype: WriteDType,
shape: Vec<usize>,
data: Vec<u8>,
scales: Vec<u8>,
group_size: usize,
tier: u8,
) -> FocrResult<()> {
let name = name.into();
if !dtype.is_quantized() {
return Err(FocrError::FormatMismatch(format!(
"add_quantized: {name:?} dtype {:?} is not quantized; use add_tensor",
dtype
)));
}
self.insert_checked(name, dtype, shape, data, scales, group_size, tier)
}
#[allow(clippy::too_many_arguments)]
fn insert_checked(
&mut self,
name: String,
dtype: WriteDType,
shape: Vec<usize>,
data: Vec<u8>,
scales: Vec<u8>,
group_size: usize,
tier: u8,
) -> FocrResult<()> {
if self.tensors.contains_key(&name) {
return Err(FocrError::FormatMismatch(format!(
"add tensor: duplicate name {name:?}"
)));
}
let numel = checked_numel(&name, &shape)?;
let expected =
if self.arch_target == 1 && dtype == WriteDType::QInt8PerChan && shape.len() == 2 {
crate::simd::pack::smmla_packed_len(shape[0], shape[1])
} else {
dtype.expected_byte_len(&name, &shape, numel)?
};
if data.len() != expected {
return Err(FocrError::FormatMismatch(format!(
"tensor {name:?}: data len {} != shape×dtype {} ({:?}, shape {:?})",
data.len(),
expected,
dtype,
shape
)));
}
Self::validate_scales(&name, dtype, &shape, &scales, group_size, tier)?;
self.tensors.insert(
name,
PendingTensor {
dtype,
shape,
data,
scales,
group_size,
tier,
},
);
Ok(())
}
fn validate_scales(
name: &str,
dtype: WriteDType,
shape: &[usize],
scales: &[u8],
group_size: usize,
tier: u8,
) -> FocrResult<()> {
match dtype {
WriteDType::F32 | WriteDType::F16 | WriteDType::Bf16 => {
if !scales.is_empty() || group_size != 0 || tier != 0 {
return Err(FocrError::FormatMismatch(format!(
"tensor {name:?}: high-precision tensors must not carry quant metadata"
)));
}
}
WriteDType::QInt8PerChan => {
let [n, _k] = shape else {
return Err(FocrError::FormatMismatch(format!(
"tensor {name:?}: QInt8 shape must be rank-2 [n,k], got {shape:?}"
)));
};
if group_size != 0 || tier != 0 {
return Err(FocrError::FormatMismatch(format!(
"tensor {name:?}: QInt8 group_size and tier must be zero"
)));
}
let expected = checked_mul(name, *n, 4, "qint8 n*f32 scale bytes")?;
if scales.len() != expected {
return Err(FocrError::FormatMismatch(format!(
"tensor {name:?}: scale bytes {} != qint8 n*f32 {}",
scales.len(),
expected
)));
}
}
WriteDType::QInt4PerGroup => {
let [n, k] = shape else {
return Err(FocrError::FormatMismatch(format!(
"tensor {name:?}: QInt4 shape must be rank-2 [n,k], got {shape:?}"
)));
};
if !VALID_GROUP_SIZES.contains(&group_size) {
return Err(FocrError::FormatMismatch(format!(
"tensor {name:?}: QInt4 group_size {group_size} must be 16 or 32"
)));
}
if !k.is_multiple_of(2) {
return Err(FocrError::FormatMismatch(format!(
"tensor {name:?}: QInt4 k {k} must be even"
)));
}
if !k.is_multiple_of(group_size) {
return Err(FocrError::FormatMismatch(format!(
"tensor {name:?}: QInt4 k {k} must be divisible by group_size {group_size}"
)));
}
let groups = k / group_size;
let scale_count = checked_mul(name, *n, groups, "qint4 n*(k/group_size)")?;
let expected = checked_mul(name, scale_count, 4, "qint4 scale_count*f32 bytes")?;
if scales.len() != expected {
return Err(FocrError::FormatMismatch(format!(
"tensor {name:?}: scale bytes {} != qint4 n*(k/group_size)*f32 {}",
scales.len(),
expected
)));
}
}
}
Ok(())
}
#[must_use]
pub fn len(&self) -> usize {
self.tensors.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.tensors.is_empty()
}
#[must_use]
pub fn build(&self) -> Vec<u8> {
let mut payload: Vec<u8> = Vec::new();
let mut records: Vec<(String, TensorLayout)> = Vec::with_capacity(self.tensors.len());
for (name, t) in &self.tensors {
self.maybe_align(&mut payload);
let byte_offset = payload.len();
payload.extend_from_slice(&t.data);
let byte_len = t.data.len();
let (scales_offset, scales_len) = if t.dtype.is_quantized() {
self.maybe_align(&mut payload);
let so = payload.len();
payload.extend_from_slice(&t.scales);
(so, t.scales.len())
} else {
(0usize, 0usize)
};
records.push((
name.clone(),
TensorLayout {
dtype: t.dtype,
shape: t.shape.clone(),
byte_offset,
byte_len,
scales_offset,
scales_len,
group_size: t.group_size,
tier: t.tier,
},
));
}
let header = self.build_header_json(&records);
let header_bytes = header.into_bytes();
let mut blob = Vec::with_capacity(51 + header_bytes.len() + payload.len());
blob.extend_from_slice(FOCRQ_MAGIC);
blob.extend_from_slice(&FOCRQ_FORMAT_VERSION.to_le_bytes());
blob.push(self.arch_target);
blob.extend_from_slice(&self.source_sha256);
blob.extend_from_slice(&(header_bytes.len() as u64).to_le_bytes());
blob.extend_from_slice(&header_bytes);
blob.extend_from_slice(&payload);
blob
}
pub fn write(&self, path: &Path) -> FocrResult<()> {
let blob = self.build();
std::fs::write(path, &blob).map_err(|e| {
FocrError::Other(anyhow::anyhow!("writing .focrq to {}: {e}", path.display()))
})
}
fn maybe_align(&self, payload: &mut Vec<u8>) {
if !self.align {
return;
}
let rem = payload.len() % ALIGN;
if rem != 0 {
payload.resize(payload.len() + (ALIGN - rem), 0);
}
}
fn build_header_json(&self, records: &[(String, TensorLayout)]) -> String {
let mut s = String::new();
s.push('{');
s.push_str("\"arch_target\":");
s.push_str(&self.arch_target.to_string());
s.push(',');
s.push_str("\"format_version\":");
s.push_str(&FOCRQ_FORMAT_VERSION.to_string());
s.push(',');
s.push_str("\"license_notice\":");
push_json_string(&mut s, &self.license_notice);
s.push(',');
if let Some(mc) = &self.model_config_json {
s.push_str("\"model_config\":");
s.push_str(mc);
s.push(',');
}
let default_id = model_arch::default_arch().id();
if let Some(id) = self
.model_id
.as_deref()
.filter(|id| !id.is_empty() && *id != default_id)
{
s.push_str("\"model_id\":");
push_json_string(&mut s, id);
s.push(',');
}
if let Some(pm) = &self.packing_manifest_json {
s.push_str("\"packing_manifest\":");
s.push_str(pm);
s.push(',');
}
if let Some(pv) = &self.provenance_json {
s.push_str("\"provenance\":");
s.push_str(pv);
s.push(',');
}
s.push_str("\"source_sha256\":");
push_json_string(&mut s, &hex_encode(&self.source_sha256));
s.push(',');
s.push_str("\"tensors\":{");
for (i, (name, layout)) in records.iter().enumerate() {
if i > 0 {
s.push(',');
}
push_json_string(&mut s, name);
s.push(':');
layout.push_record_json(&mut s);
}
s.push('}');
s.push('}');
s
}
}
struct TensorLayout {
dtype: WriteDType,
shape: Vec<usize>,
byte_offset: usize,
byte_len: usize,
scales_offset: usize,
scales_len: usize,
group_size: usize,
tier: u8,
}
impl TensorLayout {
fn push_record_json(&self, s: &mut String) {
s.push('{');
s.push_str("\"byte_len\":");
s.push_str(&self.byte_len.to_string());
s.push_str(",\"byte_offset\":");
s.push_str(&self.byte_offset.to_string());
s.push_str(",\"dtype\":");
push_json_string(s, self.dtype.as_json_str());
if self.dtype.is_quantized() {
s.push_str(",\"group_size\":");
s.push_str(&self.group_size.to_string());
s.push_str(",\"scales_len\":");
s.push_str(&self.scales_len.to_string());
s.push_str(",\"scales_offset\":");
s.push_str(&self.scales_offset.to_string());
}
s.push_str(",\"shape\":[");
for (i, d) in self.shape.iter().enumerate() {
if i > 0 {
s.push(',');
}
s.push_str(&d.to_string());
}
s.push(']');
if self.dtype.is_quantized() {
s.push_str(",\"tier\":");
s.push_str(&self.tier.to_string());
}
s.push('}');
}
}
fn push_json_string(s: &mut String, value: &str) {
s.push('"');
for ch in value.chars() {
match ch {
'"' => s.push_str("\\\""),
'\\' => s.push_str("\\\\"),
'\n' => s.push_str("\\n"),
'\r' => s.push_str("\\r"),
'\t' => s.push_str("\\t"),
c if (c as u32) < 0x20 => {
s.push_str(&format!("\\u{:04x}", c as u32));
}
c => s.push(c),
}
}
s.push('"');
}
fn hex_encode(bytes: &[u8]) -> String {
use std::fmt::Write;
let mut s = String::with_capacity(bytes.len() * 2);
for &b in bytes {
let _ = write!(s, "{b:02x}");
}
s
}
#[cfg(test)]
mod tests {
use super::*;
use crate::native_engine::weights::{DType, Weights};
use half::bf16;
fn bf16_le(values: &[f32]) -> Vec<u8> {
values
.iter()
.flat_map(|&v| bf16::from_f32(v).to_le_bytes())
.collect()
}
fn f32_le(values: &[f32]) -> Vec<u8> {
values.iter().flat_map(|&v| v.to_le_bytes()).collect()
}
#[test]
fn roundtrips_bf16_tensor_through_reader() {
let vals = [1.0f32, -2.0, 0.5, 3.0, 0.0, -0.25];
let mut b = FocrqBuilder::new()
.with_arch_target(2)
.with_source_sha256([7u8; 32]);
b.add_tensor("w", WriteDType::Bf16, vec![2, 3], bf16_le(&vals))
.unwrap();
let blob = b.build();
let w = Weights::from_bytes(blob).unwrap();
assert!(w.is_focrq());
assert_eq!(w.len(), 1);
assert_eq!(w.arch_target(), 2);
assert_eq!(w.source_sha256(), &"07".repeat(32));
let view = w.tensor("w").unwrap();
assert_eq!(view.dtype, DType::BF16);
assert_eq!(view.shape, &[2, 3]);
let m = w.mat("w").unwrap();
assert_eq!(m.shape(), (2, 3));
assert_eq!(m.data, vals);
}
#[test]
fn roundtrips_f32_tensor_through_reader() {
let vals = [1.5f32, -0.125, 1024.0, -3.0];
let mut b = FocrqBuilder::new();
b.add_tensor("bias", WriteDType::F32, vec![4], f32_le(&vals))
.unwrap();
let w = Weights::from_bytes(b.build()).unwrap();
let m = w.mat("bias").unwrap();
assert_eq!(m.shape(), (1, 4));
assert_eq!(m.data, vals);
}
#[test]
fn roundtrips_two_tensors_by_byte_range() {
let a = [1.0f32, 2.0];
let bb = [9.0f32, 8.0, 7.0];
let mut b = FocrqBuilder::new();
b.add_tensor("a", WriteDType::Bf16, vec![2], bf16_le(&a))
.unwrap();
b.add_tensor("b", WriteDType::F32, vec![3], f32_le(&bb))
.unwrap();
let w = Weights::from_bytes(b.build()).unwrap();
assert_eq!(w.mat("a").unwrap().data, vec![1.0, 2.0]);
assert_eq!(w.mat("b").unwrap().data, vec![9.0, 8.0, 7.0]);
}
#[test]
fn roundtrips_qint8_through_reader() {
let w_bytes: Vec<u8> = [1i8, -2, 3, 4, -5, 6].iter().map(|&v| v as u8).collect();
let scale_bytes = f32_le(&[0.1, 0.2]);
let mut b = FocrqBuilder::new();
b.add_quantized(
"q",
WriteDType::QInt8PerChan,
vec![2, 3],
w_bytes,
scale_bytes,
0,
0,
)
.unwrap();
let w = Weights::from_bytes(b.build()).unwrap();
let q = w.qint8("q").unwrap();
assert_eq!(q.n, 2);
assert_eq!(q.k, 3);
assert_eq!(&q.w[..], &[1i8, -2, 3, 4, -5, 6]);
assert_eq!(q.scales, vec![0.1, 0.2]);
}
#[test]
fn roundtrips_qint4_through_reader() {
let packed: Vec<u8> = (0u8..16).collect();
let scale_bytes = f32_le(&[0.1, 0.2]);
let mut b = FocrqBuilder::new();
b.add_quantized(
"e",
WriteDType::QInt4PerGroup,
vec![2, 16],
packed.clone(),
scale_bytes,
16,
3,
)
.unwrap();
let w = Weights::from_bytes(b.build()).unwrap();
let q = w.qint4("e").unwrap();
assert_eq!(q.n, 2);
assert_eq!(q.k, 16);
assert_eq!(q.group_size, 16);
assert_eq!(q.tier, 3);
assert_eq!(&q.packed[..], &packed[..]);
assert_eq!(q.scales.to_vec(), vec![0.1, 0.2]);
}
#[test]
fn license_notice_survives_roundtrip() {
let mut b = FocrqBuilder::new().with_license_notice(FOCR_MODEL_LICENSE_NOTICE);
b.add_tensor("x", WriteDType::Bf16, vec![1], bf16_le(&[1.0]))
.unwrap();
let w = Weights::from_bytes(b.build()).unwrap();
assert_eq!(w.license_notice(), FOCR_MODEL_LICENSE_NOTICE);
}
#[test]
fn forward_compat_header_fields_are_ignored_by_reader() {
let mut b = FocrqBuilder::new()
.with_provenance_json(r#"{"hf_commit":"abc","source_sha256_hex":"00"}"#)
.with_model_config_json(r#"{"hidden_size":1280,"use_mla":false}"#)
.with_packing_manifest_json(r#"{"quant_recipe":"decoder-ffn-int8-v1"}"#);
b.add_tensor("x", WriteDType::Bf16, vec![2], bf16_le(&[1.0, 2.0]))
.unwrap();
let w = Weights::from_bytes(b.build()).unwrap();
assert_eq!(w.mat("x").unwrap().data, vec![1.0, 2.0]);
}
#[test]
fn written_blob_passes_reader_census() {
let mut b = FocrqBuilder::new();
b.add_tensor("alpha", WriteDType::F32, vec![1], f32_le(&[1.0]))
.unwrap();
b.add_tensor("beta", WriteDType::F32, vec![1], f32_le(&[2.0]))
.unwrap();
let w = Weights::from_bytes(b.build()).unwrap();
assert!(w.census(["alpha", "beta"]).is_ok());
assert!(w.census(["alpha"]).is_err());
}
#[test]
fn build_is_byte_deterministic() {
let make = || {
let mut b = FocrqBuilder::new()
.with_arch_target(1)
.with_source_sha256([5u8; 32]);
b.add_tensor("zeta", WriteDType::Bf16, vec![2], bf16_le(&[3.0, 4.0]))
.unwrap();
b.add_tensor("alpha", WriteDType::F32, vec![2], f32_le(&[1.0, 2.0]))
.unwrap();
b.build()
};
assert_eq!(make(), make());
}
fn got_ocr2_notice() -> &'static str {
crate::native_engine::model_arch::arch_by_id("got-ocr2")
.expect("got-ocr2 is a registered arch")
.license_notice()
}
#[test]
fn model_id_roundtrips_through_reader() {
let mut b = FocrqBuilder::new()
.with_model_id("got-ocr2")
.with_license_notice(got_ocr2_notice());
b.add_tensor("w", WriteDType::Bf16, vec![2], bf16_le(&[1.0, 2.0]))
.unwrap();
let blob = b.build();
let header_text = String::from_utf8_lossy(&blob);
assert!(header_text.contains("\"model_id\":\"got-ocr2\""));
let w = Weights::from_bytes(blob).unwrap();
assert_eq!(w.model_id(), "got-ocr2");
assert_eq!(w.mat("w").unwrap().data, vec![1.0, 2.0]);
}
#[test]
fn default_model_id_is_omitted_and_byte_identical_to_unset() {
let make = |set_default: bool| {
let mut b = FocrqBuilder::new()
.with_arch_target(1)
.with_source_sha256([9u8; 32]);
if set_default {
b = b.with_model_id("unlimited-ocr");
}
b.add_tensor("t", WriteDType::Bf16, vec![2], bf16_le(&[3.0, 4.0]))
.unwrap();
b.build()
};
let unset = make(false);
let set_default = make(true);
assert_eq!(unset, set_default, "default model_id must not change bytes");
assert!(
!String::from_utf8_lossy(&unset).contains("model_id"),
"the default arch must omit the model_id key entirely"
);
let w = Weights::from_bytes(unset).unwrap();
assert_eq!(w.model_id(), "unlimited-ocr");
}
#[test]
fn empty_model_id_is_omitted() {
let mut b = FocrqBuilder::new().with_model_id("");
b.add_tensor("t", WriteDType::F32, vec![1], f32_le(&[1.0]))
.unwrap();
let blob = b.build();
assert!(!String::from_utf8_lossy(&blob).contains("model_id"));
assert_eq!(
Weights::from_bytes(blob).unwrap().model_id(),
"unlimited-ocr"
);
}
#[test]
fn build_with_model_id_is_byte_deterministic() {
let make = || {
let mut b = FocrqBuilder::new()
.with_model_id("got-ocr2")
.with_license_notice(got_ocr2_notice());
b.add_tensor("zeta", WriteDType::Bf16, vec![2], bf16_le(&[3.0, 4.0]))
.unwrap();
b.add_tensor("alpha", WriteDType::F32, vec![2], f32_le(&[1.0, 2.0]))
.unwrap();
b.build()
};
assert_eq!(make(), make());
}
#[test]
fn tensor_emission_order_is_sorted_by_name() {
let mut b = FocrqBuilder::new();
b.add_tensor("zeta", WriteDType::F32, vec![1], f32_le(&[1.0]))
.unwrap();
b.add_tensor("alpha", WriteDType::F32, vec![1], f32_le(&[2.0]))
.unwrap();
b.add_tensor("mid", WriteDType::F32, vec![1], f32_le(&[3.0]))
.unwrap();
let w = Weights::from_bytes(b.build()).unwrap();
let names: Vec<&str> = w.names().collect();
assert_eq!(names, vec!["alpha", "mid", "zeta"]);
}
#[test]
fn write_to_file_and_load_through_reader() {
let vals = [1.0f32, -2.0, 4.0, 8.0];
let mut b = FocrqBuilder::new()
.with_arch_target(1)
.with_source_sha256([3u8; 32]);
b.add_tensor("t", WriteDType::Bf16, vec![2, 2], bf16_le(&vals))
.unwrap();
let path = std::env::temp_dir().join(format!(
"focrq_writer_{}_{}.focrq",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
));
b.write(&path).unwrap();
let w = Weights::load(&path).unwrap();
let m = w.mat("t").unwrap();
assert_eq!(m.shape(), (2, 2));
assert_eq!(m.data, vals);
let _ = std::fs::remove_file(&path);
}
#[test]
fn aligned_payload_still_roundtrips_through_reader() {
let a = [1.0f32, 2.0, 3.0];
let bb = [9.0f32];
let mut b = FocrqBuilder::new().with_alignment(true);
b.add_tensor("a", WriteDType::F32, vec![3], f32_le(&a))
.unwrap();
b.add_tensor("b", WriteDType::Bf16, vec![1], bf16_le(&bb))
.unwrap();
let blob = b.build();
let w = Weights::from_bytes(blob).unwrap();
assert_eq!(w.mat("a").unwrap().data, vec![1.0, 2.0, 3.0]);
assert_eq!(w.mat("b").unwrap().data, vec![9.0]);
}
#[test]
fn int8_quantizer_output_roundtrips_through_writer_and_reader() {
use crate::quant::int8::quantize_int8_f32;
let w = [127.0f32, 0.0, -64.0, 254.0, -254.0, 0.0];
let q = quantize_int8_f32(&w, 2, 3);
let mut b = FocrqBuilder::new();
b.add_quantized(
"expert.down_proj",
WriteDType::QInt8PerChan,
vec![2, 3],
q.weight_bytes(),
q.scale_bytes(),
0,
0,
)
.unwrap();
let weights = Weights::from_bytes(b.build()).unwrap();
let rq = weights.qint8("expert.down_proj").unwrap();
assert_eq!(rq.n, 2);
assert_eq!(rq.k, 3);
assert_eq!(&rq.w[..], &q.q[..]);
assert_eq!(rq.scales, q.scales);
}
#[test]
fn int4_packer_output_roundtrips_through_writer_and_reader() {
use crate::quant::int4::pack_int4_f32;
let vals: Vec<f32> = (0..32).map(|i| (i as f32) - 16.0).collect();
let q = pack_int4_f32(&vals, 1, 32, 16);
let mut b = FocrqBuilder::new();
b.add_quantized(
"expert.up_proj",
WriteDType::QInt4PerGroup,
vec![1, 32],
q.packed_bytes(),
q.scale_bytes(),
16,
4,
)
.unwrap();
let weights = Weights::from_bytes(b.build()).unwrap();
let rq = weights.qint4("expert.up_proj").unwrap();
assert_eq!(rq.n, 1);
assert_eq!(rq.k, 32);
assert_eq!(rq.group_size, 16);
assert_eq!(&rq.packed[..], &q.packed[..]);
assert_eq!(rq.scales.to_vec(), q.scales);
}
#[test]
fn rejects_wrong_byte_len() {
let mut b = FocrqBuilder::new();
let err = b
.add_tensor("x", WriteDType::Bf16, vec![2, 3], vec![0u8; 4])
.unwrap_err();
assert!(matches!(err, FocrError::FormatMismatch(_)));
}
#[test]
fn rejects_shape_product_overflow() {
let mut b = FocrqBuilder::new();
let err = b
.add_tensor("x", WriteDType::Bf16, vec![usize::MAX, 2], Vec::new())
.unwrap_err();
assert!(matches!(err, FocrError::FormatMismatch(_)));
assert!(format!("{err}").contains("element count overflows"));
}
#[test]
fn rejects_byte_len_overflow() {
let mut b = FocrqBuilder::new();
let err = b
.add_tensor("x", WriteDType::F32, vec![usize::MAX / 2 + 1], Vec::new())
.unwrap_err();
assert!(matches!(err, FocrError::FormatMismatch(_)));
assert!(format!("{err}").contains("shape*dtype bytes overflows"));
}
#[test]
fn rejects_qint8_scale_len_mismatch() {
let mut b = FocrqBuilder::new();
let err = b
.add_quantized(
"q",
WriteDType::QInt8PerChan,
vec![2, 3],
vec![0u8; 6],
vec![0u8; 4],
0,
0,
)
.unwrap_err();
assert!(matches!(err, FocrError::FormatMismatch(_)));
assert!(format!("{err}").contains("qint8 n*f32"));
}
#[test]
fn rejects_qint8_nonzero_group_metadata() {
let mut b = FocrqBuilder::new();
let err = b
.add_quantized(
"q",
WriteDType::QInt8PerChan,
vec![1, 2],
vec![0u8; 2],
f32_le(&[1.0]),
16,
0,
)
.unwrap_err();
assert!(matches!(err, FocrError::FormatMismatch(_)));
assert!(format!("{err}").contains("group_size and tier must be zero"));
}
#[test]
fn rejects_qint4_noncanonical_group_size_even_when_it_divides_k() {
let mut b = FocrqBuilder::new();
let err = b
.add_quantized(
"q4",
WriteDType::QInt4PerGroup,
vec![1, 32],
vec![0u8; 16],
f32_le(&[1.0, 1.0, 1.0, 1.0]),
8,
1,
)
.unwrap_err();
assert!(matches!(err, FocrError::FormatMismatch(_)));
assert!(format!("{err}").contains("must be 16 or 32"));
}
#[test]
fn rejects_qint4_scale_len_mismatch() {
let mut b = FocrqBuilder::new();
let err = b
.add_quantized(
"q4",
WriteDType::QInt4PerGroup,
vec![2, 32],
vec![0u8; 32],
vec![0u8; 4],
16,
1,
)
.unwrap_err();
assert!(matches!(err, FocrError::FormatMismatch(_)));
assert!(format!("{err}").contains("qint4 n*(k/group_size)*f32"));
}
#[test]
fn rejects_duplicate_name() {
let mut b = FocrqBuilder::new();
b.add_tensor("x", WriteDType::F32, vec![1], f32_le(&[1.0]))
.unwrap();
let err = b
.add_tensor("x", WriteDType::F32, vec![1], f32_le(&[2.0]))
.unwrap_err();
assert!(matches!(err, FocrError::FormatMismatch(_)));
}
#[test]
fn add_tensor_rejects_quantized_dtype() {
let mut b = FocrqBuilder::new();
let err = b
.add_tensor("x", WriteDType::QInt8PerChan, vec![1], vec![0u8; 1])
.unwrap_err();
assert!(matches!(err, FocrError::FormatMismatch(_)));
}
#[test]
fn add_quantized_rejects_high_precision_dtype() {
let mut b = FocrqBuilder::new();
let err = b
.add_quantized("x", WriteDType::F32, vec![1], vec![0u8; 4], vec![], 0, 0)
.unwrap_err();
assert!(matches!(err, FocrError::FormatMismatch(_)));
}
}