use crate::Quantize;
use std::ops::Range;
pub trait Linear {
type Type;
fn range() -> Range<f64>;
fn q_max() -> Self::Type;
}
impl<L: Linear> Quantize for L
where
<L as Linear>::Type: Into<f64> + TryFrom<u64> + Copy,
{
type Type = L::Type;
fn quantize(value: f64) -> Self::Type {
quantize(value, Self::range(), Self::q_max())
}
fn dequantize(quantized: Self::Type) -> f64 {
dequantize(quantized, Self::range(), Self::q_max())
}
fn max_error() -> f64 {
max_error(Self::range(), Self::q_max().into())
}
}
pub fn quantize<T>(value: f64, range: Range<f64>, q_max: T) -> T
where
T: Into<f64> + TryFrom<u64> + Copy,
{
let normalized = ((value - range.start) / (range.end - range.start)).clamp(0.0, 1.0);
let q_max: f64 = q_max.into();
let v = ((q_max + 1.0) * normalized).min(q_max) as u64;
match v.try_into() {
Ok(v) => v,
Err(_) => panic!("{v} not convertible to T"),
}
}
pub fn dequantize<T>(quantized: T, range: Range<f64>, q_max: T) -> f64
where
T: Into<f64> + Copy,
{
let quantized = quantized.into();
let q_max = q_max.into();
range.start + (range.end - range.start) * quantized / q_max
}
pub fn max_error(range: Range<f64>, q_max: f64) -> f64 {
(range.end - range.start) / (q_max + 1.0)
}