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 MAq<T: FloatExt, S: SeedExt = Unseeded> {
pub theta: Array1<T>,
pub sigma: T,
pub n: usize,
pub seed: S,
}
impl<T: FloatExt> MAq<T> {
pub fn new(theta: Array1<T>, sigma: T, n: usize) -> Self {
assert!(sigma > T::zero(), "MAq requires sigma > 0");
Self {
theta,
sigma,
n,
seed: Unseeded,
}
}
}
impl<T: FloatExt> MAq<T, Deterministic> {
pub fn seeded(theta: Array1<T>, sigma: T, n: usize, seed: u64) -> Self {
assert!(sigma > T::zero(), "MAq requires sigma > 0");
Self {
theta,
sigma,
n,
seed: Deterministic::new(seed),
}
}
}
impl<T: FloatExt, S: SeedExt> ProcessExt<T> for MAq<T, S> {
type Output = Array1<T>;
fn sample(&self) -> Self::Output {
let q = self.theta.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 mut series = Array1::<T>::zeros(self.n);
for t in 0..self.n {
let mut val = noise[t];
for k in 1..=q {
if t >= k {
val += self.theta[k - 1] * noise[t - k];
}
}
series[t] = val;
}
series
}
}
py_process_1d!(PyMAq, MAq,
sig: (theta, sigma, n, seed=None, dtype=None),
params: (theta: Vec<f64>, sigma: f64, n: usize)
);