vpp_sim/
forecast.rs

1//! Forecasting utilities for the simulator.
2
3/// Naive "tomorrow is today" forecaster.
4///
5/// This forecast simply copies the provided baseline and repeats/truncates
6/// it to match the requested simulation horizon.
7#[derive(Debug, Default, Clone, Copy)]
8pub struct NaiveForecast;
9
10impl NaiveForecast {
11    /// Produce a naive forecast for the given horizon.
12    ///
13    /// # Arguments
14    ///
15    /// * `baseline` - Historical or baseline values used as the forecast template
16    /// * `horizon` - Number of steps to forecast
17    ///
18    /// # Returns
19    ///
20    /// A vector of forecast values with length equal to `horizon`.
21    pub fn forecast(&self, baseline: &[f32], horizon: usize) -> Vec<f32> {
22        if horizon == 0 {
23            return Vec::new();
24        }
25
26        if baseline.is_empty() {
27            return vec![0.0; horizon];
28        }
29
30        if baseline.len() == horizon {
31            return baseline.to_vec();
32        }
33
34        if baseline.len() > horizon {
35            return baseline[..horizon].to_vec();
36        }
37
38        let mut forecast = Vec::with_capacity(horizon);
39        while forecast.len() < horizon {
40            for value in baseline {
41                if forecast.len() == horizon {
42                    break;
43                }
44                forecast.push(*value);
45            }
46        }
47        forecast
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use super::NaiveForecast;
54
55    #[test]
56    fn forecast_matches_horizon_length() {
57        let baseline = vec![1.0, 2.0, 3.0];
58        let forecast = NaiveForecast.forecast(&baseline, 7);
59        assert_eq!(forecast.len(), 7);
60    }
61
62    #[test]
63    fn forecast_copies_baseline_when_equal() {
64        let baseline = vec![0.5, 1.0, 1.5, 2.0];
65        let forecast = NaiveForecast.forecast(&baseline, baseline.len());
66        assert_eq!(forecast, baseline);
67    }
68}