use std::marker::PhantomData; use crate::{ BETA, GAMMA, drift::{ConstantDrift, Drift}, gaussian::Gaussian, time::Time, }; /// Static rating configuration: prior skill, performance noise `beta`, drift. /// /// A configuration rather than a person: the per-history temporal state /// (messages, last appearance) lives on `Competitor`. #[derive(Clone, Copy, Debug)] pub struct Rating = ConstantDrift> { pub(crate) prior: Gaussian, pub(crate) beta: f64, pub(crate) drift: D, /// Multiplier on the drift *variance* this competitor accumulates; 1.0 is /// the neutral default. Set per competitor via `Member::with_drift_scale`. pub(crate) drift_scale: f64, pub(crate) _time: PhantomData, } impl> Rating { pub fn new(prior: Gaussian, beta: f64, drift: D) -> Self { Self { prior, beta, drift, drift_scale: 1.0, _time: PhantomData, } } /// Scale how fast this competitor drifts, relative to `drift`. /// /// Multiplies the drift *variance*, so the scale is in the same units as /// `gamma`. `0.0` pins the competitor still. #[must_use] pub fn with_drift_scale(mut self, drift_scale: f64) -> Self { self.drift_scale = drift_scale; self } /// The configured prior skill estimate. #[must_use] pub fn prior(&self) -> Gaussian { self.prior } /// Performance noise: how much a single showing varies around the skill. #[must_use] pub fn beta(&self) -> f64 { self.beta } /// The drift model governing how skill may move between events. #[must_use] pub fn drift(&self) -> D { self.drift } /// This competitor's multiplier on the drift variance; 1.0 is neutral. #[must_use] pub fn drift_scale(&self) -> f64 { self.drift_scale } /// Drift variance accumulated over `from -> to`, scaled for this competitor. /// /// The single place the scale is applied for a `Time`-typed span. Callers /// must go through this rather than `self.drift` directly, so a competitor's /// scale cannot be silently skipped. pub(crate) fn drift_variance_delta(&self, from: &T, to: &T) -> f64 { self.drift.variance_delta(from, to) * self.drift_scale * self.drift_scale } /// Drift variance for a cached elapsed count, scaled for this competitor. /// /// The counterpart of `drift_variance_delta` for the cached-elapsed paths. pub(crate) fn drift_variance_for_elapsed(&self, elapsed: i64) -> f64 { self.drift.variance_for_elapsed(elapsed) * self.drift_scale * self.drift_scale } pub(crate) fn performance(&self) -> Gaussian { self.prior.forget(self.beta.powi(2)) } } impl Default for Rating { fn default() -> Self { Self { prior: Gaussian::default(), beta: BETA, drift: ConstantDrift(GAMMA), drift_scale: 1.0, _time: PhantomData, } } }