refactor!: remove the factor-graph surface nothing used, add try_winner
Two decisions taken before cutting 0.5.0. #42 — the `Schedule` trait was public API the engine never called. Its only call site was `Game::custom`, itself `#[doc(hidden)]`, and `EpsilonOrMax` was never constructed anywhere. Removing that surface showed the problem was larger than the issue described: with `custom` gone, the compiler found `Factor`, `BuiltinFactor`, `RankDiffFactor` and `TeamSumFactor` all dead too. `Game::run_chain` drives a local `DiffFactor` enum and bypasses the whole T1 abstraction — it has done since it was written. So this is not just an unused extension point but the machinery it was built on, and `CLAUDE.md` was documenting it as live architecture. Removed: `graph` module, `Schedule`, `EpsilonOrMax`, `ScheduleReport`, `Game::custom`, `Factor`, `BuiltinFactor`, `RankDiffFactor`, `TeamSumFactor`. `TruncFactor`, `MarginFactor`, `VarStore` and `VarId` stay — inference uses those. The measurement behind choosing removal over wiring is in #42: the within-game loop converges in 1 to 8 iterations against a cap of 30, so a `Residual` schedule has no headroom to reclaim, and `Damped` already shipped as `ConvergenceOptions::alpha`. #20 — `Outcome::winner` panicking on an out-of-range index. Kept, and the reasoning is now on the method. It is the only constructor here that validates, which looks inconsistent until you try deferring like its siblings: `winner(5, 2)` produces ranks `[1, 1]`, an all-tied draw that ingestion accepts without complaint when `p_draw > 0`. Asking "team 5 won" and silently getting "everyone drew" is the exact failure this crate keeps removing, so the check belongs where the mistake is. Adds `Outcome::try_winner` for indices that are computed or parsed rather than written literally, following the `new`/`try_new` convention. That is additive; the panicking form stays because every call site in this repo, its tests and its README passes literals, where a `?` would be noise. BREAKING CHANGE: the `graph` module and everything it exported are removed, as are `Game::custom` and `ScheduleReport`. Closes #42. Closes #20. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011hcFjNDmHXZF8URGLku5zZ
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
N_INF,
|
||||
factor::{Factor, VarId, VarStore},
|
||||
factor::{VarId, VarStore},
|
||||
gaussian::Gaussian,
|
||||
ln_pdf,
|
||||
};
|
||||
@@ -55,12 +55,16 @@ impl MarginFactor {
|
||||
}
|
||||
}
|
||||
|
||||
impl Factor for MarginFactor {
|
||||
fn propagate(&mut self, vars: &mut VarStore) -> (f64, f64) {
|
||||
/// Undamped wrappers, used by this module's tests. Inference drives these
|
||||
/// factors through `propagate_with_alpha` and reads the cached log evidence
|
||||
/// directly, so these are not on any production path.
|
||||
#[cfg(test)]
|
||||
impl MarginFactor {
|
||||
pub(crate) fn propagate(&mut self, vars: &mut VarStore) -> (f64, f64) {
|
||||
self.propagate_with_alpha(vars, 1.0)
|
||||
}
|
||||
|
||||
fn log_evidence(&self, _vars: &VarStore) -> f64 {
|
||||
pub(crate) fn log_evidence(&self) -> f64 {
|
||||
self.log_evidence_cached.unwrap_or(0.0)
|
||||
}
|
||||
}
|
||||
@@ -146,7 +150,7 @@ mod tests {
|
||||
let diff = vars.alloc(Gaussian::from_ms(0.0, 6.0));
|
||||
let mut f = MarginFactor::new(diff, 5.0, 1.0);
|
||||
f.propagate(&mut vars);
|
||||
let logz = f.log_evidence(&vars);
|
||||
let logz = f.log_evidence();
|
||||
assert!((logz - (-3.062235327364623)).abs() < 1e-10);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user