use scirs2_core::ndarray::Array1;
use scirs2_core::numeric::{Float, FromPrimitive};
use std::fmt::Debug;
use crate::error::{Result, TimeSeriesError};
#[derive(Debug, Clone)]
pub struct DecompositionResult<F> {
pub trend: Array1<F>,
pub seasonal: Array1<F>,
pub residual: Array1<F>,
pub original: Array1<F>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DecompositionModel {
Additive,
Multiplicative,
}
pub(crate) fn box_cox_transform<F>(ts: &Array1<F>, lambda: f64) -> Result<Array1<F>>
where
F: Float + FromPrimitive + Debug,
{
let lambda_f = F::from_f64(lambda).ok_or_else(|| TimeSeriesError::InvalidParameter {
name: "lambda".to_string(),
message: "Failed to convert lambda to type F".to_string(),
})?;
let zero = F::zero();
let one = F::one();
if (lambda - 0.0).abs() < 1e-10 {
let result = ts.mapv(|x| {
if x <= zero {
return zero; }
x.ln()
});
Ok(result)
} else {
let result = ts.mapv(|x| {
if x <= zero {
return zero; }
(x.powf(lambda_f) - one) / lambda_f
});
Ok(result)
}
}
#[allow(dead_code)]
pub(crate) fn inverse_box_cox<F>(ts: &Array1<F>, lambda: f64) -> Result<Array1<F>>
where
F: Float + FromPrimitive + Debug,
{
let lambda_f = F::from_f64(lambda).ok_or_else(|| TimeSeriesError::InvalidParameter {
name: "lambda".to_string(),
message: "Failed to convert lambda to type F".to_string(),
})?;
let one = F::one();
if (lambda - 0.0).abs() < 1e-10 {
let result = ts.mapv(|x| x.exp());
Ok(result)
} else {
let result = ts.mapv(|x| (x * lambda_f + one).powf(one / lambda_f));
Ok(result)
}
}
pub(crate) fn min<T: Ord>(a: T, b: T) -> T {
if a < b {
a
} else {
b
}
}