From b553c630f5617bce9ef42f5a76da8eeaa24be9a9 Mon Sep 17 00:00:00 2001 From: Anders Olsson Date: Thu, 10 Sep 2026 06:49:22 +0200 Subject: [PATCH] refactor!: K comes first in History, HistoryBuilder and Joint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `K` is the one type parameter people change, and it was last. Naming a history in a struct field meant writing all four to say one thing: struct Ladder { history: History } struct Analysis<'h> { joint: Joint<'h, i64, ConstantDrift, NullObserver, &'static str> } Now: struct Ladder { history: History } struct Analysis<'h> { joint: Joint<'h> } `History`, all four defaulted. Bounds may reference later parameters, so `D: Drift = ConstantDrift` is legal in third position. `Joint` gains the same defaults, so `Joint<'h, String>` spells it. 72 call sites swapped, and the reorder makes most of them shorter: 18 now read `History` and the `&'static str` ones read `History`. The two turbofished builders shrink from `HistoryBuilder::::new()` to `HistoryBuilder::::new()`. `Joint` keeps `O` structurally, defaulted rather than removed. #72 notes it never touches the observer, which is true — but it borrows the whole `&'h History` and calls `History::resolve_terms`, so dropping the parameter means either a view type or moving that method off `History`. The default already buys the entire user-visible benefit, which was the spelling. Refs #72. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_011hcFjNDmHXZF8URGLku5zZ --- benches/history_converge.rs | 6 +- benches/ingest.rs | 6 +- benches/joint.rs | 4 +- benches/scored.rs | 2 +- examples/atp.rs | 2 +- src/event_builder.rs | 4 +- src/history.rs | 140 ++++++++++++++---------- tests/additive_model.rs | 2 +- tests/convergence_strictness.rs | 4 +- tests/cross_process_determinism.rs | 5 +- tests/degenerate_inputs.rs | 4 +- tests/drift_scale.rs | 6 +- tests/event_builder_members.rs | 2 +- tests/evidence_matrix.rs | 6 +- tests/honest_accessors.rs | 6 +- tests/ingestion_equivalence.rs | 2 +- tests/ingestion_shape.rs | 3 +- tests/joint_handle.rs | 4 +- tests/key_ergonomics.rs | 6 +- tests/large_history_converges_finite.rs | 4 +- tests/marginal_calibration.rs | 8 +- tests/predict_margin.rs | 8 +- tests/prediction_guards.rs | 4 +- tests/reconvergence_equivalence.rs | 4 +- tests/registration.rs | 2 +- tests/time_axis.rs | 2 +- tests/time_expanded_joint.rs | 2 +- tests/trait_impls.rs | 2 +- tests/variance_reduction.rs | 4 +- 29 files changed, 129 insertions(+), 125 deletions(-) diff --git a/benches/history_converge.rs b/benches/history_converge.rs index 95cd5f1..7ec56ed 100644 --- a/benches/history_converge.rs +++ b/benches/history_converge.rs @@ -25,16 +25,14 @@ use criterion::{BatchSize, Criterion, criterion_group, criterion_main}; use smallvec::smallvec; -use trueskill_tt::{ - ConstantDrift, ConvergenceOptions, Event, History, Member, NullObserver, Outcome, Team, -}; +use trueskill_tt::{ConstantDrift, ConvergenceOptions, Event, History, Member, Outcome, Team}; fn build_history_1v1( n_events: usize, n_competitors: usize, events_per_slice: usize, seed: u64, -) -> History { +) -> History { let mut rng = seed; let mut next = || { rng = rng diff --git a/benches/ingest.rs b/benches/ingest.rs index 16cb5b0..452f195 100644 --- a/benches/ingest.rs +++ b/benches/ingest.rs @@ -32,8 +32,7 @@ fn bench_ingest(c: &mut Criterion) { b.iter_batched( || events(n, 0), |evs| { - let mut h: History = - History::builder().key_type::().build(); + let mut h: History = History::builder().key_type::().build(); for ev in evs { h.add_events(std::iter::once(ev)).unwrap(); } @@ -47,8 +46,7 @@ fn bench_ingest(c: &mut Criterion) { b.iter_batched( || events(n, 0), |evs| { - let mut h: History = - History::builder().key_type::().build(); + let mut h: History = History::builder().key_type::().build(); h.add_events(evs).unwrap(); black_box(h.time_slices_len()) }, diff --git a/benches/joint.rs b/benches/joint.rs index f6c0eb1..e56b9cd 100644 --- a/benches/joint.rs +++ b/benches/joint.rs @@ -10,8 +10,8 @@ use smallvec::smallvec; use trueskill_tt::{ConstantDrift, ConvergenceOptions, Event, History, Member, Outcome, Team}; /// 30 slices of 8 duels: 480 appearances over 100 competitors. -fn fitted() -> History { - let mut h: History = History::builder() +fn fitted() -> History { + let mut h: History = History::builder() .key_type::() .mu(0.0) .sigma(6.0) diff --git a/benches/scored.rs b/benches/scored.rs index f0f4b6a..dbfb079 100644 --- a/benches/scored.rs +++ b/benches/scored.rs @@ -5,7 +5,7 @@ use trueskill_tt::{ConstantDrift, Event, History, Member, Outcome, Team}; fn bench_scored_history(c: &mut Criterion) { c.bench_function("scored_history_60_events_30_iter", |bencher| { bencher.iter(|| { - let mut h: History = History::builder() + let mut h: History = History::builder() .key_type::() .mu(25.0) .sigma(25.0 / 3.0) diff --git a/examples/atp.rs b/examples/atp.rs index 2274ef1..ae1ebb0 100644 --- a/examples/atp.rs +++ b/examples/atp.rs @@ -43,7 +43,7 @@ fn main() { } } - let mut hist: History = History::builder() + let mut hist: History = History::builder() .key_type::() .sigma(1.6) .drift(ConstantDrift::new(0.036)) diff --git a/src/event_builder.rs b/src/event_builder.rs index e866dc6..abad038 100644 --- a/src/event_builder.rs +++ b/src/event_builder.rs @@ -45,7 +45,7 @@ where O: Observer, K: Eq + std::hash::Hash + Clone, { - history: &'h mut History, + history: &'h mut History, event: Event, current_team_idx: Option, /// First validation failure seen while building, surfaced by `commit`. @@ -65,7 +65,7 @@ where O: Observer, K: Eq + std::hash::Hash + Clone, { - pub(crate) fn new(history: &'h mut History, time: T) -> Self { + pub(crate) fn new(history: &'h mut History, time: T) -> Self { Self { history, event: Event { diff --git a/src/history.rs b/src/history.rs index bc4d9e4..9b0c395 100644 --- a/src/history.rs +++ b/src/history.rs @@ -32,6 +32,9 @@ use crate::{ /// an unknown key. None of them can be changed after `build`, because they /// define the model the fit is of. /// +/// Parameterised as [`History`] is, `HistoryBuilder`, with the +/// same defaults. +/// /// Two of the setters change the builder's *type* rather than a field — /// [`HistoryBuilder::drift`] and [`HistoryBuilder::observer`] — so bind the /// result rather than calling them on a `&mut`. [`HistoryBuilder::time_type`] @@ -40,10 +43,10 @@ use crate::{ #[derive(Clone, Debug)] #[must_use = "a builder does nothing until `.build()`"] pub struct HistoryBuilder< + K: Eq + Hash + Clone = &'static str, T: Time = i64, D: Drift = ConstantDrift, O: Observer = NullObserver, - K: Eq + Hash + Clone = &'static str, > { mu: f64, sigma: f64, @@ -58,7 +61,7 @@ pub struct HistoryBuilder< _key: PhantomData, } -impl, O: Observer, K: Eq + Hash + Clone> HistoryBuilder { +impl, O: Observer, K: Eq + Hash + Clone> HistoryBuilder { /// Prior mean skill. /// /// # Panics @@ -150,7 +153,7 @@ impl, O: Observer, K: Eq + Hash + Clone> HistoryBuilder< /// implementation. `converge` checks the variance each competitor actually /// accumulates and reports `InvalidParameter` if it is negative or /// non-finite. - pub fn drift>(self, drift: D2) -> HistoryBuilder { + pub fn drift>(self, drift: D2) -> HistoryBuilder { HistoryBuilder { drift, mu: self.mu, @@ -249,7 +252,7 @@ impl, O: Observer, K: Eq + Hash + Clone> HistoryBuilder< /// assert!(h.current_skill(&"alice").unwrap().mu() > 0.0); /// # Ok::<(), trueskill_tt::InferenceError>(()) /// ``` - pub fn time_type(self) -> HistoryBuilder + pub fn time_type(self) -> HistoryBuilder where T2: Time, D: Drift, @@ -283,7 +286,7 @@ impl, O: Observer, K: Eq + Hash + Clone> HistoryBuilder< /// h.record_winner(&"alice".to_string(), &"bob".to_string(), 1)?; /// # Ok::<(), trueskill_tt::InferenceError>(()) /// ``` - pub fn key_type(self) -> HistoryBuilder { + pub fn key_type(self) -> HistoryBuilder { HistoryBuilder { mu: self.mu, sigma: self.sigma, @@ -305,7 +308,7 @@ impl, O: Observer, K: Eq + Hash + Clone> HistoryBuilder< /// observer by value; to keep a handle on one that accumulates state, pass /// an `Arc` and keep a clone, or read it back with /// [`History::observer`] / [`History::into_observer`]. - pub fn observer>(self, observer: O2) -> HistoryBuilder { + pub fn observer>(self, observer: O2) -> HistoryBuilder { HistoryBuilder { mu: self.mu, sigma: self.sigma, @@ -324,7 +327,7 @@ impl, O: Observer, K: Eq + Hash + Clone> HistoryBuilder< /// Finish configuring and produce an empty [`History`]. /// /// Every parameter was validated as it was set, so this cannot fail. - pub fn build(self) -> History { + pub fn build(self) -> History { History { size: 0, time_slices: Vec::new(), @@ -351,7 +354,7 @@ impl, O: Observer, K: Eq + Hash + Clone> HistoryBuilder< /// That, plus private fields and no `new`, meant a downstream crate could not /// construct a `History` on any other time axis at all — `Untimed` and every /// custom `Drift` were public but unreachable. -impl Default for HistoryBuilder { +impl Default for HistoryBuilder { fn default() -> Self { Self { mu: MU, @@ -443,11 +446,25 @@ impl CompetitorConfig { /// /// `tests/reconvergence_equivalence.rs` pins the path-independence this rests /// on. +/// The top-level container: ingests events, runs forward/backward message +/// passing, and answers queries about the fit. +/// +/// # Type parameters +/// +/// `History` — key type, time type, drift model, observer — all +/// defaulted, so `History` alone means `&'static str` keys on an `i64` time +/// axis with [`ConstantDrift`] and no observer, and `History` is the +/// whole spelling for owned keys. +/// +/// `K` is first because it is the one people change. It used to be last, so +/// naming a history in a struct field meant writing all four: +/// `History` to say "keys are +/// `String`". See #72. pub struct History< + K: Eq + Hash + Clone = &'static str, T: Time = i64, D: Drift = ConstantDrift, O: Observer = NullObserver, - K: Eq + Hash + Clone = &'static str, > { size: usize, pub(crate) time_slices: Vec>, @@ -470,25 +487,25 @@ pub struct History< declared: HashMap, } -impl Default for History { +impl Default for History { fn default() -> Self { HistoryBuilder::default().build() } } -impl History { +impl History { /// Start configuring a history. /// /// The defaults are `i64` time, [`ConstantDrift`], no observer and /// `&'static str` keys. Any of the four can be changed — the two type /// parameters that no argument would pin are named with /// [`HistoryBuilder::time_type`] and [`HistoryBuilder::key_type`]. - pub fn builder() -> HistoryBuilder { + pub fn builder() -> HistoryBuilder { HistoryBuilder::default() } } -impl HistoryBuilder { +impl HistoryBuilder { /// A builder on any time axis and key type, with the default drift and no /// observer. /// @@ -499,7 +516,7 @@ impl HistoryBuilder::new().build(); + /// let mut h = HistoryBuilder::::new().build(); /// h.record_winner(&"alice".to_string(), &"bob".to_string(), Untimed)?; /// h.converge()?; /// # Ok::<(), trueskill_tt::InferenceError>(()) @@ -535,7 +552,7 @@ impl HistoryBuilder, O: Observer, K: Eq + Hash + Clone> History { +impl, O: Observer, K: Eq + Hash + Clone> History { /// Promote a key to its [`Index`], creating the entry if it is new. /// /// Crate-internal since #73: interning reserves a storage slot and nothing @@ -550,7 +567,7 @@ impl, O: Observer, K: Eq + Hash + Clone> History, O: Observer, K: Eq + Hash + Clone> History { +impl, O: Observer, K: Eq + Hash + Clone> History { fn iteration(&mut self) -> (f64, f64) { let mut step = (0.0, 0.0); @@ -1577,7 +1594,7 @@ impl, O: Observer, K: Eq + Hash + Clone> History Result, InferenceError> { + pub fn joint(&self) -> Result, InferenceError> { if self.time_slices.is_empty() { return Err(InferenceError::JointUnavailable { reason: "the history has no events", @@ -2048,7 +2065,7 @@ impl, O: Observer, K: Eq + Hash + Clone> History, O: Observer, K: Eq + Hash + Clone> History { +impl, O: Observer, K: Eq + Hash + Clone> History { pub(crate) fn add_events_with_prior( &mut self, mut composition: Vec>>, @@ -2654,7 +2671,7 @@ impl, O: Observer, K: Eq + Hash + Clone> History, O: Observer, K: Eq + Hash + Clone> std::fmt::Debug - for History + for History { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("History") @@ -2712,8 +2729,14 @@ impl, O: Observer, K: Eq + Hash + Clone> std::fmt::Debug /// so a competitor seen in the first and last of a hundred slices contributes /// two variables, not a hundred. #[must_use] -pub struct Joint<'h, T: Time, D: Drift, O: Observer, K: Eq + Hash + Clone> { - history: &'h History, +pub struct Joint< + 'h, + K: Eq + Hash + Clone = &'static str, + T: Time = i64, + D: Drift = ConstantDrift, + O: Observer = NullObserver, +> { + history: &'h History, cholesky: crate::joint::Cholesky, /// `(row, slice)` of each competitor's latest appearance. latest: HashMap, @@ -2726,7 +2749,7 @@ pub struct Joint<'h, T: Time, D: Drift, O: Observer, K: Eq + Hash + Clone> /// Deliberately does not print the factorisation, which is `n^2` floats and /// would make a `{:?}` of a large joint unreadable and slow. impl, O: Observer, K: Eq + Hash + Clone> std::fmt::Debug - for Joint<'_, T, D, O, K> + for Joint<'_, K, T, D, O> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Joint") @@ -2735,7 +2758,7 @@ impl, O: Observer, K: Eq + Hash + Clone> std::fmt::Debug } } -impl, O: Observer, K: Eq + Hash + Clone> Joint<'_, T, D, O, K> { +impl, O: Observer> Joint<'_, K, T, D, O> { /// Number of variables in the joint: the history's appearances, after /// collapsing consecutive pairs a competitor does not drift between. /// @@ -2933,8 +2956,7 @@ mod tests { #[test] fn per_slice_footprint_is_independent_of_index_magnitude() { fn total_skill_slots(high_indices: bool) -> usize { - let mut h: History = - History::builder().key_type::().build(); + let mut h: History = History::builder().key_type::().build(); for i in 0..2_000 { h.intern(&format!("k{i:05}")); @@ -3240,7 +3262,7 @@ mod tests { #[test] fn test_teams() { - let mut h: History = History::builder() + let mut h: History = History::builder() .mu(0.0) .sigma(6.0) .beta(1.0) @@ -3346,7 +3368,7 @@ mod tests { #[test] fn test_add_events() { - let mut h: History = History::builder() + let mut h: History = History::builder() .mu(0.0) .sigma(2.0) .beta(1.0) @@ -3443,7 +3465,7 @@ mod tests { #[test] fn test_only_add_events() { - let mut h: History = History::builder() + let mut h: History = History::builder() .mu(0.0) .sigma(2.0) .beta(1.0) @@ -3542,7 +3564,7 @@ mod tests { fn test_log_evidence() { use crate::ConvergenceOptions; - let mut h: History = History::builder().build(); + let mut h: History = History::builder().build(); // empty results in the old API = team 0 wins; reproduce with Outcome::winner(0,2) let events = make_events_1v1( @@ -3598,7 +3620,7 @@ mod tests { epsilon = 1e-4 ); - let mut h2: History = History::builder().build(); + let mut h2: History = History::builder().build(); let events = make_events_1v1( &[("a", "b"), ("b", "a")], @@ -3616,7 +3638,7 @@ mod tests { #[test] fn test_add_events_with_time() { - let mut h: History = History::builder() + let mut h: History = History::builder() .mu(0.0) .sigma(2.0) .beta(1.0) @@ -3719,7 +3741,7 @@ mod tests { // second scenario: team-0 wins (empty results in old API), different composition order - let mut h2: History = History::builder() + let mut h2: History = History::builder() .mu(0.0) .sigma(2.0) .beta(1.0) @@ -3823,7 +3845,7 @@ mod tests { #[test] fn test_1vs1_weighted() { - let mut h: History = History::builder() + let mut h: History = History::builder() .mu(2.0) .sigma(6.0) .beta(1.0) @@ -3890,7 +3912,7 @@ mod tests { fn test_converge_returns_report() { use crate::ConvergenceOptions; - let mut h: History = History::builder() + let mut h: History = History::builder() .mu(0.0) .sigma(2.0) .beta(1.0) @@ -3930,19 +3952,18 @@ mod tests { fn history_propagates_convergence_to_inner_run_chain() { use crate::ConvergenceOptions; - let events_for = - |h: &mut History| { - h.event(0) - .team(["a"]) - .team(["b"]) - .team(["c"]) - .team(["d"]) - .ranking([0u32, 1, 2, 3]) - .commit() - .unwrap(); - }; + let events_for = |h: &mut History| { + h.event(0) + .team(["a"]) + .team(["b"]) + .team(["c"]) + .team(["d"]) + .ranking([0u32, 1, 2, 3]) + .commit() + .unwrap(); + }; - let mut h_capped: History = History::builder() + let mut h_capped: History = History::builder() .convergence(ConvergenceOptions { max_iter: 1, ..ConvergenceOptions::default() @@ -3953,7 +3974,7 @@ mod tests { // result rather than an error. let _ = h_capped.converge_partial().unwrap(); - let mut h_full: History = History::builder().build(); + let mut h_full: History = History::builder().build(); events_for(&mut h_full); let _ = h_full.converge().unwrap(); @@ -3978,23 +3999,22 @@ mod tests { fn history_with_damping_reaches_same_fixed_point_as_undamped() { use crate::ConvergenceOptions; - let events_for = - |h: &mut History| { - h.event(0) - .team(["a"]) - .team(["b"]) - .team(["c"]) - .team(["d"]) - .ranking([0u32, 1, 2, 3]) - .commit() - .unwrap(); - }; + let events_for = |h: &mut History| { + h.event(0) + .team(["a"]) + .team(["b"]) + .team(["c"]) + .team(["d"]) + .ranking([0u32, 1, 2, 3]) + .commit() + .unwrap(); + }; - let mut h_undamped: History = History::builder().build(); + let mut h_undamped: History = History::builder().build(); events_for(&mut h_undamped); let _ = h_undamped.converge().unwrap(); - let mut h_damped: History = History::builder() + let mut h_damped: History = History::builder() .convergence(ConvergenceOptions { alpha: 0.5, max_iter: 200, diff --git a/tests/additive_model.rs b/tests/additive_model.rs index c4f25bb..4784f5b 100644 --- a/tests/additive_model.rs +++ b/tests/additive_model.rs @@ -29,7 +29,7 @@ fn additive_structure_makes_sums_wide_and_differences_tight() { let players = ["p0", "p1", "p2"]; let holes = ["h0", "h1"]; - let mut h: History = History::builder() + let mut h: History = History::builder() .mu(0.0) .sigma(6.0) .beta(1.0) diff --git a/tests/convergence_strictness.rs b/tests/convergence_strictness.rs index 0910cf9..4953426 100644 --- a/tests/convergence_strictness.rs +++ b/tests/convergence_strictness.rs @@ -11,7 +11,7 @@ use trueskill_tt::{ ConstantDrift, ConvergenceOptions, Event, History, InferenceError, Member, Outcome, Team, }; -type H = History; +type H = History; fn duel(a: &'static str, b: &'static str, t: i64) -> Event { Event { @@ -108,7 +108,7 @@ fn the_two_agree_on_a_converged_fit() { /// At the old value of 30 this history stopped short and said nothing. #[test] fn the_default_cap_clears_an_ordinary_history() { - let mut h: History = History::builder() + let mut h: History = History::builder() .key_type::() .mu(0.0) .sigma(6.0) diff --git a/tests/cross_process_determinism.rs b/tests/cross_process_determinism.rs index c9f197a..70b5617 100644 --- a/tests/cross_process_determinism.rs +++ b/tests/cross_process_determinism.rs @@ -15,8 +15,7 @@ use std::{env, process::Command}; use smallvec::smallvec; use trueskill_tt::{ - ConstantDrift, ConvergenceOptions, Event, History, Member, NullObserver, Outcome, Team, - UnknownKeys, + ConstantDrift, ConvergenceOptions, Event, History, Member, Outcome, Team, UnknownKeys, }; /// Set in the child so it reports instead of re-spawning. @@ -24,7 +23,7 @@ const CHILD: &str = "TSTT_DETERMINISM_CHILD"; const RUNS: usize = 40; -type H = History; +type H = History; fn fitted() -> H { let mut h: H = History::builder() diff --git a/tests/degenerate_inputs.rs b/tests/degenerate_inputs.rs index 9adf95b..e2be13e 100644 --- a/tests/degenerate_inputs.rs +++ b/tests/degenerate_inputs.rs @@ -8,7 +8,7 @@ mod common; use common::assert_finite; use trueskill_tt::{ ConstantDrift, ConvergenceOptions, Game, GameOptions, Gaussian, History, InferenceError, - NullObserver, Outcome, Rating, + Outcome, Rating, }; type R = Rating; @@ -126,7 +126,7 @@ fn empty_history_converges_trivially() { /// indexed out of bounds in release, so this must run in both profiles. #[test] fn converge_on_an_empty_history_with_owned_keys() { - let mut history: History = History::builder() + let mut history: History = History::builder() .key_type::() .score_sigma(5.0) .build(); diff --git a/tests/drift_scale.rs b/tests/drift_scale.rs index 934fcb4..64aaf0e 100644 --- a/tests/drift_scale.rs +++ b/tests/drift_scale.rs @@ -8,11 +8,11 @@ use smallvec::smallvec; use trueskill_tt::{ - ConstantDrift, ConvergenceOptions, Event, Gaussian, History, InferenceError, Member, - NullObserver, Outcome, Team, + ConstantDrift, ConvergenceOptions, Event, Gaussian, History, InferenceError, Member, Outcome, + Team, }; -type Fit = History; +type Fit = History; const CONVERGENCE: ConvergenceOptions = ConvergenceOptions { max_iter: 64, diff --git a/tests/event_builder_members.rs b/tests/event_builder_members.rs index 5c3ad3b..0aceb47 100644 --- a/tests/event_builder_members.rs +++ b/tests/event_builder_members.rs @@ -11,7 +11,7 @@ use trueskill_tt::{ Team, }; -type H = History; +type H = History; fn history() -> H { History::builder() diff --git a/tests/evidence_matrix.rs b/tests/evidence_matrix.rs index 249c7df..c3f80ce 100644 --- a/tests/evidence_matrix.rs +++ b/tests/evidence_matrix.rs @@ -4,11 +4,9 @@ //! `filtered_log_evidence_for` was the missing corner: the one a per-competitor //! prequential score needs. -use trueskill_tt::{ - ConstantDrift, Event, History, InferenceError, Member, NullObserver, Outcome, Team, -}; +use trueskill_tt::{Event, History, InferenceError, Member, Outcome, Team}; -type H = History; +type H = History; /// Two disjoint cohorts, so a key restriction is guaranteed to leave events out. fn two_cohorts() -> H { diff --git a/tests/honest_accessors.rs b/tests/honest_accessors.rs index 22a9dc6..a6b147a 100644 --- a/tests/honest_accessors.rs +++ b/tests/honest_accessors.rs @@ -4,11 +4,9 @@ //! Each test carries a control: the same call on a key the history *does* know, //! so it cannot pass merely because everything returns the same thing. -use trueskill_tt::{ - ConstantDrift, Event, History, InferenceError, Member, NullObserver, Outcome, Team, -}; +use trueskill_tt::{Event, History, InferenceError, Member, Outcome, Team}; -type H = History; +type H = History; fn history() -> H { let mut h = H::default(); diff --git a/tests/ingestion_equivalence.rs b/tests/ingestion_equivalence.rs index 88c2ba3..4f8b202 100644 --- a/tests/ingestion_equivalence.rs +++ b/tests/ingestion_equivalence.rs @@ -47,7 +47,7 @@ fn configured_event(a: &str, b: &str, time: i64, scale: f64) -> Event>, batched: bool) -> Vec<(String, Gaussian)> { - let mut h: History = History::builder() + let mut h: History = History::builder() .key_type::() .convergence(tight()) .build(); diff --git a/tests/ingestion_shape.rs b/tests/ingestion_shape.rs index 5c2e43f..7d27ff9 100644 --- a/tests/ingestion_shape.rs +++ b/tests/ingestion_shape.rs @@ -14,8 +14,7 @@ use trueskill_tt::{Event, History, InferenceError, Member, Outcome, Team}; type Ev = Event; -fn history() -> History -{ +fn history() -> History { History::builder().score_sigma(1.0).build() } diff --git a/tests/joint_handle.rs b/tests/joint_handle.rs index bb63490..a913439 100644 --- a/tests/joint_handle.rs +++ b/tests/joint_handle.rs @@ -11,7 +11,7 @@ use trueskill_tt::{ UnknownKeys, }; -type H = History; +type H = History; fn duel(a: &'static str, b: &'static str, t: i64, sa: f64, sb: f64) -> Event { Event { @@ -288,7 +288,7 @@ fn unseen_competitors_match_a_fresh_factorisation() { #[test] fn a_drift_too_small_to_represent_collapses_rather_than_corrupting() { fn variance(scale: f64) -> f64 { - let mut h: History = History::builder() + let mut h: History = History::builder() .key_type::() .mu(0.0) .sigma(6.0) diff --git a/tests/key_ergonomics.rs b/tests/key_ergonomics.rs index 89d5352..1d9122d 100644 --- a/tests/key_ergonomics.rs +++ b/tests/key_ergonomics.rs @@ -8,10 +8,10 @@ //! Both key types are exercised in every test, because the point is that the //! spelling is the same. -use trueskill_tt::{ConstantDrift, History, NullObserver}; +use trueskill_tt::{ConstantDrift, History}; -type Owned = History; -type Borrowed = History; +type Owned = History; +type Borrowed = History; fn owned() -> Owned { let mut h: Owned = History::builder().key_type::().build(); diff --git a/tests/large_history_converges_finite.rs b/tests/large_history_converges_finite.rs index 48d4756..620aa5c 100644 --- a/tests/large_history_converges_finite.rs +++ b/tests/large_history_converges_finite.rs @@ -3,7 +3,7 @@ //! produced a tiny-negative precision whose `sigma() = 1/sqrt(pi)` was NaN, which the //! moment-space `Sub` in the game chain propagated into every skill once the slice grew past //! ~75 competitors (e.g. a real ranking dataset with hundreds of players). -use trueskill_tt::{ConstantDrift, ConvergenceOptions, EPSILON, History, ITERATIONS, NullObserver}; +use trueskill_tt::{ConstantDrift, ConvergenceOptions, EPSILON, History, ITERATIONS}; /// Tiny deterministic LCG — avoids a dev-dependency on `rand`. struct Lcg(u64); @@ -24,7 +24,7 @@ impl Lcg { } fn nan_after_fit(players: usize) -> usize { - let mut h: History = History::builder() + let mut h: History = History::builder() .key_type::() .beta(1.0) .sigma(6.0) diff --git a/tests/marginal_calibration.rs b/tests/marginal_calibration.rs index bded762..512a276 100644 --- a/tests/marginal_calibration.rs +++ b/tests/marginal_calibration.rs @@ -132,10 +132,8 @@ fn key(i: usize) -> &'static str { } /// Returns (worst mean error, worst sd ratio). -fn fitted( - obs: &[(usize, usize, f64)], -) -> History { - let mut h: History = History::builder() +fn fitted(obs: &[(usize, usize, f64)]) -> History { + let mut h: History = History::builder() .mu(MU0) .sigma(SIGMA0) .beta(BETA) @@ -324,7 +322,7 @@ fn cost_scaling() { use std::time::Instant; for n in [50usize, 100, 200, 400, 800] { let names: Vec = (0..n).map(|i| format!("c{i}")).collect(); - let mut h: History = History::builder() + let mut h: History = History::builder() .key_type::() .score_sigma(2.0) .drift(ConstantDrift::new(0.0)) diff --git a/tests/predict_margin.rs b/tests/predict_margin.rs index 4e5b047..88d0b0f 100644 --- a/tests/predict_margin.rs +++ b/tests/predict_margin.rs @@ -6,9 +6,7 @@ use trueskill_tt::{ UnknownKeys, }; -fn builder( - policy: UnknownKeys, -) -> History { +fn builder(policy: UnknownKeys) -> History { History::builder() .mu(0.0) .sigma(6.0) @@ -37,9 +35,7 @@ fn round(a: &'static str, b: &'static str, sa: f64, sb: f64) -> Event History { +fn fitted(policy: UnknownKeys) -> History { let mut h = builder(policy); let mut events: Vec<_> = (0..40) .map(|t| round("veteran", "regular", 10.0 + f64::from(t % 3), 5.0)) diff --git a/tests/prediction_guards.rs b/tests/prediction_guards.rs index 189cf60..4cc106c 100644 --- a/tests/prediction_guards.rs +++ b/tests/prediction_guards.rs @@ -10,10 +10,10 @@ //! returning `Err`. use trueskill_tt::{ - ConstantDrift, Event, Gaussian, History, InferenceError, Member, NullObserver, Outcome, Team, + ConstantDrift, Event, Gaussian, History, InferenceError, Member, Outcome, Team, }; -type H = History; +type H = History; fn build(beta: f64, prior: Option, outcome: Outcome) -> H { let mut h: H = History::builder() diff --git a/tests/reconvergence_equivalence.rs b/tests/reconvergence_equivalence.rs index aa28a6a..81b5446 100644 --- a/tests/reconvergence_equivalence.rs +++ b/tests/reconvergence_equivalence.rs @@ -35,7 +35,7 @@ fn ev(a: &str, b: &str, time: i64) -> Event { /// Ingest each chunk in turn, converging fully after every one. fn fit_in_chunks(chunks: Vec) -> Vec<(String, Gaussian)> { - let mut h: History = History::builder() + let mut h: History = History::builder() .key_type::() .convergence(tight()) .build(); @@ -152,7 +152,7 @@ fn re_converging_an_unchanged_history_costs_one_iteration() { let (early, late) = fixture(); let all: Vec<_> = early.into_iter().chain(late).collect(); - let mut h: History = History::builder() + let mut h: History = History::builder() .key_type::() .convergence(tight()) .build(); diff --git a/tests/registration.rs b/tests/registration.rs index 4c23fe5..f165622 100644 --- a/tests/registration.rs +++ b/tests/registration.rs @@ -11,7 +11,7 @@ use trueskill_tt::{ Team, }; -type H = History; +type H = History; const PINNED: Gaussian = Gaussian::from_ms(2.0, 0.5); diff --git a/tests/time_axis.rs b/tests/time_axis.rs index 894157c..08fdc38 100644 --- a/tests/time_axis.rs +++ b/tests/time_axis.rs @@ -144,7 +144,7 @@ fn key_type_replaces_builder_with_key() { /// Both axes at once, via the explicit constructor rather than the setters. #[test] fn new_constructs_on_any_axis_directly() { - let mut h = HistoryBuilder::::new().build(); + let mut h = HistoryBuilder::::new().build(); h.record_winner(&"a".to_string(), &"b".to_string(), Season(7)) .unwrap(); assert!(h.converge().unwrap().converged); diff --git a/tests/time_expanded_joint.rs b/tests/time_expanded_joint.rs index c54e6aa..fc1d413 100644 --- a/tests/time_expanded_joint.rs +++ b/tests/time_expanded_joint.rs @@ -16,7 +16,7 @@ const BETA: f64 = 1.0; const SCORE_SIGMA: f64 = 2.0; const GAMMA: f64 = 0.5; -type H = History; +type H = History; fn history(gamma: f64) -> H { History::builder() diff --git a/tests/trait_impls.rs b/tests/trait_impls.rs index 438ba75..36f71b6 100644 --- a/tests/trait_impls.rs +++ b/tests/trait_impls.rs @@ -42,7 +42,7 @@ fn a_struct_holding_a_history_can_derive_debug() { #[test] fn history_builder_is_debug_and_clone() { - let b: HistoryBuilder = History::builder(); + let b: HistoryBuilder = History::builder(); let cloned = b.clone(); assert!(!format!("{cloned:?}").is_empty()); } diff --git a/tests/variance_reduction.rs b/tests/variance_reduction.rs index dd97897..b76e744 100644 --- a/tests/variance_reduction.rs +++ b/tests/variance_reduction.rs @@ -6,7 +6,7 @@ use trueskill_tt::{ UnknownKeys, }; -type H = History; +type H = History; fn round(a: &'static str, b: &'static str, sa: f64, sb: f64) -> Event { Event { @@ -30,7 +30,7 @@ fn base() -> Vec> { } fn fit(extra: Option>, policy: UnknownKeys) -> H { - let mut h: History = History::builder() + let mut h: History = History::builder() .mu(0.0) .sigma(6.0) .beta(1.0)