use anyhow::Result;
use crate::util;
use rand::Rng;
pub fn arima_sim<T: Rng>(
n: usize,
ar: Option<&[f64]>,
ma: Option<&[f64]>,
d: usize,
noise_fn: &dyn Fn(&mut T) -> f64,
rng: &mut T,
) -> Result<Vec<f64>> {
let mut x: Vec<f64> = Vec::new();
let ar_order = match ar {
Some(par) => par.len(),
None => 0_usize,
};
let ma_order = match ma {
Some(par) => par.len(),
None => 0_usize,
};
let burn_in = ar_order + ma_order + 10;
for _ in 0..burn_in + n {
let e = noise_fn(rng);
x.push(e);
}
if ma_order > 0 {
let ma = ma.unwrap();
let noise = x.clone();
for i in ma_order..burn_in + n {
for j in 0..ma_order {
x[i] += ma[j] * noise[i - j - 1];
}
}
for a in x.iter_mut().take(ma_order) {
*a = 0.0
}
}
if ar_order > 0 {
let ar = ar.unwrap();
for i in ma_order + ar_order..burn_in + n {
for j in 0..ar_order {
x[i] += ar[j] * x[i - j - 1];
}
}
}
if d > 0 {
x = util::diffinv(&x[burn_in..x.len() - d], d);
} else {
x.drain(0..burn_in);
}
Ok(x)
}
pub fn arima_forecast<F: Fn(usize, &mut T) -> f64, T: Rng>(
ts: &[f64],
n: usize,
ar: Option<&[f64]>,
ma: Option<&[f64]>,
d: usize,
noise_fn: &F,
rng: &mut T,
) -> Result<Vec<f64>> {
let n_past = ts.len();
let mut x = ts.to_vec();
let ar_order = match ar {
Some(par) => par.len(),
None => 0_usize,
};
let ma_order = match ma {
Some(par) => par.len(),
None => 0_usize,
};
for i in 0..n {
let e = noise_fn(i, rng);
x.push(e);
}
if ma_order > 0 {
let ma = ma.unwrap();
let x_ = x.clone();
for i in n_past..n_past + n {
for j in 0..ma_order {
x[i] += ma[j] * x_[i - j - 1];
}
}
}
if ar_order > 0 {
let ar = ar.unwrap();
for i in n_past..n_past + n {
for j in 0..ar_order {
x[i] += ar[j] * x[i - j - 1];
}
}
}
if d > 0 {
x = util::diffinv(&x[n_past..x.len()], d);
x.drain(0..d);
} else {
x.drain(0..n_past);
}
Ok(x)
}