use crate::forecasting::ExpSmoothing;
use crate::time_series::{TimeSeries, Style};
use crate::regression::LinearRegression;
use crate::plotable::Plotable;
use crate::time_series::Grouper;
use plotlib::view::{View, ContinuousView};
use plotlib::repr::Plot;
use plotlib::page::Page;
const DEFAULT_ALPHA: f64 = 0.4;
pub struct Dumb {
original: TimeSeries,
expsmooth: Option<ExpSmoothing>,
linear_reg: Option<LinearRegression>,
season: usize,
prediction: Vec<(f64, f64)>,
}
impl Dumb {
pub fn new(time_series: &TimeSeries) -> Self {
let mut this = Self {
original: time_series.clone(),
expsmooth: None,
linear_reg: None,
season: 0,
prediction: Vec::new(),
};
this.expsmooth = Some(
ExpSmoothing::new(time_series).with_alpha(DEFAULT_ALPHA)
);
this.linear_reg = Some(LinearRegression::new(time_series));
this
}
pub fn with_season(mut self, season: usize) -> Self {
self.season = season; self.update_data();
self
}
fn update_data(&mut self) {
if self.season == 0 {
panic!("No season length set for Dumb")
}
let mut sm = self.exp_smooth().as_time_series().get_data();
sm.insert(0, (1.0, -1.0));
let mut sm = TimeSeries::from_pairs_vec(sm);
if let Some(expsmooth) = &self.expsmooth {
self.prediction = Vec::new(); let alpha = expsmooth.alpha();
let len = sm.len();
let r = alpha * sm.get_range_at(len - 1) + (1.0 - alpha) * expsmooth.as_time_series().get_range_at(len - 1);
self.prediction.push((1.0, r));
let mut past = Vec::new();
let mut c = 1;
for seas in 0..(sm.len() / self.season) as usize {
past.push(vec![0.0; self.season]);
for i in 0..self.season {
past[seas][i] = sm.get_range_at(c);
c += 1;
}
}
let mut months = Vec::new(); for month in 0..self.season {
months.push(vec![0.0; past.len()]);
for season in 0..past.len() {
months[month][season] = past[season][month];
}
}
let mut x_points = Vec::new();
for i in 0..months.len() + 1 { x_points.push(vec![0.0; past.len()]);
for season in 0..months[0].len() { x_points[i][season] = (i + season*self.season) as f64;
}
}
let regression_points: Vec<Vec<f64>> = x_points[1..].iter().map(
|x| {x.iter().map(
|y| {
self.get_linear_regression().calculate(y.clone())
}
).collect()}
).collect();
let smooth = self.exp_smooth().as_time_series();
let x_points = (&x_points[2..]).to_vec();
let regression_points = (®ression_points).to_vec();
let mut distances = Vec::new();
for i in 0..x_points.len() { distances.push(Vec::new());
for j in 0..x_points[i].len() { distances[i].push(smooth.get_range_at(x_points[i][j] as usize) - regression_points[i][j]);
}
}
let mut factors = Vec::new();
for i in 0..distances.len() {
factors.push(Vec::new());
for j in 0..distances[i].len() - 1 {
let mut growth = distances[i][j + 1] / distances[i][j];
if distances[i][j] < 0.0 && distances[i][j + 1] > 0.0 { growth = -1.0 * growth / 2.0;
}
if growth > 10.0 || growth < -10.0 {
growth = DEFAULT_ALPHA * growth;
}
factors[i].push(growth); }
}
let mut pro_factors = Vec::new();
for i in 0..factors.len() { if factors[i].len() != 2 {
panic!("HARDCODED FOR 2 FACTORS IN 3 YEARS");
}
pro_factors.push(factors[i][0] * 0.8 + factors[i][1]);
}
let mut last_d = Vec::new(); for i in 0..distances.len() {
last_d.push(distances[i][2] * pro_factors[i]);
}
println!("d = {:?}", distances);
println!("lastd = {:?}", last_d);
let mut finales = Vec::new();
for i in 0..last_d.len() {
finales.push(last_d[i] + self.get_linear_regression().calculate(i as f64 + 36.0));
}
let mut counter = 38.0; for element in finales.iter() {
self.prediction.push((counter, element.clone().abs().floor()));
counter += 1.0;
}
self.prediction[0].0 = 37.0;
println!("finales: {:?}", self.prediction());
} else {
panic!("Can't update Dumbs data, no expsmooth set.");
}
}
pub fn prediction(&self) -> Vec<(f64, f64)> {
self.prediction.clone()
}
pub fn get_linear_regression(&self) -> LinearRegression {
if let Some(reg) = &self.linear_reg {
reg.clone()
} else {
panic!("No linear regression calculated for Dumb");
}
}
fn exp_smooth(&self) -> ExpSmoothing {
if let Some(ex) = &self.expsmooth {
ex.clone()
} else {
panic!("Dumb has no exponential smoothing set")
}
}
pub fn plot_to_file(&self, filename: String) {
Page::single(
self.plot().as_ref()
).save(filename).unwrap();
}
}
impl Plotable for Dumb {
fn plot(&self) -> Box<dyn View> {
let mut tm = self.original.clone();
let smooth = self.exp_smooth();
let linear = self.get_linear_regression();
let pred = TimeSeries::from_pairs_vec(self.prediction());
let mut group = Grouper::new(&tm)
.last_with_style(Style::from_color("#000000"))
.add(&smooth.as_time_series())
.last_with_style(Style::from_color("#af0af6"))
.add(&linear.as_time_series())
.last_with_style(Style::from_color("#87faa4"))
.add(&pred)
.last_with_style(Style::from_color("#ff00a2"));
group.plot()
}
fn as_plot(&self) -> Plot {
unimplemented!()
}
}