use super::bits::WeightBits;
use super::{TQ19Matrix, MAX_RAW, MIN_RAW};
#[cfg(any(table_format = "q16_16", table_format = "q32_32"))]
#[inline]
fn half_up(num: i128, den: i128) -> i128 {
(2 * num + den) / (2 * den)
}
#[cfg(any(table_format = "q16_16", table_format = "q32_32"))]
const MANTISSA_BITS: i32 = 11;
#[cfg(any(table_format = "q16_16", table_format = "q32_32"))]
#[inline]
fn greater(m: u64, e: i32, mm: u64, me: i32) -> bool {
let gap = e - me;
if gap >= MANTISSA_BITS {
true
} else if gap <= -MANTISSA_BITS {
false
} else if gap >= 0 {
(m << gap) > mm
} else {
m > (mm << -gap)
}
}
#[cfg(any(table_format = "q16_16", table_format = "q32_32"))]
fn row_max(w: &WeightBits, base: usize) -> Result<Option<(u64, i32)>, ()> {
let mut mx: Option<(u64, i32)> = None;
for c in 0..w.cols {
let (_, m, e) = w.decompose(base + c).map_err(|_| ())?;
if m == 0 {
continue;
}
mx = Some(match mx {
None => (m, e),
Some((mm, me)) => {
if greater(m, e, mm, me) { (m, e) } else { (mm, me) }
}
});
}
Ok(mx)
}
#[cfg(any(table_format = "q16_16", table_format = "q32_32"))]
#[inline]
fn row_code(m: u64, e: i32, mm: u64, me: i32, levels: i128) -> i128 {
let d = e - me;
if d <= -64 {
return 0;
}
assert!(d < MANTISSA_BITS, "row_code: element above the row maximum");
let (num, den) = if d >= 0 { ((m as i128) * levels * (1i128 << d), mm as i128) } else { ((m as i128) * levels, (mm as i128) << (-d)) };
half_up(num, den).min(levels)
}
#[cfg(any(table_format = "q16_16", table_format = "q32_32"))]
fn row_scale_q32(n: i128, me: i32, levels: i128) -> Option<u64> {
let sh = me + 32;
if sh > 64 {
return None;
}
let (num, den) = if sh >= 0 { (n << sh, levels) } else { (n, levels << (-sh)) };
u64::try_from(half_up(num, den)).ok()
}
pub fn quantize_tq19(w: &WeightBits) -> Option<TQ19Matrix> {
let total = w.rows * w.cols;
let mut data = Vec::with_capacity(total);
let mut clamped = 0u64;
for i in 0..total {
let scaled = w.tq19_raw(i).ok()?;
if scaled > MAX_RAW as i64 {
data.push(MAX_RAW);
clamped += 1;
} else if scaled < MIN_RAW as i64 {
data.push(MIN_RAW);
clamped += 1;
} else {
data.push(scaled as i16);
}
}
if clamped > (total as u64 / 100) {
return None;
}
Some(TQ19Matrix::new(w.rows, w.cols, data))
}
#[cfg(any(table_format = "q16_16", table_format = "q32_32"))]
pub fn quantize_tq19_rowscaled(w: &WeightBits) -> Option<super::RowScaledTQ19> {
let levels = MAX_RAW as i128;
let mut data = vec![0i16; w.rows * w.cols];
let mut scales_q32 = vec![0u64; w.rows];
for r in 0..w.rows {
let base = r * w.cols;
let (mm, me) = match row_max(w, base).ok()? {
Some(x) => x,
None => continue,
};
for c in 0..w.cols {
let (sign, m, e) = w.decompose(base + c).ok()?;
if m == 0 {
continue;
}
let q = row_code(m, e, mm, me, levels);
data[base + c] = if sign { -(q as i16) } else { q as i16 };
}
scales_q32[r] = row_scale_q32((mm as i128) * super::SCALE as i128, me, levels)?;
}
Some(super::RowScaledTQ19::from_parts(w.rows, w.cols, data, scales_q32))
}
#[cfg(table_format = "q16_16")]
pub fn quantize_tq5_rowscaled(w: &WeightBits) -> Option<super::RowScaledTQ5> {
let levels = super::TQ5_MAX as i128;
let mut data = vec![0i8; w.rows * w.cols];
let mut scales_q32 = vec![0u64; w.rows];
for r in 0..w.rows {
let base = r * w.cols;
let (mm, me) = match row_max(w, base).ok()? {
Some(x) => x,
None => continue,
};
for c in 0..w.cols {
let (sign, m, e) = w.decompose(base + c).ok()?;
if m == 0 {
continue;
}
let q = row_code(m, e, mm, me, levels);
data[base + c] = if sign { -(q as i8) } else { q as i8 };
}
scales_q32[r] = row_scale_q32(mm as i128, me, levels)?;
}
Some(super::RowScaledTQ5::from_parts(w.rows, w.cols, data, scales_q32))
}