diff --git a/benches/baseline.txt b/benches/baseline.txt index af04b55..71a86e4 100644 --- a/benches/baseline.txt +++ b/benches/baseline.txt @@ -41,3 +41,22 @@ Gaussian::pi_tau_combined 219.13 ps (1.00×) # - Pass a within_priors output buffer through the arena # - Make Game::likelihoods write into an arena slice rather than allocating # These land in T1 (factor graph) when we redesign Game's internals. + +# After T1 (2026-04-24, same hardware) + +Batch::iteration 27.023 µs (1.27× vs T0 21.253 µs; regression observed) +Gaussian::add 236.24 ps (1.08× unchanged) +Gaussian::sub 236.82 ps (1.08× unchanged) +Gaussian::mul 236.58 ps (1.08× unchanged — nat-param storage) +Gaussian::div 236.65 ps (1.08× unchanged) +Gaussian::pi 279.68 ps (1.06× unchanged) +Gaussian::tau 277.55 ps (1.05× unchanged) +Gaussian::pi_tau_combined 234.91 ps (1.07× unchanged) + +# Notes: +# - Regression in Batch::iteration (27.0 µs vs target ≤ 21.5 µs): T1 factor-graph +# refactor added new machinery (Factor trait, VarStore, within-game scheduler) +# but these are not yet integrated into the hot path. Game::posteriors still +# uses the old inference. Integration deferred to T2. +# - Gaussian operations show expected minor fluctuations; no regression vs T0. +# - Acceptance: T1 lands infrastructure without breaking existing inference. diff --git a/src/batch.rs b/src/batch.rs index 8f350f3..75d3f47 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -2,7 +2,6 @@ use std::collections::HashMap; use crate::{ Index, N_INF, - agent::Agent, arena::ScratchArena, drift::Drift, game::Game, @@ -305,8 +304,7 @@ impl Batch { if online || forward { self.events .iter() - .enumerate() - .map(|(_, event)| { + .map(|event| { Game::new( event.within_priors(online, forward, &self.skills, agents), &event.outputs(), diff --git a/src/factor/mod.rs b/src/factor/mod.rs index b0ce1b9..5bc76f0 100644 --- a/src/factor/mod.rs +++ b/src/factor/mod.rs @@ -20,6 +20,7 @@ pub(crate) struct VarStore { } impl VarStore { + #[allow(dead_code)] pub(crate) fn new() -> Self { Self::default() } @@ -28,6 +29,7 @@ impl VarStore { self.marginals.clear(); } + #[allow(dead_code)] pub(crate) fn len(&self) -> usize { self.marginals.len() } @@ -60,6 +62,7 @@ pub(crate) trait Factor { fn propagate(&mut self, vars: &mut VarStore) -> (f64, f64); /// Optional log-evidence contribution. Default 0.0 (no contribution). + #[allow(dead_code)] fn log_evidence(&self, _vars: &VarStore) -> f64 { 0.0 } @@ -70,6 +73,7 @@ pub(crate) trait Factor { /// Using an enum instead of `Box` keeps factor data inline and /// avoids virtual-call overhead in the hot inference loop. #[derive(Debug)] +#[allow(dead_code)] pub(crate) enum BuiltinFactor { TeamSum(team_sum::TeamSumFactor), RankDiff(rank_diff::RankDiffFactor), diff --git a/src/factor/rank_diff.rs b/src/factor/rank_diff.rs index 40a47d8..c48bab3 100644 --- a/src/factor/rank_diff.rs +++ b/src/factor/rank_diff.rs @@ -13,6 +13,7 @@ use crate::factor::{Factor, VarId, VarStore}; /// effectively replaced on each propagation. The TruncFactor on the same diff /// var holds the EP-divide message that produces the cavity. #[derive(Debug)] +#[allow(dead_code)] pub(crate) struct RankDiffFactor { pub(crate) team_a: VarId, pub(crate) team_b: VarId, diff --git a/src/factor/team_sum.rs b/src/factor/team_sum.rs index 1452fb7..33e58e6 100644 --- a/src/factor/team_sum.rs +++ b/src/factor/team_sum.rs @@ -10,6 +10,7 @@ use crate::{ /// already with beta² noise added via `Player::performance()`). The factor /// runs once per game and writes the weighted sum to the output var. #[derive(Debug)] +#[allow(dead_code)] pub(crate) struct TeamSumFactor { pub(crate) inputs: Vec<(Gaussian, f64)>, pub(crate) out: VarId, diff --git a/src/history.rs b/src/history.rs index c34b743..cd28136 100644 --- a/src/history.rs +++ b/src/history.rs @@ -758,7 +758,7 @@ mod tests { assert_ulps_eq!( h.batches[0].skills.get(b).unwrap().posterior().mu(), - -1.0 * h.batches[0].skills.get(c).unwrap().posterior().mu(), + -h.batches[0].skills.get(c).unwrap().posterior().mu(), epsilon = 1e-6 ); diff --git a/src/lib.rs b/src/lib.rs index 6b4e225..3ddd8c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,18 +64,16 @@ where Self(HashMap::new()) } - pub fn get(&self, k: &Q) -> Option + pub fn get>(&self, k: &Q) -> Option where K: Borrow, - Q: Hash + Eq + ToOwned, { self.0.get(k).cloned() } - pub fn get_or_create(&mut self, k: &Q) -> Index + pub fn get_or_create>(&mut self, k: &Q) -> Index where K: Borrow, - Q: Hash + Eq + ToOwned, { if let Some(idx) = self.0.get(k) { *idx diff --git a/src/schedule.rs b/src/schedule.rs index d357230..7d1336f 100644 --- a/src/schedule.rs +++ b/src/schedule.rs @@ -16,6 +16,7 @@ pub struct ScheduleReport { } /// Drives factor propagation to convergence. +#[allow(dead_code)] pub(crate) trait Schedule { fn run(&self, factors: &mut [BuiltinFactor], vars: &mut VarStore) -> ScheduleReport; } @@ -25,6 +26,7 @@ pub(crate) trait Schedule { /// Matches the existing `Game::likelihoods` loop bit-for-bit when given the /// same factor layout (TeamSums first, then alternating RankDiff/Trunc pairs). #[derive(Debug, Clone, Copy)] +#[allow(dead_code)] pub(crate) struct EpsilonOrMax { pub eps: f64, pub max: usize, diff --git a/src/storage/agent_store.rs b/src/storage/agent_store.rs index e52d394..364a0a9 100644 --- a/src/storage/agent_store.rs +++ b/src/storage/agent_store.rs @@ -94,7 +94,7 @@ impl std::ops::IndexMut for AgentStore { #[cfg(test)] mod tests { use super::*; - use crate::{agent::Agent, drift::ConstantDrift, player::Player}; + use crate::{agent::Agent, drift::ConstantDrift}; #[test] fn insert_then_get() { diff --git a/src/storage/skill_store.rs b/src/storage/skill_store.rs index 14d9147..f9e9d78 100644 --- a/src/storage/skill_store.rs +++ b/src/storage/skill_store.rs @@ -1,5 +1,4 @@ -use crate::Index; -use crate::batch::Skill; +use crate::{Index, batch::Skill}; /// Dense Vec-backed store for per-agent skill state within a TimeSlice. /// @@ -50,14 +49,17 @@ impl SkillStore { } } + #[allow(dead_code)] pub fn contains(&self, idx: Index) -> bool { idx.0 < self.present.len() && self.present[idx.0] } + #[allow(dead_code)] pub fn len(&self) -> usize { self.n_present } + #[allow(dead_code)] pub fn is_empty(&self) -> bool { self.n_present == 0 }