///|
/// `PageHinkley` implements the Page-Hinkley test for online change point detection.
pub struct PageHinkley {
mut target_mean : Double
control_limit : Double
delta : Double
alpha : Double
mut sum : Double
mut min_sum : Double
mut n : Int
}
///|
/// Creates a new Page-Hinkley detector.
pub fn PageHinkley::new(
target_mean? : Double = 0.0,
control_limit? : Double = 10.0,
delta? : Double = 0.5,
alpha? : Double = 0.99,
) -> PageHinkley {
{ target_mean, control_limit, delta, alpha, sum: 0.0, min_sum: 0.0, n: 0 }
}
///|
/// Updates the Page-Hinkley detector with a new value and returns true if a change is detected.
pub fn PageHinkley::update(self : PageHinkley, value : Double) -> Bool {
self.n += 1
// Update the mean incrementally with forgetting factor alpha
self.target_mean = self.target_mean * self.alpha + value * (1.0 - self.alpha)
// Update cumulative sum
self.sum += value - self.target_mean - self.delta
if self.sum < self.min_sum {
self.min_sum = self.sum
}
if self.sum - self.min_sum > self.control_limit {
self.reset()
return true
}
return false
}
///|
/// Resets the internal accumulators.
pub fn PageHinkley::reset(self : PageHinkley) -> Unit {
self.sum = 0.0
self.min_sum = 0.0
self.n = 0
}
///|
/// Rich result form of `update`, retaining direction and cumulative evidence.
pub fn PageHinkley::update_result(
self : PageHinkley,
value : Double,
index? : Int = 0,
) -> DetectionResult {
let delta = value - self.target_mean
let changed = self.update(value)
let evidence = self.sum - self.min_sum
let score = if self.control_limit <= 0.0 {
0.0
} else {
evidence / self.control_limit
}
DetectionResult::new(
changed,
score,
clamp_probability(score / (score + 1.0)),
direction_for_delta(delta),
index,
evidence~,
)
}