use std::fmt::Debug;
use nalgebra::{DMatrix, DVector, RealField, Scalar};
use num_traits::Float;
use crate::distrib::Regression;
use crate::Error;
pub(crate) mod adf;
pub(crate) mod dickeyfuller;
#[derive(Debug, Clone)]
pub struct Report<F: Debug + Clone> {
pub test_statistic: F,
pub size: usize,
}
pub(crate) fn prepare<F: RealField + Scalar + Float>(
y: &DVector<F>,
n: usize,
regression: Regression,
) -> Result<(DVector<F>, DMatrix<F>, usize), Error> {
let y_len = y.len();
if y_len <= n + 1 {
return Err(Error::NotEnoughSamples);
}
let y_t_1_full = y.clone().remove_row(y_len - 1);
let delta_y = y.clone().remove_row(0) - &y_t_1_full;
let delta_y_output = delta_y.clone().remove_rows(0, n);
let mut x = DMatrix::zeros(y_len - n - 1, n + 1);
let y_t_1 = y_t_1_full.remove_rows(0, n);
x.column_mut(0).copy_from(&y_t_1);
if n > 0 {
let mut delta_y_shifted = delta_y.clone().remove_row(delta_y.len() - 1);
for i in 0..n {
let col = delta_y_shifted.clone().remove_rows(0, n - i - 1);
x.column_mut(i + 1).copy_from(&col);
let delta_y_shifted_len = delta_y_shifted.len();
delta_y_shifted = delta_y_shifted.remove_row(delta_y_shifted_len - 1);
}
}
if regression != Regression::NoConstantNoTrend {
let constant = F::from(1.0).ok_or(Error::ConversionFailed)?;
let a = vec![constant; x.nrows()];
x.extend(a)
}
if regression == Regression::ConstantAndTrend {
let tt: Result<Vec<F>, crate::Error> = (1..x.nrows() + 1)
.map(|i| F::from(i as f64).ok_or(Error::ConversionFailed))
.collect();
match tt {
Ok(tt) => x.extend(tt),
Err(_) => return Err(Error::ConversionFailed),
};
}
Ok((delta_y_output.into_owned(), x, y_len - n - 1))
}
#[cfg(test)]
mod tests {
use nalgebra::{DMatrix, Matrix, Vector};
use crate::distrib::Regression;
#[test]
fn test_prepare_constant() {
let sz = 10;
let n = 2;
let y = vec![1., 3., 6., 10., 15., 21., 28., 36., 45., 55.];
assert_eq!(y.len(), sz);
let row_count = sz - n - 1;
let column_count = n + 2;
let expected = DMatrix::from_row_slice(
row_count,
column_count,
&[
6., 3., 2., 1., 10., 4., 3., 1., 15., 5., 4., 1., 21., 6., 5., 1., 28., 7., 6., 1., 36., 8., 7., 1., 45., 9., 8., 1., ],
);
let y = Matrix::from(y);
let regression = Regression::Constant;
let (delta_y, x, sz_) = super::prepare(&y, n, regression).unwrap();
assert_eq!(sz_, sz - n - 1);
assert_eq!(delta_y, Vector::from(vec![4., 5., 6., 7., 8., 9., 10.]));
assert_eq!(
x.shape(),
(row_count, column_count),
"The shape of x was not as expected"
);
assert_eq!(
x, expected,
"The output matrix x did not match the expected result"
);
}
#[test]
fn test_prepare_constant_and_trend() {
let sz = 10;
let n = 2;
let y = vec![1., 3., 6., 10., 15., 21., 28., 36., 45., 55.];
assert_eq!(y.len(), sz);
let row_count = sz - n - 1;
let column_count = n + 3;
let expected = DMatrix::from_row_slice(
row_count,
column_count,
&[
6., 3., 2., 1., 1., 10., 4., 3., 1., 2., 15., 5., 4., 1., 3., 21., 6., 5., 1., 4., 28., 7., 6., 1., 5., 36., 8., 7., 1., 6., 45., 9., 8., 1., 7., ],
);
let y = Matrix::from(y);
let regression = Regression::ConstantAndTrend;
let (delta_y, x, sz_) = super::prepare(&y, n, regression).unwrap();
assert_eq!(sz_, sz - n - 1);
assert_eq!(delta_y, Vector::from(vec![4., 5., 6., 7., 8., 9., 10.]));
assert_eq!(
x.shape(),
(row_count, column_count),
"The shape of x was not as expected"
);
assert_eq!(
x, expected,
"The output matrix x did not match the expected result"
);
}
#[test]
fn test_prepare_no_constant_no_trend() {
let sz = 10;
let n = 2;
let y = vec![1., 3., 6., 10., 15., 21., 28., 36., 45., 55.];
assert_eq!(y.len(), sz);
let row_count = sz - n - 1;
let column_count = n + 1;
let expected = DMatrix::from_row_slice(
row_count,
column_count,
&[
6., 3., 2., 10., 4., 3., 15., 5., 4., 21., 6., 5., 28., 7., 6., 36., 8., 7., 45., 9., 8., ],
);
let y = Matrix::from(y);
let regression = Regression::NoConstantNoTrend;
let (delta_y, x, sz_) = super::prepare(&y, n, regression).unwrap();
assert_eq!(sz_, sz - n - 1);
assert_eq!(delta_y, Vector::from(vec![4., 5., 6., 7., 8., 9., 10.]));
assert_eq!(
x.shape(),
(row_count, column_count),
"The shape of x was not as expected"
);
assert_eq!(
x, expected,
"The output matrix x did not match the expected result"
);
}
#[test]
fn test_prepare_minimum_size_00() {
let n = 0;
let y: Vec<f32> = vec![];
let y = Matrix::from(y);
let res = super::prepare(&y, n, Regression::Constant);
assert!(res.is_err());
}
#[test]
fn test_prepare_minimum_size_0() {
let n = 0;
let y = vec![1.];
let y = Matrix::from(y);
let res = super::prepare(&y, n, Regression::Constant);
assert!(res.is_err());
}
#[test]
fn test_prepare_minimum_size_1() {
let n = 1;
let y = vec![1.];
let y = Matrix::from(y);
let res = super::prepare(&y, n, Regression::Constant);
assert!(res.is_err());
}
#[test]
fn test_prepare_minimum_size_2() {
let n = 1;
let y = vec![1., 3.];
let y = Matrix::from(y);
let res = super::prepare(&y, n, Regression::Constant);
assert!(res.is_err());
}
#[test]
fn test_prepare_minimum_size_3() {
let n = 2;
let y = vec![1., 3.];
let y = Matrix::from(y);
let res = super::prepare(&y, n, Regression::Constant);
assert!(res.is_err());
}
}