use super::qtypes::QuantError;
pub fn quantize_i8_symmetric_f32(input: &[f32], output: &mut [i8]) -> Result<f32, QuantError> {
if input.is_empty() {
return Err(QuantError::Empty);
}
if output.len() < input.len() {
return Err(QuantError::ShapeMismatch);
}
let mut scale_from_contract = 0.0f32;
if crate::engine::try_invoke_gpu_quantize_i8_f32(input, output, &mut scale_from_contract) {
if !scale_from_contract.is_finite() || scale_from_contract <= 0.0 {
return Err(QuantError::InvalidScale);
}
return Ok(scale_from_contract);
}
let mut max_abs = 0.0f32;
for &v in input {
let a = v.abs();
if a > max_abs {
max_abs = a;
}
}
let scale = if max_abs <= 0.0 { 1.0 } else { max_abs / 127.0 };
if !scale.is_finite() || scale <= 0.0 {
return Err(QuantError::InvalidScale);
}
for i in 0..input.len() {
let v = crate::math::roundf(input[i] / scale);
output[i] = v.clamp(-127.0, 127.0) as i8;
}
Ok(scale)
}
pub fn quantize_i8_symmetric(input: &[f32], output: &mut [i8]) -> Result<f32, QuantError> {
quantize_i8_symmetric_f32(input, output)
}
pub fn dequantize_i8_symmetric_f32(
input: &[i8],
output: &mut [f32],
scale: f32,
) -> Result<(), QuantError> {
if input.is_empty() {
return Err(QuantError::Empty);
}
if output.len() < input.len() {
return Err(QuantError::ShapeMismatch);
}
if !scale.is_finite() || scale <= 0.0 {
return Err(QuantError::InvalidScale);
}
if crate::engine::try_invoke_gpu_dequantize_i8_f32(input, output, scale) {
return Ok(());
}
for i in 0..input.len() {
output[i] = input[i] as f32 * scale;
}
Ok(())
}
pub fn dequantize_i8_symmetric(
input: &[i8],
output: &mut [f32],
scale: f32,
) -> Result<(), QuantError> {
dequantize_i8_symmetric_f32(input, output, scale)
}
pub fn dequantize_i8_symmetric_f64(
input: &[i8],
output: &mut [f64],
scale: f64,
) -> Result<(), QuantError> {
if input.is_empty() {
return Err(QuantError::Empty);
}
if output.len() < input.len() {
return Err(QuantError::ShapeMismatch);
}
if !scale.is_finite() || scale <= 0.0 {
return Err(QuantError::InvalidScale);
}
if crate::engine::try_invoke_gpu_dequantize_i8_f64(input, output, scale) {
return Ok(());
}
for i in 0..input.len() {
output[i] = input[i] as f64 * scale;
}
Ok(())
}
pub fn quantize_i8_symmetric_f64(input: &[f64], output: &mut [i8]) -> Result<f64, QuantError> {
if input.is_empty() {
return Err(QuantError::Empty);
}
if output.len() < input.len() {
return Err(QuantError::ShapeMismatch);
}
let mut scale_from_contract = 0.0f64;
if crate::engine::try_invoke_gpu_quantize_i8_f64(input, output, &mut scale_from_contract) {
if !scale_from_contract.is_finite() || scale_from_contract <= 0.0 {
return Err(QuantError::InvalidScale);
}
return Ok(scale_from_contract);
}
let mut max_abs = 0.0f64;
for &v in input {
let a = v.abs();
if a > max_abs {
max_abs = a;
}
}
let scale = if max_abs <= 0.0 { 1.0 } else { max_abs / 127.0 };
if !scale.is_finite() || scale <= 0.0 {
return Err(QuantError::InvalidScale);
}
for i in 0..input.len() {
let v = crate::math::roundd(input[i] / scale);
output[i] = v.clamp(-127.0, 127.0) as i8;
}
Ok(scale)
}