Skip to content

Latest commit

 

History

History
1935 lines (1451 loc) · 45.8 KB

File metadata and controls

1935 lines (1451 loc) · 45.8 KB

API Reference

This document provides a comprehensive reference for all public APIs in the anofox-forecast crate. The crate provides 35+ forecasting models, 76+ time series features, and extensive utilities for time series analysis.

Table of Contents


Core Types

TimeSeries

Container for time series data with timestamps and multivariate values.

pub struct TimeSeries {
    // Fields are private, use methods to access
}

Constructor Methods

Method Description
TimeSeries::new(timestamps, values, labels) Create with full configuration
TimeSeries::univariate(values) Create simple single-dimension series

Key Methods

Method Returns Description
len() usize Number of observations
dimensions() usize Number of dimensions
is_empty() bool Check if series is empty
is_multivariate() bool Check if multi-dimensional
timestamps() &[DateTime<Utc>] Get timestamps
values(dimension) Result<&[f64]> Get values for dimension
primary_values() &[f64] Get first dimension values
slice(start, end) Result<TimeSeries> Extract subsequence
has_missing_values() bool Check for NaN/Inf
missing_mask() Vec<bool> Boolean mask: true where NaN/Inf (primary dimension)
missing_count() Vec<usize> Count of missing values per dimension
interpolated(fill_edges) TimeSeries Linear interpolation for NaN values
sanitized(policy) Result<TimeSeries> Apply missing value policy
imputed_forward_backward() TimeSeries Forward-fill then backward-fill
imputed_moving_average(window) Result<TimeSeries> Centered moving average imputation
imputed_seasonal(period) Result<TimeSeries> Seasonal median imputation
with_imputed_regressors(policy) Result<TimeSeries> Impute NaN in regressor vectors

Back to top


TimeSeriesBuilder

Builder pattern for constructing TimeSeries.

let ts = TimeSeriesBuilder::new()
    .timestamps(timestamps)
    .values(values)
    .frequency(Duration::days(1))
    .build()?;
Method Description
new() Create new builder
timestamps(Vec<DateTime<Utc>>) Set timestamps
values(Vec<f64>) Set univariate values
multivariate_values(Vec<Vec<f64>>, ValueLayout) Set multivariate values
labels(Vec<String>) Set dimension labels
frequency(Duration) Set time frequency
build() Build the TimeSeries

Back to top


Forecast

Prediction output containing point forecasts and optional confidence intervals.

pub struct Forecast {
    // Fields are private, use methods to access
}

Constructor Methods

Method Description
Forecast::new() Create empty forecast
Forecast::from_values(values) Create from point forecasts
Forecast::from_values_with_intervals(values, lower, upper) Create with intervals

Key Methods

Method Returns Description
horizon() usize Number of forecast steps
primary() &[f64] Get point forecasts
lower() Option<&[Vec<f64>]> Get lower bounds
upper() Option<&[Vec<f64>]> Get upper bounds
has_lower() bool Check if lower bounds exist
has_upper() bool Check if upper bounds exist

Back to top


ForecastError

Error types for forecasting operations.

pub enum ForecastError {
    EmptyData,
    InsufficientData { needed: usize, got: usize, hint: Option<String> },
    InvalidParameter(String),
    DimensionMismatch { expected: usize, got: usize },
    FitRequired,
    MissingValues,
    ComputationError(String),
    // ... other variants
}
Variant Description
EmptyData Input data is empty
InsufficientData Not enough data points
InvalidParameter Invalid parameter value
DimensionMismatch Dimension mismatch in data
FitRequired Model not fitted before prediction
MissingValues Missing values detected
ComputationError Numerical computation error

Back to top


Missing Value Imputation

Tools for handling NaN/Inf values before model fitting. All models reject missing values at fit() time, so imputation must be applied beforehand.

MissingValuePolicy

pub enum MissingValuePolicy {
    Drop,           // Remove observations with NaN/Inf
    Fill(f64),      // Replace with specific value
    ForwardFill,    // Carry last valid value forward
    BackwardFill,   // Carry next valid value backward
    FillMean,       // Replace with mean of finite values
    FillMedian,     // Replace with median of finite values
    Interpolate,    // Linear interpolation (edges filled)
    Error,          // Return error if any missing
}

Usage:

use anofox_forecast::core::{TimeSeries, MissingValuePolicy};

// Apply policy via sanitized()
let clean = ts.sanitized(MissingValuePolicy::FillMean)?;
let clean = ts.sanitized(MissingValuePolicy::BackwardFill)?;
let clean = ts.sanitized(MissingValuePolicy::Interpolate)?;

Imputation Methods

Method Description
sanitized(policy) Apply any MissingValuePolicy variant
imputed_forward_backward() Forward-fill then backward-fill — handles both leading and trailing NaN
imputed_moving_average(window) Centered window mean with multi-pass for adjacent gaps. Window must be odd. Remaining NaN filled with global mean.
imputed_seasonal(period) Fill NaN with median of same seasonal position across cycles. Requires at least 1 full cycle. Errors if >50% missing in any bucket.
with_imputed_regressors(policy) Apply fill policy to each regressor vector independently. Supports Fill, ForwardFill, BackwardFill, FillMean, FillMedian, Interpolate.

Metadata Helpers

Method Returns Description
has_missing_values() bool True if any NaN/Inf in any dimension
missing_mask() Vec<bool> Per-observation mask for primary dimension
missing_count() Vec<usize> Count of NaN/Inf per dimension

Example — seasonal imputation:

// Weekly data with gaps
let clean = ts.imputed_seasonal(7)?;  // Fill using same-weekday median

Example — regressor imputation:

let clean = ts.with_imputed_regressors(MissingValuePolicy::FillMean)?;

Back to top


Forecaster Trait

Main trait interface that all forecasting models implement.

pub trait Forecaster {
    fn fit(&mut self, series: &TimeSeries) -> Result<()>;
    fn predict(&self, horizon: usize) -> Result<Forecast>;
    fn predict_with_intervals(&self, horizon: usize, level: f64) -> Result<Forecast>;
    fn fitted_values(&self) -> Option<&[f64]>;
    fn residuals(&self) -> Option<&[f64]>;
    fn name(&self) -> &str;
    fn is_fitted(&self) -> bool;
}
Method Parameters Returns Description
fit series: &TimeSeries Result<()> Fit model to data
predict horizon: usize Result<Forecast> Generate point forecasts
predict_with_intervals horizon: usize, level: f64 Result<Forecast> Forecasts with confidence intervals
fitted_values - Option<&[f64]> Get in-sample fitted values
residuals - Option<&[f64]> Get residuals (actual - fitted)
name - &str Model name
is_fitted - bool Check if model is fitted

Back to top


Baseline Models

Naive

Repeats the last observed value for all forecast horizons.

pub struct Naive;

impl Naive {
    pub fn new() -> Self;
}

Example:

let mut model = Naive::new();
model.fit(&ts)?;
let forecast = model.predict(12)?;

Back to top


SeasonalNaive

Repeats values from the same season in the previous cycle.

pub struct SeasonalNaive {
    period: usize,
}

impl SeasonalNaive {
    pub fn new(period: usize) -> Self;
}
Parameter Type Description
period usize Seasonal period (e.g., 12 for monthly data)

Back to top


RandomWalkWithDrift

Random walk model with trend drift component.

pub struct RandomWalkWithDrift;

impl RandomWalkWithDrift {
    pub fn new() -> Self;
}

The drift is estimated as the average change between consecutive observations.

Back to top


HistoricAverage

Forecasts the mean of all historical observations.

pub struct HistoricAverage;

impl HistoricAverage {
    pub fn new() -> Self;
}

Back to top


WindowAverage

Moving window average forecaster.

pub struct WindowAverage {
    window: usize,
}

impl WindowAverage {
    pub fn new(window: usize) -> Self;
}
Parameter Type Description
window usize Number of observations to average

Back to top


SeasonalWindowAverage

Seasonal window-based averaging.

pub struct SeasonalWindowAverage {
    period: usize,
    window: usize,
}

impl SeasonalWindowAverage {
    pub fn new(period: usize, window: usize) -> Self;
}
Parameter Type Description
period usize Seasonal period
window usize Number of seasonal cycles to average

Back to top


Exponential Smoothing

SimpleExponentialSmoothing

Simple exponential smoothing for non-seasonal, non-trending data.

pub struct SimpleExponentialSmoothing {
    alpha: Option<f64>,
}

impl SimpleExponentialSmoothing {
    pub fn new(alpha: f64) -> Self;
    pub fn auto() -> Self;
    pub fn alpha(&self) -> Option<f64>;
    pub fn level(&self) -> Option<f64>;
}
Parameter Type Description
alpha f64 Smoothing parameter (0 < alpha < 1)
Method Returns Description
auto() Self Create with auto-optimized alpha
alpha() Option<f64> Get fitted alpha value
level() Option<f64> Get final level

Back to top


Holt

Holt's linear trend method (double exponential smoothing).

pub struct Holt {
    alpha: Option<f64>,
    beta: Option<f64>,
}

impl Holt {
    pub fn new(alpha: f64, beta: f64) -> Self;
    pub fn auto() -> Self;
}
Parameter Type Description
alpha f64 Level smoothing (0 < alpha < 1)
beta f64 Trend smoothing (0 < beta < 1)

Back to top


HoltWinters

Holt-Winters seasonal exponential smoothing.

pub struct HoltWinters {
    period: usize,
    seasonal_type: SeasonalType,
    alpha: Option<f64>,
    beta: Option<f64>,
    gamma: Option<f64>,
}

impl HoltWinters {
    pub fn new(period: usize, seasonal_type: SeasonalType) -> Self;
    pub fn with_params(period: usize, seasonal_type: SeasonalType,
                       alpha: f64, beta: f64, gamma: f64) -> Self;
    pub fn auto(period: usize, seasonal_type: SeasonalType) -> Self;
}

pub enum SeasonalType {
    Additive,
    Multiplicative,
}
Parameter Type Description
period usize Seasonal period
seasonal_type SeasonalType Additive or Multiplicative
alpha f64 Level smoothing
beta f64 Trend smoothing
gamma f64 Seasonal smoothing

Back to top


ETS

Error-Trend-Seasonal state-space model following the FPP3 taxonomy.

pub struct ETS {
    spec: ETSSpec,
}

impl ETS {
    pub fn new(spec: ETSSpec, period: usize) -> Self;
}

pub struct ETSSpec {
    pub error: ErrorType,
    pub trend: TrendType,
    pub seasonal: SeasonalType,
}

pub enum ErrorType { Additive, Multiplicative }
pub enum TrendType { None, Additive, AdditiveDamped }
pub enum SeasonalType { None, Additive, Multiplicative }

ETS Model Taxonomy

This implementation follows the ETS taxonomy from Forecasting: Principles and Practice (FPP3).

Valid ETS Specifications (16 of 18 combinations):

Code Name Constructor
ANN Simple exponential smoothing ETSSpec::ann()
AAN Holt's linear method ETSSpec::aan()
AAdN Additive damped trend ETSSpec::aadn()
ANA Seasonal (no trend, additive) ETSSpec::ana()
ANM Seasonal (no trend, multiplicative) ETSSpec::anm()
AAA Holt-Winters additive ETSSpec::aaa()
AAM Holt-Winters multiplicative seasonal ETSSpec::aam()
AAdA Damped Holt-Winters additive ETSSpec::aada()
AAdM Damped Holt-Winters multiplicative ETSSpec::aadm()
MNN Multiplicative error simple smoothing ETSSpec::mnn()
MAN Multiplicative error with trend ETSSpec::man()
MAdN Multiplicative error damped trend ETSSpec::madn()
MNM Multiplicative error and seasonal ETSSpec::mnm()
MAM Multiplicative Holt-Winters ETSSpec::mam()
MAdM Damped multiplicative Holt-Winters ETSSpec::madm()

Invalid/Unstable (rejected):

Code Reason
MAA Multiplicative error + additive trend + additive seasonal
MAdA Multiplicative error + damped trend + additive seasonal

Parsing ETS Notation

impl ETSSpec {
    /// Parse from notation string like "AAA", "MAM", "AAdM"
    pub fn from_notation(notation: &str) -> Result<Self>;

    /// Check if this combination is valid
    pub fn is_valid(&self) -> bool;
}

Example:

use anofox_forecast::models::exponential::ETSSpec;

// Parse notation
let spec = ETSSpec::from_notation("AAA")?;  // Holt-Winters additive
let spec = ETSSpec::from_notation("MAdM")?; // Damped multiplicative

// Invalid combinations return error
assert!(ETSSpec::from_notation("MAA").is_err());

Back to top


AutoETS

Automatic ETS model selection using information criteria.

pub struct AutoETS {
    config: AutoETSConfig,
}

impl AutoETS {
    pub fn new() -> Self;
    pub fn with_config(config: AutoETSConfig) -> Self;
    pub fn with_period(period: usize) -> Self;
}

pub struct AutoETSConfig {
    pub criterion: SelectionCriterion,
    pub seasonal_period: Option<usize>,
    pub allow_multiplicative: bool,
}

pub enum SelectionCriterion { AIC, BIC, AICc }

Back to top


SeasonalES

Multiplicative seasonal exponential smoothing.

pub struct SeasonalES {
    period: usize,
}

impl SeasonalES {
    pub fn new(period: usize) -> Self;
}

Back to top


ARIMA Models

ARIMA

Non-seasonal ARIMA(p,d,q) model.

pub struct ARIMA {
    spec: ARIMASpec,
}

impl ARIMA {
    pub fn new(p: usize, d: usize, q: usize) -> Self;
    pub fn spec(&self) -> &ARIMASpec;
    pub fn ar_coefficients(&self) -> &[f64];
    pub fn ma_coefficients(&self) -> &[f64];
    pub fn intercept(&self) -> f64;
    pub fn aic(&self) -> Option<f64>;
    pub fn bic(&self) -> Option<f64>;
}

pub struct ARIMASpec {
    pub p: usize,  // AR order
    pub d: usize,  // Differencing order
    pub q: usize,  // MA order
}
Parameter Type Description
p usize Autoregressive order
d usize Differencing order
q usize Moving average order

Back to top


SARIMA

Seasonal ARIMA(p,d,q)(P,D,Q)[s] model.

pub struct SARIMA {
    spec: SARIMASpec,
}

impl SARIMA {
    pub fn new(p: usize, d: usize, q: usize,
               cap_p: usize, cap_d: usize, cap_q: usize, s: usize) -> Self;
}

pub struct SARIMASpec {
    pub p: usize, pub d: usize, pub q: usize,       // Non-seasonal
    pub cap_p: usize, pub cap_d: usize, pub cap_q: usize,  // Seasonal
    pub s: usize,  // Seasonal period
}
Parameter Type Description
p, d, q usize Non-seasonal orders
P, D, Q usize Seasonal orders
s usize Seasonal period

Back to top


AutoARIMA

Automatic ARIMA order selection.

pub struct AutoARIMA {
    config: AutoARIMAConfig,
}

impl AutoARIMA {
    pub fn new() -> Self;
    pub fn with_config(config: AutoARIMAConfig) -> Self;
}

pub struct AutoARIMAConfig {
    pub max_p: usize,
    pub max_d: usize,
    pub max_q: usize,
    pub seasonal_period: Option<usize>,
    pub criterion: SelectionCriterion,
    pub stepwise: bool,
    pub true_stepwise: bool,  // Neighbor-based hill climbing
}

impl AutoARIMAConfig {
    pub fn with_true_stepwise(self, enabled: bool) -> Self;
    pub fn exhaustive(self) -> Self;
}
Parameter Description
stepwise Use stepwise search (faster, fewer models)
true_stepwise Use neighbor-based hill climbing (60-70% fewer evaluations)

Parallel Execution:

Enable with --features parallel for 4-8x speedup on multi-core systems:

[dependencies]
anofox-forecast = { version = "0.3", features = ["parallel"] }

Back to top


Theta Models

Theta

Standard Theta Model (STM) for forecasting.

pub struct Theta {
    theta: f64,
    seasonal_period: usize,
    decomposition: DecompositionType,
}

impl Theta {
    pub fn new() -> Self;
    pub fn with_theta(theta: f64) -> Self;
    pub fn seasonal(period: usize) -> Self;
    pub fn seasonal_with_type(period: usize, decomposition: DecompositionType) -> Self;
}

pub enum DecompositionType {
    Additive,
    Multiplicative,
}
Parameter Type Description
theta f64 Theta parameter (default: 2.0)
period usize Seasonal period (0 for non-seasonal)
decomposition DecompositionType Seasonal decomposition type

Back to top


OptimizedTheta

Theta model with optimized alpha and theta parameters.

pub struct OptimizedTheta;

impl OptimizedTheta {
    pub fn new() -> Self;
}

Parameters are optimized using Nelder-Mead minimization of MSE.

Back to top


DynamicTheta

Theta with dynamic linear coefficient updates.

pub struct DynamicTheta {
    period: Option<usize>,
}

impl DynamicTheta {
    pub fn new(period: Option<usize>) -> Self;
}

Back to top


DynamicOptimizedTheta

Combines dynamic updates with parameter optimization.

pub struct DynamicOptimizedTheta {
    period: Option<usize>,
}

impl DynamicOptimizedTheta {
    pub fn new(period: Option<usize>) -> Self;
}

Back to top


AutoTheta

Automatic Theta model selection.

pub struct AutoTheta;

impl AutoTheta {
    pub fn new() -> Self;
}

Selects the best Theta variant based on cross-validation performance.

Back to top


Intermittent Demand Models

Croston

Croston's method for intermittent demand forecasting.

pub struct Croston {
    variant: CrostonVariant,
    alpha: f64,
}

impl Croston {
    pub fn new() -> Self;           // Classic variant
    pub fn classic() -> Self;
    pub fn sba() -> Self;           // Syntetos-Babai adjusted
    pub fn with_alpha(alpha: f64) -> Self;
}

pub enum CrostonVariant {
    Classic,
    SBA,  // Syntetos-Babai Approximation
}
Variant Description
Classic Original Croston method
SBA Bias-corrected Syntetos-Babai variant

Back to top


TSB

Teunter-Syntetos-Babai method for intermittent demand.

pub struct TSB {
    alpha: f64,
    beta: f64,
}

impl TSB {
    pub fn new() -> Self;
    pub fn with_params(alpha: f64, beta: f64) -> Self;
}

Back to top


ADIDA

Aggregate-Disaggregate Intermittent Demand Approach.

pub struct ADIDA {
    aggregation_level: usize,
}

impl ADIDA {
    pub fn new() -> Self;
    pub fn with_aggregation(level: usize) -> Self;
}

Back to top


IMAPA

Intermittent Multiple Aggregation Prediction Algorithm.

pub struct IMAPA;

impl IMAPA {
    pub fn new() -> Self;
}

Combines forecasts from multiple aggregation levels.

Back to top


Advanced Models

MFLES

Multiple Fourier Linear Exponential Smoothing - gradient boosted decomposition.

pub struct MFLES {
    seasonal_periods: Vec<usize>,
}

impl MFLES {
    pub fn new(seasonal_periods: Vec<usize>) -> Self;
    pub fn with_max_rounds(rounds: usize) -> Self;
}
Parameter Type Description
seasonal_periods Vec<usize> Seasonal periods to model
max_rounds usize Maximum boosting iterations

Back to top


MSTLForecaster

MSTL decomposition-based forecaster for multiple seasonalities.

pub struct MSTLForecaster {
    seasonal_periods: Vec<usize>,
}

impl MSTLForecaster {
    pub fn new(seasonal_periods: Vec<usize>) -> Self;
}

Back to top


TBATS

Trigonometric seasonality, Box-Cox transformation, ARMA errors, Trend, Seasonal components.

pub struct TBATS {
    seasonal_periods: Vec<usize>,
}

impl TBATS {
    pub fn new(seasonal_periods: Vec<usize>) -> Self;
}

Handles complex seasonal patterns with trigonometric representation.

Back to top


AutoTBATS

Automatic TBATS configuration selection.

pub struct AutoTBATS;

impl AutoTBATS {
    pub fn new(seasonal_periods: Vec<usize>) -> Self;
}

Back to top


GARCH

Generalized Autoregressive Conditional Heteroskedasticity for volatility modeling.

pub struct GARCH {
    p: usize,
    q: usize,
}

impl GARCH {
    pub fn new(p: usize, q: usize) -> Self;
}
Parameter Type Description
p usize GARCH order (variance lags)
q usize ARCH order (squared residual lags)

Back to top


Ensemble

Combines multiple forecasting models.

pub struct Ensemble {
    models: Vec<Box<dyn Forecaster>>,
    method: CombinationMethod,
}

impl Ensemble {
    pub fn new(models: Vec<Box<dyn Forecaster>>) -> Self;
    pub fn with_method(method: CombinationMethod) -> Self;
    pub fn with_weights(weights: Vec<f64>) -> Self;
}

pub enum CombinationMethod {
    Mean,
    Median,
    WeightedMSE,
    Custom,
}
Method Description
Mean Simple average of forecasts
Median Median of forecasts
WeightedMSE Inverse MSE weighting
Custom User-provided weights

Back to top


Decomposition

STL

Seasonal-Trend decomposition using LOESS.

pub struct STL {
    period: usize,
}

impl STL {
    pub fn new(period: usize) -> Self;
    pub fn decompose(&self, series: &[f64]) -> Result<STLResult>;
}

pub struct STLResult {
    pub seasonal: Vec<f64>,
    pub trend: Vec<f64>,
    pub remainder: Vec<f64>,
}

Back to top


MSTL

Multiple Seasonal-Trend decomposition using LOESS.

pub struct MSTL {
    periods: Vec<usize>,
}

impl MSTL {
    pub fn new(periods: Vec<usize>) -> Self;
    pub fn decompose(&self, series: &[f64]) -> Result<MSTLResult>;
}

pub struct MSTLResult {
    pub seasonal_components: Vec<Vec<f64>>,
    pub trend: Vec<f64>,
    pub remainder: Vec<f64>,
}

Back to top


Spectral Analysis

Welch Periodogram

Welch's method for reduced variance spectral estimation using overlapping windowed segments.

/// Welch's periodogram for reduced variance spectral estimation
pub fn welch_periodogram(
    signal: &[f64],
    window_size: usize,  // Segment size (power of 2 recommended)
    overlap: f64,        // Overlap ratio (0.0-0.9, typically 0.5)
) -> Vec<(usize, f64)>;
Parameter Type Description
signal &[f64] Input time series
window_size usize Segment size (power of 2 for efficiency)
overlap f64 Overlap ratio between segments (0.0-0.9)

Returns: Vector of (period, power) tuples sorted by period (largest first).

Example:

use anofox_forecast::detection::welch_periodogram;

let signal: Vec<f64> = (0..256)
    .map(|i| (2.0 * std::f64::consts::PI * i as f64 / 12.0).sin())
    .collect();

let psd = welch_periodogram(&signal, 64, 0.5);
if let Some((period, _)) = psd.iter().max_by(|a, b| a.1.partial_cmp(&b.1).unwrap()) {
    println!("Dominant period: {}", period);
}

Note: For comprehensive periodicity detection (ACF, FFT, Autoperiod, CFD-Autoperiod, SAZED), see the fdars crate.

Back to top


Feature Extraction

The crate provides 76+ time series features organized by category.

Basic Features

pub fn mean(series: &[f64]) -> f64;
pub fn median(series: &[f64]) -> f64;
pub fn variance(series: &[f64]) -> f64;
pub fn standard_deviation(series: &[f64]) -> f64;
pub fn minimum(series: &[f64]) -> f64;
pub fn maximum(series: &[f64]) -> f64;
pub fn sum_values(series: &[f64]) -> f64;
pub fn abs_energy(series: &[f64]) -> f64;
pub fn mean_abs_change(series: &[f64]) -> f64;
pub fn mean_change(series: &[f64]) -> f64;

Distribution Features

pub fn skewness(series: &[f64]) -> f64;
pub fn kurtosis(series: &[f64]) -> f64;
pub fn quantile(series: &[f64], q: f64) -> f64;
pub fn variation_coefficient(series: &[f64]) -> f64;

Autocorrelation Features

pub fn autocorrelation(series: &[f64], lag: usize) -> f64;
pub fn partial_autocorrelation(series: &[f64], lag: usize) -> f64;

Entropy Features

pub fn approximate_entropy(series: &[f64], m: usize, r: f64) -> f64;
pub fn sample_entropy(series: &[f64], m: usize, r: f64) -> f64;
pub fn permutation_entropy(series: &[f64], order: usize) -> f64;

Complexity Features

pub fn cid_ce(series: &[f64], normalize: bool) -> f64;
pub fn lempel_ziv_complexity(series: &[f64], threshold: Option<f64>) -> f64;

Trend Features

pub fn linear_trend(series: &[f64]) -> LinearTrendResult;
pub fn ar_coefficient(series: &[f64], k: usize) -> f64;

Back to top


Transformations

Box-Cox

pub fn boxcox(series: &[f64], lambda: f64) -> Result<BoxCoxResult>;
pub fn boxcox_auto(series: &[f64]) -> Result<BoxCoxResult>;
pub fn inv_boxcox(transformed: &[f64], lambda: f64) -> Result<Vec<f64>>;
pub fn boxcox_lambda(series: &[f64]) -> Result<f64>;

pub struct BoxCoxResult {
    pub transformed: Vec<f64>,
    pub lambda: f64,
}

Scaling

pub fn standardize(series: &[f64]) -> ScaleResult;
pub fn normalize(series: &[f64]) -> ScaleResult;
pub fn robust_scale(series: &[f64]) -> ScaleResult;

pub struct ScaleResult {
    pub scaled: Vec<f64>,
    pub mean: f64,
    pub std: f64,
}

Window Functions

pub fn rolling_mean(series: &[f64], window: usize, center: bool) -> Vec<f64>;
pub fn rolling_std(series: &[f64], window: usize, center: bool) -> Vec<f64>;
pub fn rolling_min(series: &[f64], window: usize, center: bool) -> Vec<f64>;
pub fn rolling_max(series: &[f64], window: usize, center: bool) -> Vec<f64>;
pub fn expanding_mean(series: &[f64]) -> Vec<f64>;
pub fn ewm_mean(series: &[f64], span: f64) -> Vec<f64>;

Back to top


Validation

Residual Tests

pub fn ljung_box(residuals: &[f64], nlags: Option<usize>, seasonal: usize) -> LjungBoxResult;
pub fn box_pierce(residuals: &[f64], nlags: Option<usize>, seasonal: usize) -> LjungBoxResult;
pub fn durbin_watson(residuals: &[f64]) -> DurbinWatsonResult;

pub struct LjungBoxResult {
    pub statistic: f64,
    pub p_value: f64,
    pub degrees_of_freedom: usize,
}

pub struct DurbinWatsonResult {
    pub statistic: f64,  // Values near 2 indicate no autocorrelation
}

Stationarity Tests

pub fn adf_test(series: &[f64], nlags: Option<usize>) -> StationarityResult;
pub fn kpss_test(series: &[f64], nlags: Option<usize>) -> StationarityResult;

pub struct StationarityResult {
    pub test_statistic: f64,
    pub p_value: f64,
    pub is_stationary: bool,
}

Back to top


Changepoint Detection

PELT (Pruned Exact Linear Time) algorithm for changepoint detection.

pub fn pelt_detect(series: &[f64], config: &PeltConfig) -> PeltResult;

pub struct PeltConfig {
    pub penalty: f64,
    pub min_segment_length: usize,
    pub cost_fn: CostFunction,
}

impl PeltConfig {
    pub fn default() -> Self;
    pub fn penalty(penalty: f64) -> Self;
    pub fn with_bic_penalty(n: usize) -> Self;
}

pub enum CostFunction {
    L2,           // Squared cost (default)
    L1,           // Absolute cost, robust to outliers
    Normal,       // Normal likelihood
    Poisson,      // Poisson likelihood for count data
    LinearTrend,  // Detects slope/trend changes
    MeanVariance, // Joint mean and variance changes
    Cusum,        // Sustained mean shifts
}

pub struct PeltResult {
    pub changepoints: Vec<usize>,
    pub n_changepoints: usize,
}

Back to top


Utilities

Accuracy Metrics

pub fn calculate_metrics(actual: &[f64], predicted: &[f64],
                         seasonal_period: Option<usize>) -> Result<AccuracyMetrics>;

pub struct AccuracyMetrics {
    pub mae: f64,      // Mean Absolute Error
    pub mse: f64,      // Mean Squared Error
    pub rmse: f64,     // Root Mean Squared Error
    pub mape: f64,     // Mean Absolute Percentage Error
    pub smape: f64,    // Symmetric MAPE
    pub mase: f64,     // Mean Absolute Scaled Error
    pub r_squared: f64,
}

Cross-Validation

pub fn cross_validate<F>(config: &CVConfig, series: &TimeSeries,
                         model_factory: F) -> Result<CVResults>;

pub struct CVConfig {
    pub horizon: usize,
    pub initial_window: usize,
    pub step_size: usize,
    pub strategy: CVStrategy,
}

pub enum CVStrategy {
    Rolling,    // Fixed window slides forward
    Expanding,  // Window grows over time
}

pub struct CVResults {
    pub n_folds: usize,
    pub aggregated: AggregatedMetrics,
    pub fold_metrics: Vec<AccuracyMetrics>,
}

Optimization

pub fn nelder_mead(objective: fn(&[f64]) -> f64, initial: Vec<f64>,
                   config: &NelderMeadConfig) -> Result<NelderMeadResult>;

pub struct NelderMeadConfig {
    pub max_iter: usize,
    pub tolerance: f64,
}

pub struct NelderMeadResult {
    pub parameters: Vec<f64>,
    pub value: f64,
    pub iterations: usize,
}

Back to top


Bootstrap Intervals

Bootstrap methods for empirical confidence intervals.

pub struct BootstrapConfig {
    pub n_samples: usize,      // Number of bootstrap samples (default: 1000)
    pub block_size: Option<usize>,  // Block size for block bootstrap
    pub seed: Option<u64>,     // Random seed for reproducibility
}

impl BootstrapConfig {
    pub fn new(n_samples: usize) -> Self;
    pub fn with_block_size(self, block_size: usize) -> Self;
    pub fn with_seed(self, seed: u64) -> Self;
}

pub struct BootstrapResult {
    pub lower: Vec<f64>,       // Lower bounds per horizon step
    pub upper: Vec<f64>,       // Upper bounds per horizon step
    pub level: f64,            // Confidence level used
    pub n_samples: usize,      // Number of samples used
}

/// Generate bootstrap confidence intervals
pub fn bootstrap_intervals<M: Forecaster + Clone>(
    model: &M,
    series: &TimeSeries,
    horizon: usize,
    level: f64,
    config: &BootstrapConfig,
) -> Result<BootstrapResult>;

/// Generate forecast with bootstrap intervals
pub fn bootstrap_forecast<M: Forecaster + Clone>(
    model: &M,
    series: &TimeSeries,
    horizon: usize,
    level: f64,
    config: &BootstrapConfig,
) -> Result<Forecast>;
Method Description
Residual Bootstrap Resamples fitted residuals with replacement
Block Bootstrap Preserves autocorrelation structure

Example:

use anofox_forecast::utils::bootstrap::{bootstrap_forecast, BootstrapConfig};

let config = BootstrapConfig::new(500).with_seed(42);
let forecast = bootstrap_forecast(&model, &ts, 12, 0.95, &config)?;

Back to top


Probabilistic Postprocessing

The postprocessing module provides methods to convert point forecasts into calibrated predictive distributions with coverage guarantees. It follows the approach of PostForecasts.jl.

Core Types

PointForecasts

Point forecasts with optional timestamps and metadata.

pub struct PointForecasts {
    timestamps: Vec<DateTime<Utc>>,
    values: Vec<f64>,
    model_name: Option<String>,
}

impl PointForecasts {
    pub fn new(timestamps: Vec<DateTime<Utc>>, values: Vec<f64>) -> Result<Self>;
    pub fn from_values(values: Vec<f64>) -> Self;
    pub fn empty() -> Self;
    pub fn with_model_name(self, name: impl Into<String>) -> Self;
    pub fn len(&self) -> usize;
    pub fn values(&self) -> &[f64];
    pub fn timestamps(&self) -> &[DateTime<Utc>];
}

QuantileForecasts

Multi-quantile forecasts representing a discrete predictive distribution.

pub struct QuantileForecasts {
    timestamps: Vec<DateTime<Utc>>,
    quantiles: Vec<f64>,
    values: Vec<Vec<f64>>,  // values[time][quantile]
}

impl QuantileForecasts {
    pub fn new(timestamps: Vec<DateTime<Utc>>, quantiles: Vec<f64>, values: Vec<Vec<f64>>) -> Result<Self>;
    pub fn from_values(quantiles: Vec<f64>, values: Vec<Vec<f64>>) -> Result<Self>;
    pub fn n_times(&self) -> usize;
    pub fn n_quantiles(&self) -> usize;
    pub fn quantiles(&self) -> &[f64];
    pub fn at_time(&self, idx: usize) -> Option<&[f64]>;
    pub fn at_quantile(&self, idx: usize) -> Option<Vec<f64>>;
    pub fn median(&self) -> Option<Vec<f64>>;
    pub fn to_prediction_intervals(&self, coverage: f64) -> Option<PredictionIntervals>;
}

PredictionIntervals

Lower and upper bounds with coverage level.

pub struct PredictionIntervals {
    timestamps: Vec<DateTime<Utc>>,
    lower: Vec<f64>,
    upper: Vec<f64>,
    coverage: f64,
}

impl PredictionIntervals {
    pub fn new(timestamps: Vec<DateTime<Utc>>, lower: Vec<f64>, upper: Vec<f64>, coverage: f64) -> Result<Self>;
    pub fn from_bounds(lower: Vec<f64>, upper: Vec<f64>, coverage: f64) -> Result<Self>;
    pub fn lower(&self) -> &[f64];
    pub fn upper(&self) -> &[f64];
    pub fn coverage(&self) -> f64;
    pub fn widths(&self) -> Vec<f64>;
    pub fn midpoints(&self) -> Vec<f64>;
    pub fn contains(&self, values: &[f64]) -> Vec<bool>;
    pub fn empirical_coverage(&self, actuals: &[f64]) -> Option<f64>;
}

Back to top


ConformalPredictor

Distribution-free prediction intervals with coverage guarantees.

pub struct ConformalPredictor {
    coverage: f64,
    method: ConformalMethod,
}

pub enum ConformalMethod {
    Split { cal_fraction: f64 },
    CrossVal { n_folds: usize },
    JackknifePlus,
}

impl ConformalPredictor {
    pub fn new(coverage: f64, method: ConformalMethod) -> Self;
    pub fn split(coverage: f64) -> Self;
    pub fn cross_val(coverage: f64, n_folds: usize) -> Self;
    pub fn jackknife_plus(coverage: f64) -> Self;
    pub fn fit(&self, forecasts: &[f64], actuals: &[f64]) -> Result<ConformalResult>;
    pub fn predict(&self, result: &ConformalResult, forecasts: &PointForecasts) -> PredictionIntervals;
    pub fn predict_values(&self, result: &ConformalResult, values: &[f64]) -> PredictionIntervals;
}

pub struct ConformalResult {
    pub fn scores(&self) -> &[f64];
    pub fn quantile_value(&self) -> f64;
    pub fn coverage(&self) -> f64;
    pub fn method(&self) -> &ConformalMethod;
}
Method Description
Split Fast method using a holdout calibration set
CrossVal Uses all data via k-fold cross-validation
JackknifePlus Leave-one-out with finite sample validity

Example:

use anofox_forecast::postprocess::{ConformalPredictor, ConformalMethod, PointForecasts};

let predictor = ConformalPredictor::split(0.90);
let result = predictor.fit(&historical_forecasts, &historical_actuals)?;

let new_forecasts = PointForecasts::from_values(vec![20.0, 21.0, 22.0]);
let intervals = predictor.predict(&result, &new_forecasts);

Back to top


HistoricalSimulator

Non-parametric empirical error distribution for uncertainty quantification.

pub struct HistoricalSimulator {
    quantiles: Vec<f64>,
    window_size: Option<usize>,
}

impl HistoricalSimulator {
    pub fn new(quantiles: Vec<f64>) -> Self;
    pub fn with_window(quantiles: Vec<f64>, window_size: usize) -> Self;
    pub fn fit(&self, forecasts: &[f64], actuals: &[f64]) -> Result<HistoricalSimResult>;
    pub fn predict_values(&self, result: &HistoricalSimResult, values: &[f64]) -> Result<QuantileForecasts>;
}

Back to top


NormalPredictor

Gaussian error assumption baseline for uncertainty quantification.

pub struct NormalPredictor {
    quantiles: Vec<f64>,
}

impl NormalPredictor {
    pub fn new(quantiles: Vec<f64>) -> Self;
    pub fn fit(&self, forecasts: &[f64], actuals: &[f64]) -> Result<NormalResult>;
    pub fn predict_values(&self, result: &NormalResult, values: &[f64]) -> Result<QuantileForecasts>;
}

Back to top


IDRPredictor

Isotonic Distributional Regression for state-of-the-art calibration.

pub struct IDRPredictor {
    quantiles: Vec<f64>,
}

impl IDRPredictor {
    pub fn new(quantiles: Vec<f64>) -> Self;
    pub fn fit(&self, forecasts: &[f64], actuals: &[f64]) -> Result<IDRResult>;
    pub fn predict_values(&self, result: &IDRResult, values: &[f64]) -> Result<QuantileForecasts>;
}

Back to top


QRAPredictor

Quantile Regression Averaging for ensemble combining.

pub struct QRAPredictor {
    quantiles: Vec<f64>,
    regularization: QRARegularization,
}

pub enum QRARegularization {
    None,
    L1(f64),
    L2(f64),
}

impl QRAPredictor {
    pub fn new(quantiles: Vec<f64>) -> Self;
    pub fn with_regularization(quantiles: Vec<f64>, reg: QRARegularization) -> Self;
}

Back to top


PostProcessor

Unified interface for all postprocessing methods.

pub struct PostProcessor {
    model: PostModel,
}

pub enum PostModel {
    Conformal { coverage: f64, method: ConformalMethod },
    HistoricalSim { quantiles: Vec<f64>, window_size: Option<usize> },
    Normal { quantiles: Vec<f64> },
    IDR { quantiles: Vec<f64> },
}

impl PostProcessor {
    pub fn new(model: PostModel) -> Self;
    pub fn conformal(coverage: f64) -> Self;
    pub fn historical_sim(quantiles: Vec<f64>) -> Self;
    pub fn normal(quantiles: Vec<f64>) -> Self;
    pub fn idr(quantiles: Vec<f64>) -> Self;
    pub fn train(&self, forecasts: &PointForecasts, actuals: &[f64]) -> Result<TrainedModel>;
    pub fn predict_intervals(&self, trained: &TrainedModel, forecasts: &PointForecasts) -> Result<PredictionIntervals>;
    pub fn predict_quantiles(&self, trained: &TrainedModel, forecasts: &PointForecasts) -> Result<QuantileForecasts>;
    pub fn point_to_quantiles(&self, train_forecasts: &PointForecasts, train_actuals: &[f64], predict_forecasts: &PointForecasts) -> Result<QuantileForecasts>;
}

pub enum TrainedModel {
    Conformal(ConformalResult),
    HistoricalSim(HistoricalSimResult),
    Normal(NormalResult),
    IDR(IDRResult),
}

Example:

use anofox_forecast::postprocess::{PostProcessor, PointForecasts};

// Create a conformal processor with 90% coverage
let processor = PostProcessor::conformal(0.90);

// Train on historical data
let train_forecasts = PointForecasts::from_values(historical_f);
let trained = processor.train(&train_forecasts, &historical_actuals)?;

// Generate prediction intervals
let new_forecasts = PointForecasts::from_values(new_f);
let intervals = processor.predict_intervals(&trained, &new_forecasts)?;

Back to top


Backtesting

Rolling/expanding window backtesting with horizon-aware calibration.

pub struct BacktestConfig {
    pub initial_window: usize,
    pub step: usize,
    pub horizon: usize,
    pub expanding: bool,
    pub horizon_aware: bool,
}

impl BacktestConfig {
    pub fn new() -> Self;
    pub fn initial_window(self, size: usize) -> Self;
    pub fn step(self, step: usize) -> Self;
    pub fn horizon(self, horizon: usize) -> Self;
    pub fn expanding(self, expanding: bool) -> Self;
    pub fn horizon_aware(self, aware: bool) -> Self;
}

pub struct BacktestResult {
    pub fn n_folds(&self) -> usize;
    pub fn config(&self) -> &BacktestConfig;
    pub fn folds(&self) -> impl Iterator<Item = &BacktestFold>;
    pub fn coverage(&self) -> f64;
    pub fn calibration_error(&self, target_coverage: f64) -> f64;
    pub fn interval_widths(&self) -> f64;
    pub fn coverage_by_horizon(&self) -> &HashMap<usize, f64>;
    pub fn calibrated_model(&self, processor: &PostProcessor) -> Result<TrainedModel>;
    pub fn calibrated_model_by_horizon(&self, processor: &PostProcessor) -> Result<CalibratedModelByHorizon>;
}

pub struct BacktestFold {
    pub fold_idx: usize,
    pub train_start: usize,
    pub train_end: usize,
    pub test_start: usize,
    pub test_end: usize,
    pub intervals: PredictionIntervals,
    pub actuals: Vec<f64>,
    pub coverage: f64,
    pub avg_width: f64,
}

Example:

use anofox_forecast::postprocess::{PostProcessor, BacktestConfig, PointForecasts};

let processor = PostProcessor::conformal(0.90);

let config = BacktestConfig::new()
    .initial_window(100)
    .step(10)
    .horizon(7)
    .horizon_aware(true);

let forecasts = PointForecasts::from_values(all_forecasts);
let results = processor.backtest(&forecasts, &all_actuals, config)?;

println!("Coverage: {:.1}%", results.coverage() * 100.0);
println!("Calibration error: {:.3}", results.calibration_error(0.90));

Back to top


Conformalize

Recalibrate quantile forecasts using conformal prediction.

pub fn conformalize(
    forecasts: &QuantileForecasts,
    calib_forecasts: &QuantileForecasts,
    calib_actuals: &[f64],
) -> Result<ConformalizeResult>;

pub fn conformalize_with_config(
    forecasts: &QuantileForecasts,
    calib_forecasts: &QuantileForecasts,
    calib_actuals: &[f64],
    config: ConformalizeConfig,
) -> Result<ConformalizeResult>;

pub struct ConformalizeConfig {
    method: ConformalMethod,
    symmetric: bool,
}

impl ConformalizeConfig {
    pub fn new() -> Self;
    pub fn method(self, method: ConformalMethod) -> Self;
    pub fn symmetric(self, symmetric: bool) -> Self;
}

pub struct ConformalizeResult {
    pub fn forecasts(&self) -> &QuantileForecasts;
    pub fn into_forecasts(self) -> QuantileForecasts;
    pub fn adjustments(&self) -> &[f64];
    pub fn original_coverage(&self) -> &[f64];
}

Example:

use anofox_forecast::postprocess::{conformalize, QuantileForecasts};

// Calibrate quantile forecasts
let calibrated = conformalize(&test_forecasts, &calib_forecasts, &calib_actuals)?;

// Get the recalibrated forecasts
let improved = calibrated.into_forecasts();

Back to top


Prelude

Convenience re-exports for common usage:

pub use crate::core::{Forecast, TimeSeries};
pub use crate::error::{ForecastError, Result};
pub use crate::models::Forecaster;
pub use crate::utils::{calculate_metrics, AccuracyMetrics};

Usage:

use anofox_forecast::prelude::*;

Back to top