///|
pub fn WindowState::new(config : WindowConfig) -> WindowState {
{ values: [], target_size: config.min_size, config }
}
///|
pub fn mean(values : Array[Double]) -> Double {
if values.length() == 0 {
0.0
} else {
let mut total = 0.0
for value in values {
total += value
}
total / values.length().to_double()
}
}
///|
pub fn variance(values : Array[Double]) -> Double {
if values.length() <= 1 {
0.0
} else {
let avg = mean(values)
let mut total = 0.0
for value in values {
total += square(value - avg)
}
total / values.length().to_double()
}
}
///|
fn trim_to(values : Array[Double], size : Int) -> Array[Double] {
let out : Array[Double] = []
let start = if values.length() > size { values.length() - size } else { 0 }
for i in start.. WindowState {
let values = self.values.copy()
values.push(value)
let recent = trim_to(values, self.config.max_size)
let v = variance(recent)
let next_size = if v <= self.config.low_variance {
self.target_size + self.config.expansion_step
} else if v >= self.config.high_variance {
self.target_size - self.config.shrink_step
} else {
self.target_size
}
let target_size = clamp(
next_size.to_double(),
self.config.min_size.to_double(),
self.config.max_size.to_double(),
).to_int()
{ ..self, values: trim_to(recent, target_size), target_size }
}
///|
pub fn WindowState::average(self : WindowState) -> Double {
mean(self.values)
}
///|
pub fn WindowState::stability(self : WindowState) -> Double {
1.0 / (1.0 + variance(self.values))
}