use num_complex::{Complex32, Complex64};
use tenferro_tensor::{DType, Error, Result, Tensor};
fn invalid_factor(op: &'static str, message: String) -> Error {
Error::invalid_argument(op, "factor", message)
}
fn finite_real_factor(value: f64) -> Result<f64> {
if value.is_finite() {
Ok(value)
} else {
Err(invalid_factor(
"scale_real",
format!("real scalar must be finite, got {value}"),
))
}
}
fn round_real_to_i64(value: f64) -> Result<i64> {
let rounded = finite_real_factor(value)?.round();
if rounded < i64::MIN as f64 || rounded >= -(i64::MIN as f64) {
return Err(invalid_factor(
"scale_real",
format!("rounded real scalar {rounded} is out of i64 range"),
));
}
Ok(rounded as i64)
}
fn round_real_to_i32(value: f64) -> Result<i32> {
let rounded = round_real_to_i64(value)?;
i32::try_from(rounded).map_err(|_| {
invalid_factor(
"scale_real",
format!("rounded real scalar {rounded} is out of i32 range"),
)
})
}
pub fn real_scale_scalar(dtype: DType, factor: f64) -> Result<Tensor> {
match dtype {
DType::F64 => Tensor::from_vec_col_major(vec![], vec![factor]),
DType::F32 => Tensor::from_vec_col_major(vec![], vec![factor as f32]),
DType::I32 => Tensor::from_vec_col_major(vec![], vec![round_real_to_i32(factor)?]),
DType::I64 => Tensor::from_vec_col_major(vec![], vec![round_real_to_i64(factor)?]),
DType::Bool => Tensor::from_vec_col_major(vec![], vec![finite_real_factor(factor)? != 0.0]),
DType::C64 => Tensor::from_vec_col_major(vec![], vec![Complex64::new(factor, 0.0)]),
DType::C32 => Tensor::from_vec_col_major(vec![], vec![Complex32::new(factor as f32, 0.0)]),
DType::External(_) => Err(Error::invalid_argument(
"scale_real",
"dtype",
"an externally defined scalar has no scale factor",
)),
}
}
pub fn complex_scale_scalar(dtype: DType, factor: Complex64) -> Result<Tensor> {
match dtype {
DType::C64 => Tensor::from_vec_col_major(vec![], vec![factor]),
DType::C32 => Tensor::from_vec_col_major(
vec![],
vec![Complex32::new(factor.re as f32, factor.im as f32)],
),
dtype => Err(Error::invalid_argument(
"scale_complex",
"dtype",
format!("requires complex tensor dtype, got {dtype:?}"),
)),
}
}