augurs_core/
traits.rs

1use crate::{Forecast, ModelError};
2
3/// A new, unfitted time series forecasting model.
4pub trait Fit {
5    /// The type of the fitted model produced by the `fit` method.
6    type Fitted: Predict;
7
8    /// The type of error returned when fitting the model.
9    type Error: ModelError;
10
11    /// Fit the model to the training data.
12    fn fit(&self, y: &[f64]) -> Result<Self::Fitted, Self::Error>;
13}
14
15impl<F> Fit for Box<F>
16where
17    F: Fit,
18{
19    type Fitted = F::Fitted;
20    type Error = F::Error;
21    fn fit(&self, y: &[f64]) -> Result<Self::Fitted, Self::Error> {
22        (**self).fit(y)
23    }
24}
25
26/// A fitted time series forecasting model.
27pub trait Predict {
28    /// The type of error returned when predicting with the model.
29    type Error: ModelError;
30
31    /// Calculate the in-sample predictions, storing the results in the provided
32    /// [`Forecast`] struct.
33    ///
34    /// The predictions are point forecasts and optionally include
35    /// prediction intervals at the specified `level`.
36    ///
37    /// `level` should be a float between 0 and 1 representing the
38    /// confidence level of the prediction intervals. If `None` then
39    /// no prediction intervals are returned.
40    ///
41    /// # Errors
42    ///
43    /// Any errors returned by the trend model are propagated.
44    fn predict_in_sample_inplace(
45        &self,
46        level: Option<f64>,
47        forecast: &mut Forecast,
48    ) -> Result<(), Self::Error>;
49
50    /// Calculate the n-ahead predictions for the given horizon, storing the results in the
51    /// provided [`Forecast`] struct.
52    ///
53    /// The predictions are point forecasts and optionally include
54    /// prediction intervals at the specified `level`.
55    ///
56    /// `level` should be a float between 0 and 1 representing the
57    /// confidence level of the prediction intervals. If `None` then
58    /// no prediction intervals are returned.
59    ///
60    /// # Errors
61    ///
62    /// Any errors returned by the trend model are propagated.
63    fn predict_inplace(
64        &self,
65        horizon: usize,
66        level: Option<f64>,
67        forecast: &mut Forecast,
68    ) -> Result<(), Self::Error>;
69
70    /// Return the number of training data points used to fit the model.
71    ///
72    /// This is used for pre-allocating the in-sample forecasts.
73    fn training_data_size(&self) -> usize;
74
75    /// Return the n-ahead predictions for the given horizon.
76    ///
77    /// The predictions are point forecasts and optionally include
78    /// prediction intervals at the specified `level`.
79    ///
80    /// `level` should be a float between 0 and 1 representing the
81    /// confidence level of the prediction intervals. If `None` then
82    /// no prediction intervals are returned.
83    ///
84    /// # Errors
85    ///
86    /// Any errors returned by the trend model are propagated.
87    fn predict(
88        &self,
89        horizon: usize,
90        level: impl Into<Option<f64>>,
91    ) -> Result<Forecast, Self::Error> {
92        let level = level.into();
93        let mut forecast = level
94            .map(|l| Forecast::with_capacity_and_level(horizon, l))
95            .unwrap_or_else(|| Forecast::with_capacity(horizon));
96        self.predict_inplace(horizon, level, &mut forecast)?;
97        Ok(forecast)
98    }
99
100    /// Return the in-sample predictions.
101    ///
102    /// The predictions are point forecasts and optionally include
103    /// prediction intervals at the specified `level`.
104    ///
105    /// `level` should be a float between 0 and 1 representing the
106    /// confidence level of the prediction intervals. If `None` then
107    /// no prediction intervals are returned.
108    ///
109    /// # Errors
110    ///
111    /// Any errors returned by the trend model are propagated.
112    fn predict_in_sample(&self, level: impl Into<Option<f64>>) -> Result<Forecast, Self::Error> {
113        let level = level.into();
114        let mut forecast = level
115            .map(|l| Forecast::with_capacity_and_level(self.training_data_size(), l))
116            .unwrap_or_else(|| Forecast::with_capacity(self.training_data_size()));
117        self.predict_in_sample_inplace(level, &mut forecast)?;
118        Ok(forecast)
119    }
120}