///|
/// Fixed-size online window for monitoring recent surprise without retaining
/// an entire generation trace. Values are measured in bits.
pub struct SurpriseWindow {
capacity : Int
values : Array[Double]
mut next : Int
mut count : Int
mut total : Double
} derive(Debug)
///|
pub fn SurpriseWindow::new(
capacity : Int,
) -> Result[SurpriseWindow, SamplingError] {
if capacity < 1 {
return Err(InvalidParameter("window capacity must be positive"))
}
Ok({
capacity,
values: Array::make(capacity, 0.0),
next: 0,
count: 0,
total: 0.0,
})
}
///|
pub fn SurpriseWindow::count(self : SurpriseWindow) -> Int {
self.count
}
///|
pub fn SurpriseWindow::capacity(self : SurpriseWindow) -> Int {
self.capacity
}
///|
pub fn SurpriseWindow::push(
self : SurpriseWindow,
surprise : Double,
) -> Result[Unit, SamplingError] {
if !finite(surprise) || surprise < 0.0 {
return Err(InvalidParameter("surprise must be finite and non-negative"))
}
let old = if self.count == self.capacity {
self.values[self.next]
} else {
0.0
}
let new_total = self.total - old + surprise
if !finite(new_total) {
return Err(NumericalFailure)
}
self.values[self.next] = surprise
self.next = (self.next + 1) % self.capacity
if self.count < self.capacity {
self.count = self.count + 1
}
self.total = new_total
Ok(())
}
///|
pub fn SurpriseWindow::push_step(
self : SurpriseWindow,
step : Step,
) -> Result[Unit, SamplingError] {
self.push(step.observed_surprise)
}
///|
pub fn SurpriseWindow::mean(
self : SurpriseWindow,
) -> Result[Double, SamplingError] {
if self.count == 0 {
return Err(InvalidParameter("window has no observations"))
}
Ok(self.total / self.count.to_double())
}
///|
pub fn SurpriseWindow::clear(self : SurpriseWindow) -> Unit {
self.next = 0
self.count = 0
self.total = 0.0
}