///|
/// `Bayesian` implements a simplified Bayesian Online Change Point Detection using a Normal-Gamma conjugate prior.
pub struct Bayesian {
hazard_rate : Double
mut run_length_probs : Array[Double]
// Sufficient statistics for each run length
mut mu_t : Array[Double]
mut kappa_t : Array[Double]
mut alpha_t : Array[Double]
mut beta_t : Array[Double]
// Prior parameters
mu0 : Double
kappa0 : Double
alpha0 : Double
beta0 : Double
max_run_length : Int
}
///|
/// Creates a new Bayesian Online Change Point Detector.
pub fn Bayesian::new(
hazard_rate? : Double = 0.01,
mu0? : Double = 0.0,
kappa0? : Double = 1.0,
alpha0? : Double = 1.0,
beta0? : Double = 1.0,
max_run_length? : Int = 100,
) -> Bayesian {
{
hazard_rate,
run_length_probs: [1.0],
mu_t: [mu0],
kappa_t: [kappa0],
alpha_t: [alpha0],
beta_t: [beta0],
mu0,
kappa0,
alpha0,
beta0,
max_run_length,
}
}
///|
/// Student-T probability density function (simplified)
fn student_t_pdf(
x : Double,
mu : Double,
variance : Double,
_nu : Double,
) -> Double {
// We use a simplified Gaussian approximation for speed since this is a demonstration
let diff = x - mu
let exp_val = @math.exp(-(diff * diff) / (2.0 * variance))
exp_val / (2.0 * 3.14159265358979323846 * variance).sqrt()
}
///|
/// Updates the detector and returns the probability of a change point at the current step.
pub fn Bayesian::update(self : Bayesian, value : Double) -> Double {
let len = self.run_length_probs.length()
// 1. Evaluate predictive probabilities for each run length
let pred_probs = Array::make(len, 0.0)
for i in 0.. self.max_run_length {
self.max_run_length
} else {
new_probs.length()
}
let truncated_probs = Array::make(truncated_len, 0.0)
for i in 0.. DetectionResult {
let probability = self.update(value)
DetectionResult::new(
probability > 0.5,
probability,
probability,
DistributionShift,
index,
evidence=probability,
)
}