#![allow(clippy::too_many_arguments)]
use super::Float;
pub fn stl<T: Float>(
y: &[T],
np: usize,
ns: usize,
nt: usize,
nl: usize,
isdeg: i32,
itdeg: i32,
ildeg: i32,
nsjump: usize,
ntjump: usize,
nljump: usize,
ni: usize,
no: usize,
rw: &mut [T],
season: &mut [T],
trend: &mut [T],
work: &mut [T],
) {
let n = y.len();
let work_size = n + 2 * np;
let (work1, work) = work.split_at_mut(work_size);
let (work2, work) = work.split_at_mut(work_size);
let (work3, work) = work.split_at_mut(work_size);
let (work4, work5) = work.split_at_mut(work_size);
let mut userw = false;
let mut k = 0;
loop {
onestp(
y, n, np, ns, nt, nl, isdeg, itdeg, ildeg, nsjump, ntjump, nljump, ni, userw, rw,
season, trend, work1, work2, work3, work4, work5,
);
k += 1;
if k > no {
break;
}
for i in 0..n {
work1[i] = trend[i] + season[i];
}
rwts(y, n, work1, rw);
userw = true;
}
if no == 0 {
for v in rw.iter_mut() {
*v = T::one();
}
}
}
fn ess<T: Float>(
y: &[T],
n: usize,
len: usize,
ideg: i32,
njump: usize,
userw: bool,
rw: &[T],
ys: &mut [T],
res: &mut [T],
) {
if n < 2 {
ys[0] = y[0];
return;
}
let mut nleft = 0;
let mut nright = 0;
let newnj = njump.min(n - 1);
if len >= n {
nleft = 1;
nright = n;
let mut i = 1;
while i <= n {
let ok = est(
y,
n,
len,
ideg,
T::from_usize(i),
&mut ys[i - 1],
nleft,
nright,
res,
userw,
rw,
);
if !ok {
ys[i - 1] = y[i - 1];
}
i += newnj;
}
} else if newnj == 1 {
let nsh = len.div_ceil(2);
nleft = 1;
nright = len;
for i in 1..=n {
if i > nsh && nright != n {
nleft += 1;
nright += 1;
}
let ok = est(
y,
n,
len,
ideg,
T::from_usize(i),
&mut ys[i - 1],
nleft,
nright,
res,
userw,
rw,
);
if !ok {
ys[i - 1] = y[i - 1];
}
}
} else {
let nsh = len.div_ceil(2);
let mut i = 1;
while i <= n {
if i < nsh {
nleft = 1;
nright = len;
} else if i > n - nsh {
nleft = n - len + 1;
nright = n;
} else {
nleft = i - nsh + 1;
nright = len + i - nsh;
}
let ok = est(
y,
n,
len,
ideg,
T::from_usize(i),
&mut ys[i - 1],
nleft,
nright,
res,
userw,
rw,
);
if !ok {
ys[i - 1] = y[i - 1];
}
i += newnj;
}
}
if newnj != 1 {
let mut i = 1;
while i <= n - newnj {
let delta = (ys[i + newnj - 1] - ys[i - 1]) / T::from_usize(newnj);
for j in i + 1..=i + newnj - 1 {
ys[j - 1] = ys[i - 1] + delta * T::from_usize(j - i);
}
i += newnj;
}
let k = ((n - 1) / newnj) * newnj + 1;
if k != n {
let ok = est(
y,
n,
len,
ideg,
T::from_usize(n),
&mut ys[n - 1],
nleft,
nright,
res,
userw,
rw,
);
if !ok {
ys[n - 1] = y[n - 1];
}
if k != n - 1 {
let delta = (ys[n - 1] - ys[k - 1]) / T::from_usize(n - k);
for j in k + 1..=n - 1 {
ys[j - 1] = ys[k - 1] + delta * T::from_usize(j - k);
}
}
}
}
}
fn est<T: Float>(
y: &[T],
n: usize,
len: usize,
ideg: i32,
xs: T,
ys: &mut T,
nleft: usize,
nright: usize,
w: &mut [T],
userw: bool,
rw: &[T],
) -> bool {
let range = T::from_usize(n) - T::one();
let mut h = (xs - T::from_usize(nleft)).max(T::from_usize(nright) - xs);
if len > n {
h += T::from_usize((len - n) / 2);
}
let h9 = T::from_f64(0.999) * h;
let h1 = T::from_f64(0.001) * h;
let mut a = T::zero();
for j in nleft..=nright {
w[j - 1] = T::zero();
let r = (T::from_usize(j) - xs).abs();
if r <= h9 {
if r <= h1 {
w[j - 1] = T::one();
} else {
w[j - 1] = pow3(T::one() - pow3(r / h));
}
if userw {
w[j - 1] *= rw[j - 1];
}
a += w[j - 1];
}
}
if a <= T::zero() {
false
} else {
for j in nleft..=nright {
w[j - 1] /= a;
}
if h > T::zero() && ideg > 0 {
let mut a = T::zero();
for j in nleft..=nright {
a += w[j - 1] * T::from_usize(j);
}
let mut b = xs - a;
let mut c = T::zero();
for j in nleft..=nright {
c += w[j - 1] * pow2(T::from_usize(j) - a);
}
if c.sqrt() > T::from_f64(0.001) * range {
b /= c;
for j in nleft..=nright {
w[j - 1] *= b * (T::from_usize(j) - a) + T::one();
}
}
}
*ys = T::zero();
for j in nleft..=nright {
*ys += w[j - 1] * y[j - 1];
}
true
}
}
fn fts<T: Float>(x: &[T], n: usize, np: usize, trend: &mut [T], work: &mut [T]) {
ma(x, n, np, trend);
ma(trend, n - np + 1, np, work);
ma(work, n - 2 * np + 2, 3, trend);
}
fn ma<T: Float>(x: &[T], n: usize, len: usize, ave: &mut [T]) {
let newn = n - len + 1;
let flen = T::from_usize(len);
let mut v: T = x.iter().take(len).copied().sum();
ave[0] = v / flen;
if newn > 1 {
for (m, aj) in ave.iter_mut().take(newn).skip(1).enumerate() {
v = v - x[m] + x[len + m];
*aj = v / flen;
}
}
}
fn onestp<T: Float>(
y: &[T],
n: usize,
np: usize,
ns: usize,
nt: usize,
nl: usize,
isdeg: i32,
itdeg: i32,
ildeg: i32,
nsjump: usize,
ntjump: usize,
nljump: usize,
ni: usize,
userw: bool,
rw: &mut [T],
season: &mut [T],
trend: &mut [T],
work1: &mut [T],
work2: &mut [T],
work3: &mut [T],
work4: &mut [T],
work5: &mut [T],
) {
for _ in 0..ni {
for i in 0..n {
work1[i] = y[i] - trend[i];
}
ss(
work1, n, np, ns, isdeg, nsjump, userw, rw, work2, work3, work4, work5, season,
);
fts(work2, n + 2 * np, np, work3, work1);
ess(work3, n, nl, ildeg, nljump, false, work4, work1, work5);
for i in 0..n {
season[i] = work2[np + i] - work1[i];
}
for i in 0..n {
work1[i] = y[i] - season[i];
}
ess(work1, n, nt, itdeg, ntjump, userw, rw, trend, work3);
}
}
fn rwts<T: Float>(y: &[T], n: usize, fit: &[T], rw: &mut [T]) {
for i in 0..n {
rw[i] = (y[i] - fit[i]).abs();
}
let mid1 = (n - 1) / 2;
let mid2 = n / 2;
rw.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
let cmad = T::from_f64(3.0) * (rw[mid1] + rw[mid2]); let c9 = T::from_f64(0.999) * cmad;
let c1 = T::from_f64(0.001) * cmad;
for i in 0..n {
let r = (y[i] - fit[i]).abs();
if r <= c1 {
rw[i] = T::one();
} else if r <= c9 {
rw[i] = pow2(T::one() - pow2(r / cmad));
} else {
rw[i] = T::zero();
}
}
}
fn ss<T: Float>(
y: &[T],
n: usize,
np: usize,
ns: usize,
isdeg: i32,
nsjump: usize,
userw: bool,
rw: &[T],
season: &mut [T],
work1: &mut [T],
work2: &mut [T],
work3: &mut [T],
work4: &mut [T],
) {
for j in 1..=np {
let k = (n - j) / np + 1;
for i in 1..=k {
work1[i - 1] = y[(i - 1) * np + j - 1];
}
if userw {
for i in 1..=k {
work3[i - 1] = rw[(i - 1) * np + j - 1];
}
}
ess(
work1,
k,
ns,
isdeg,
nsjump,
userw,
work3,
&mut work2[1..],
work4,
);
let mut xs = T::zero();
let nright = ns.min(k);
let ok = est(
work1,
k,
ns,
isdeg,
xs,
&mut work2[0],
1,
nright,
work4,
userw,
work3,
);
if !ok {
work2[0] = work2[1];
}
xs = T::from_usize(k + 1);
let nleft = 1.max(k as i32 - ns as i32 + 1) as usize;
let ok = est(
work1,
k,
ns,
isdeg,
xs,
&mut work2[k + 1],
nleft,
k,
work4,
userw,
work3,
);
if !ok {
work2[k + 1] = work2[k];
}
for m in 1..=k + 2 {
season[(m - 1) * np + j - 1] = work2[m - 1];
}
}
}
fn pow2<T: Float>(x: T) -> T {
x * x
}
fn pow3<T: Float>(x: T) -> T {
x * x * x
}