Skip to main content

tsorder_core/
lib.rs

1//! # tsorder-core
2//!
3//! Dependency-free core for time-series order selection.
4//!
5//! Two families of estimators live here, deliberately sharing one data path
6//! (sample autocovariance → Levinson–Durbin recursion):
7//!
8//! * **Classical information criteria** ([`ic_order`]): AIC, AICc, BIC, HQ, FPE,
9//!   evaluated over nested AR fits of order `0..=max_order`.
10//! * **Fine–Hwang threshold estimators** ([`fh_order`]): fit a model whose memory
11//!   `p_n` grows with `n`, "clip" every statistic below a vanishing threshold
12//!   `η_n`, and report the index of the last surviving lag. Several pluggable
13//!   statistics are supported ([`Statistic`]).
14//!
15//! The mathematical background, the equivalences between the two families and
16//! the empirical findings that motivated the design are summarised on the
17//! project page: <https://castlaboratory.github.io/tsorder/>.
18//!
19//! All functions take `&[f64]`, never allocate more than `O(n + K^2)`, and are
20//! `no_std`-friendly in spirit (they use `Vec` but nothing else from `std`).
21
22pub mod acov;
23pub mod arma;
24pub mod cancorr;
25pub mod criteria;
26pub mod dist;
27pub mod eacf;
28pub mod hankel;
29pub mod integration;
30pub mod levinson;
31pub mod linalg;
32pub mod robust;
33pub mod select;
34#[cfg(feature = "sim")]
35pub mod sim;
36pub mod threshold;
37
38pub use acov::{acf, autocovariance};
39pub use arma::{hannan_rissanen, HrConfig, HrResult};
40pub use cancorr::{
41    canonical_correlations, canonical_correlations_from_acov, canonical_correlations_stacked,
42    svc_order, Cancorr, SvcConfig, SvcPenalty, SvcResult,
43};
44pub use criteria::{ic_order, ic_order_with, Criterion, IcMethod, IcResult};
45pub use dist::{chi2_sf, df_tau_c_critical, imhof_sf, kpss_critical, satterthwaite_sf};
46pub use eacf::{eacf, EacfConfig, EacfResult};
47pub use hankel::{
48    hankel_rank_order, hankel_svt_order, HankelRankConfig, HankelRankResult, HankelSvtConfig,
49    HankelSvtResult, RankAlpha, RankPvalue,
50};
51pub use integration::{integration_order, IntegrationConfig, IntegrationResult, UnitRootTest};
52pub use levinson::{burg_from_series, levinson, levinson_from_series, Levinson};
53pub use robust::{qn, robust_autocorrelation, robust_autocovariance, shrink_to_psd};
54#[cfg(feature = "ensemble")]
55pub use select::{ensemble_order, EnsembleResult, EnsembleRule};
56pub use select::{fh_order, FhConfig, FhResult, Statistic};
57pub use select::{jirak_order, JirakConfig, JirakResult};
58pub use threshold::{polylog_memory, power_memory, Memory, Threshold};
59
60/// Library error type.
61#[derive(Debug, Clone, PartialEq)]
62pub enum Error {
63    /// Series too short for the requested computation.
64    TooShort { n: usize, needed: usize },
65    /// Non-finite value found in the input.
66    NonFinite,
67    /// Sample autocovariance matrix is numerically singular.
68    Singular,
69    /// Invalid parameter.
70    Invalid(&'static str),
71}
72
73impl core::fmt::Display for Error {
74    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
75        match self {
76            Error::TooShort { n, needed } => {
77                write!(
78                    f,
79                    "series of length {n} is too short (need at least {needed})"
80                )
81            }
82            Error::NonFinite => write!(f, "input contains NaN or infinite values"),
83            Error::Singular => write!(f, "sample covariance matrix is singular"),
84            Error::Invalid(m) => write!(f, "invalid argument: {m}"),
85        }
86    }
87}
88
89impl std::error::Error for Error {}
90
91pub type Result<T> = core::result::Result<T, Error>;
92
93pub(crate) fn check_input(x: &[f64], needed: usize) -> Result<()> {
94    if x.len() < needed {
95        return Err(Error::TooShort { n: x.len(), needed });
96    }
97    if x.iter().any(|v| !v.is_finite()) {
98        return Err(Error::NonFinite);
99    }
100    Ok(())
101}