use ndarray::Array1;
use stochastic_rs_core::simd_rng::Deterministic;
use stochastic_rs_core::simd_rng::SeedExt;
use stochastic_rs_core::simd_rng::Unseeded;
use stochastic_rs_distributions::normal::SimdNormal;
use crate::traits::FloatExt;
use crate::traits::ProcessExt;
#[derive(Debug, Clone)]
pub struct ARp<T: FloatExt, S: SeedExt = Unseeded> {
pub phi: Array1<T>,
pub sigma: T,
pub n: usize,
pub x0: Option<Array1<T>>,
pub seed: S,
}
impl<T: FloatExt> ARp<T> {
pub fn new(phi: Array1<T>, sigma: T, n: usize, x0: Option<Array1<T>>) -> Self {
assert!(sigma > T::zero(), "ARp requires sigma > 0");
if let Some(init) = &x0 {
let required = phi.len().min(n);
assert!(
init.len() >= required,
"ARp requires x0.len() >= min(phi.len(), n) (got {}, need at least {})",
init.len(),
required
);
}
Self {
phi,
sigma,
n,
x0,
seed: Unseeded,
}
}
}
impl<T: FloatExt> ARp<T, Deterministic> {
pub fn seeded(phi: Array1<T>, sigma: T, n: usize, x0: Option<Array1<T>>, seed: u64) -> Self {
assert!(sigma > T::zero(), "ARp requires sigma > 0");
if let Some(init) = &x0 {
let required = phi.len().min(n);
assert!(
init.len() >= required,
"ARp requires x0.len() >= min(phi.len(), n) (got {}, need at least {})",
init.len(),
required
);
}
Self {
phi,
sigma,
n,
x0,
seed: Deterministic::new(seed),
}
}
}
impl<T: FloatExt, S: SeedExt> ProcessExt<T> for ARp<T, S> {
type Output = Array1<T>;
fn sample(&self) -> Self::Output {
let p = self.phi.len();
let mut noise = Array1::<T>::zeros(self.n);
if self.n > 0 {
let slice = noise.as_slice_mut().expect("contiguous");
let normal = SimdNormal::<T>::from_seed_source(T::zero(), self.sigma, &self.seed);
normal.fill_slice_fast(slice);
}
let noise = &noise;
let mut series = Array1::<T>::zeros(self.n);
if let Some(init) = &self.x0 {
for i in 0..p.min(self.n) {
series[i] = init[i];
}
}
let start = if self.x0.is_some() { p.min(self.n) } else { 0 };
for t in start..self.n {
let mut val = T::zero();
for k in 1..=p {
if t >= k {
val += self.phi[k - 1] * series[t - k];
}
}
series[t] = val + noise[t];
}
series
}
}
py_process_1d!(PyARp, ARp,
sig: (phi, sigma, n, x0=None, seed=None, dtype=None),
params: (phi: Vec<f64>, sigma: f64, n: usize, x0: Option<Vec<f64>>)
);