1use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6use crate::error::{Result, TurboQuantError};
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
10pub struct ScalarCodebook {
11 pub bits: u8,
12 pub min: f32,
13 pub max: f32,
14}
15
16impl ScalarCodebook {
17 pub fn uniform(bits: u8, min: f32, max: f32) -> Result<Self> {
18 if bits == 0 || bits > 16 {
19 return Err(TurboQuantError::InvalidBitWidth { got: bits });
20 }
21 if !min.is_finite() || !max.is_finite() || min >= max {
22 return Err(TurboQuantError::MalformedCode {
23 reason: "invalid uniform codebook range".into(),
24 });
25 }
26 Ok(Self { bits, min, max })
27 }
28
29 pub fn levels(&self) -> u32 {
30 1u32 << self.bits
31 }
32
33 pub fn quantize(&self, value: f32) -> Result<u16> {
34 if !value.is_finite() {
35 return Err(TurboQuantError::NonFiniteInput { index: 0 });
36 }
37 let levels = self.levels();
38 let clipped = value.clamp(self.min, self.max);
39 let normalized = (clipped - self.min) / (self.max - self.min);
40 let index = (normalized * levels as f32).floor() as u32;
41 Ok(index.min(levels - 1) as u16)
42 }
43
44 pub fn dequantize_midpoint(&self, index: u16) -> Result<f32> {
45 let levels = self.levels();
46 if u32::from(index) >= levels {
47 return Err(TurboQuantError::MalformedCode {
48 reason: format!("codebook index {index} is outside [0, {levels})"),
49 });
50 }
51 let width = (self.max - self.min) / levels as f32;
52 Ok(self.min + (f32::from(index) + 0.5) * width)
53 }
54}