#[inline]
pub fn dot_f32_scalar(q: &[f32], row_bytes: &[u8]) -> f32 {
let mut acc = 0.0f32;
for (i, qv) in q.iter().enumerate() {
let off = i * 4;
let v = f32::from_le_bytes([
row_bytes[off],
row_bytes[off + 1],
row_bytes[off + 2],
row_bytes[off + 3],
]);
acc += *qv * v;
}
acc
}
#[inline]
pub fn dot_f32_f16_scalar(q: &[f32], row_bytes: &[u8]) -> f32 {
let mut acc = 0.0f32;
for (i, qv) in q.iter().enumerate() {
let off = i * 2;
let h = half::f16::from_le_bytes([row_bytes[off], row_bytes[off + 1]]);
acc += *qv * h.to_f32();
}
acc
}
#[inline]
pub fn dot_f32_i8_scalar(q: &[f32], row: &[i8]) -> f32 {
let mut acc = 0.0f32;
for (qv, &iv) in q.iter().zip(row.iter()) {
acc += *qv * (iv as f32);
}
acc
}
#[inline]
fn nib_to_f32(b: u8) -> f32 {
let n = b & 0x0F;
let s = if n & 0x08 != 0 {
(n | 0xF0) as i8
} else {
n as i8
};
s as f32
}
#[inline]
pub fn dot_f32_i4_blocked_scalar(
q: &[f32],
codes: &[u8],
group_scales: &[f32],
dim: usize,
block: usize,
) -> f32 {
let mut acc = 0.0f32;
let _ = dim;
for (g, &scale) in group_scales.iter().enumerate() {
let mut part = 0.0f32;
let base = g * block;
for j in 0..block {
let idx = base + j;
let byte = codes[idx / 2];
let nib = if idx % 2 == 0 { byte } else { byte >> 4 };
part += q[idx] * nib_to_f32(nib);
}
acc += part * scale;
}
acc
}