diff --git a/benches/batch.rs b/benches/batch.rs index b84f653..1f2d4d2 100644 --- a/benches/batch.rs +++ b/benches/batch.rs @@ -11,9 +11,7 @@ use criterion::{Criterion, criterion_group, criterion_main}; use smallvec::smallvec; -use trueskill_tt::{ - ConstantDrift, ConvergenceOptions, Event, History, Member, Outcome, Team, -}; +use trueskill_tt::{ConstantDrift, ConvergenceOptions, Event, History, Member, Outcome, Team}; fn criterion_benchmark(criterion: &mut Criterion) { let build = || { diff --git a/src/convergence.rs b/src/convergence.rs index e7041fd..ee7e87a 100644 --- a/src/convergence.rs +++ b/src/convergence.rs @@ -68,11 +68,7 @@ impl Default for ConvergenceOptions { /// [`InferenceError::NotConverged`](crate::InferenceError::NotConverged) there. /// From [`History::converge_partial`](crate::History::converge_partial) it may /// not be, and `converged` is what says so. -#[derive(Clone, Debug)] -#[must_use = "from `converge_partial` this may describe a fit that stopped at \ - `max_iter`, which is wrong by a little rather than loudly \ - broken — check `converged`, or bind it to `_` to say you have \ - decided not to"] +#[derive(Clone, Debug, PartialEq)] pub struct ConvergenceReport { pub iterations: usize, pub final_step: (f64, f64), diff --git a/src/event.rs b/src/event.rs index f547cc3..b36278c 100644 --- a/src/event.rs +++ b/src/event.rs @@ -11,7 +11,7 @@ use smallvec::SmallVec; use crate::{gaussian::Gaussian, outcome::Outcome, time::Time}; /// A single match at time `time` involving some number of teams. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct Event { pub time: T, pub teams: SmallVec<[Team; 4]>, @@ -19,7 +19,7 @@ pub struct Event { } /// A team: list of members competing together. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct Team { pub members: SmallVec<[Member; 4]>, } @@ -61,7 +61,7 @@ impl Default for Team { /// for one competitor within a single batch is /// `InferenceError::ConflictingCompetitorConfig`: events in a batch have no /// order, so there would be no well-defined winner. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct Member { pub key: K, pub weight: f64, diff --git a/src/event_builder.rs b/src/event_builder.rs index ecc1555..6ed9255 100644 --- a/src/event_builder.rs +++ b/src/event_builder.rs @@ -9,6 +9,8 @@ use crate::{ time::Time, }; +#[must_use = "an event is only recorded by `.commit()`; a dropped builder \ + silently ingests nothing"] pub struct EventBuilder<'h, T, D, O, K> where T: Time, diff --git a/src/factor/mod.rs b/src/factor/mod.rs index 4578755..8b84c3d 100644 --- a/src/factor/mod.rs +++ b/src/factor/mod.rs @@ -44,7 +44,6 @@ impl VarStore { id } - #[must_use] pub fn get(&self, id: VarId) -> Gaussian { self.marginals[id.0 as usize] } diff --git a/src/game.rs b/src/game.rs index 8c97fed..d946cfb 100644 --- a/src/game.rs +++ b/src/game.rs @@ -92,6 +92,7 @@ impl Default for GameOptions { /// can be returned freely from public constructors. The inference inputs /// themselves are not retained — nothing reads them back. #[derive(Debug)] +#[must_use] pub struct OwnedGame> { teams: Vec>>, pub(crate) likelihoods: Vec>, diff --git a/src/gaussian.rs b/src/gaussian.rs index 08ba486..58a1884 100644 --- a/src/gaussian.rs +++ b/src/gaussian.rs @@ -11,6 +11,7 @@ use crate::{MU, N_INF, SIGMA}; /// the stored fields with no `sqrt` or reciprocal in the hot path. `mu()` and /// `sigma()` are accessors computed on demand. #[derive(Clone, Copy, PartialEq, Debug)] +#[must_use] pub struct Gaussian { pi: f64, tau: f64, @@ -44,7 +45,6 @@ impl Gaussian { /// small truncated sigma and inference must not panic. It is worth knowing /// that such a `Gaussian` is not equal to itself, so two identical /// declarations of one can be reported as conflicting. - #[must_use] pub const fn from_ms(mu: f64, sigma: f64) -> Self { // NaN is admitted on purpose. A broken fit legitimately produces a NaN // sigma — `sqrt` of a negative truncated variance — and the design is @@ -243,7 +243,6 @@ impl Gaussian { /// Used by within-game inference to stabilise oscillating fixed-point /// loops on hard graphs. `alpha = 1.0` returns `new` exactly; /// `alpha < 1.0` shrinks each per-step update. - #[must_use] pub fn damp_natural(self, new: Gaussian, alpha: f64) -> Gaussian { Gaussian::from_natural( alpha * new.pi() + (1.0 - alpha) * self.pi(), diff --git a/src/history.rs b/src/history.rs index 98fbc28..ebc3a63 100644 --- a/src/history.rs +++ b/src/history.rs @@ -24,7 +24,8 @@ use crate::{ tuple_gt, tuple_max, }; -#[derive(Clone)] +#[derive(Clone, Debug)] +#[must_use = "a builder does nothing until `.build()`"] pub struct HistoryBuilder< T: Time = i64, D: Drift = ConstantDrift, @@ -197,7 +198,6 @@ impl, O: Observer, K: Eq + Hash + Clone> HistoryBuilder< /// assert!(h.current_skill(&"alice").unwrap().mu() > 0.0); /// # Ok::<(), trueskill_tt::InferenceError>(()) /// ``` - #[must_use] pub fn time_type(self) -> HistoryBuilder where T2: Time, @@ -232,7 +232,6 @@ impl, O: Observer, K: Eq + Hash + Clone> HistoryBuilder< /// h.record_winner(&"alice".to_string(), &"bob".to_string(), 1)?; /// # Ok::<(), trueskill_tt::InferenceError>(()) /// ``` - #[must_use] pub fn key_type(self) -> HistoryBuilder { HistoryBuilder { mu: self.mu, @@ -418,7 +417,6 @@ impl Default for History { } impl History { - #[must_use] pub fn builder() -> HistoryBuilder { HistoryBuilder::default() } @@ -440,7 +438,6 @@ impl HistoryBuilder(()) /// ``` - #[must_use] pub fn new() -> Self { Self::default() } @@ -455,6 +452,7 @@ impl, O: Observer, K: Eq + Hash + Clone> History(&self, key: &Q) -> Option where K: Borrow, @@ -563,6 +561,7 @@ impl, O: Observer, K: Eq + Hash + Clone> History(()) /// ``` + #[must_use] pub fn competitors(&self) -> impl ExactSizeIterator { self.keys.keys() } @@ -580,6 +579,7 @@ impl, O: Observer, K: Eq + Hash + Clone> History HashMap> { #[cfg(feature = "rayon")] { @@ -728,6 +728,7 @@ impl, O: Observer, K: Eq + Hash + Clone> History(&self, key: &Q) -> Option where K: std::borrow::Borrow, @@ -741,6 +742,7 @@ impl, O: Observer, K: Eq + Hash + Clone> History(&self, key: &Q) -> Vec<(T, Gaussian)> where K: std::borrow::Borrow, @@ -764,6 +766,7 @@ impl, O: Observer, K: Eq + Hash + Clone> History HashMap> { let mut data: HashMap> = HashMap::new(); @@ -786,6 +789,7 @@ impl, O: Observer, K: Eq + Hash + Clone> History(&self, key: &Q) -> Vec<(T, Gaussian)> where K: Borrow, @@ -841,12 +845,14 @@ impl, O: Observer, K: Eq + Hash + Clone> History f64 { self.log_evidence_internal(false, &[]) } /// Log-evidence restricted to time slices containing at least one of the /// given keys. Useful for leave-one-out cross-validation. + #[must_use] pub fn log_evidence_for(&self, keys: &[&Q]) -> f64 where K: std::borrow::Borrow, @@ -1759,6 +1765,8 @@ impl, O: Observer, K: Eq + Hash + Clone> History Result { use std::time::Instant; diff --git a/src/lib.rs b/src/lib.rs index 7927e63..4f37b3d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,12 +104,10 @@ use std::{ f64::consts::{FRAC_1_SQRT_2, FRAC_2_SQRT_PI, SQRT_2}, }; +mod acquisition; #[cfg(feature = "approx")] mod approx; pub(crate) mod arena; -mod time; -mod time_slice; -mod acquisition; mod color_group; mod competitor; mod convergence; @@ -130,6 +128,8 @@ mod predict; pub(crate) mod quadrature; mod rating; pub(crate) mod storage; +mod time; +mod time_slice; pub use acquisition::expected_information_gain; pub use convergence::{ConvergenceOptions, ConvergenceReport}; diff --git a/src/predict.rs b/src/predict.rs index ac7cfe4..081979f 100644 --- a/src/predict.rs +++ b/src/predict.rs @@ -456,6 +456,7 @@ pub(crate) fn ranking_probability( /// `Game::ranked` asks "what would we believe if *this* happened", which is /// what an expected-information-gain calculation needs alongside the weight. #[derive(Clone, Debug, PartialEq)] +#[must_use] pub struct Prediction { outcomes: Vec<(Vec, f64)>, } diff --git a/src/rating.rs b/src/rating.rs index a58fabc..f7faef3 100644 --- a/src/rating.rs +++ b/src/rating.rs @@ -11,7 +11,7 @@ use crate::{ /// /// A configuration rather than a person: the per-history temporal state /// (messages, last appearance) lives on `Competitor`. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct Rating = ConstantDrift> { pub(crate) prior: Gaussian, pub(crate) beta: f64, @@ -61,7 +61,6 @@ impl> Rating { } /// The configured prior skill estimate. - #[must_use] pub fn prior(&self) -> Gaussian { self.prior }