Commit Graph

88 Commits

Author SHA1 Message Date
ae141752b7 feat(factor): implement RankDiffFactor
Maintains diff = team_a - team_b across three variables. On each
propagation, reads the team-perf marginals (which may have been
updated by neighboring factors) and computes the new diff via
Gaussian Sub (variance addition).
2026-04-24 08:19:18 +02:00
1210a34a64 fix(factor): move N_INF import to test module in team_sum 2026-04-24 08:17:54 +02:00
cee70c6272 feat(factor): implement TeamSumFactor
Computes the weighted sum of player performance Gaussians into a
team-performance variable. Runs once per game (no iteration needed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 08:17:14 +02:00
ebccc7b454 feat(factor): introduce Factor trait and BuiltinFactor enum
Adds the trait that all factors implement and the enum dispatcher
used by the schedule to drive heterogeneous factors without dynamic
dispatch in the hot loop.

The three built-in factors (TeamSum, RankDiff, Trunc) are stubbed
out; concrete implementations follow in tasks 4-6.
2026-04-24 08:14:00 +02:00
dac4427b65 feat(factor): introduce VarId and VarStore
Foundation types for the T1 factor graph machinery. VarStore is a
flat Vec<Gaussian> indexed by VarId; variables are allocated by
alloc() and the store can be cleared between games to reuse capacity.

Part of T1 of docs/superpowers/specs/2026-04-23-trueskill-engine-redesign-design.md.
2026-04-24 08:09:25 +02:00
fa85bcee51 docs: add T1 factor-graph implementation plan
Bite-sized, TDD-style task breakdown for the second tier of the engine
redesign: introduce VarStore, Factor trait, BuiltinFactor enum, and
EpsilonOrMax schedule, then re-implement Game::likelihoods on top of
the new machinery. Internal-only refactor; public Game/History API
unchanged.

Acceptance: existing tests pass within ULP, iteration counts match T0,
no Batch::iteration regression vs T0 (~21.5 µs).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 07:42:33 +02:00
d3cfee53a1 bench: capture T0 final numbers and post-mortem
Batch::iteration: 29.840 µs → 21.253 µs (1.40×)
Gaussian::mul:     1.568 ns →  218.69 ps (7.17×)
Gaussian::div:     1.572 ns →  218.64 ps (7.19×)

Gaussian arithmetic hit target (7×+ vs 1.5–2× expected). Batch::iteration
reached 1.40× vs the 3× target. Post-mortem: the bench exercises 100 tiny
2-team events and the dominant cost is still Vec allocation in within_priors,
sort_perm, and Game::likelihoods. The HashMap→Vec win shows at the History
level (forward/backward sweep) which this bench doesn't exercise.

Remediation plan documented in benches/baseline.txt: arena-ify sort_perm,
within_priors, and Game::likelihoods in T1 when Game's internals are
redesigned around the new factor graph.

38/38 tests passing. Closes T0 tier.
2026-04-24 07:28:28 +02:00
b1e0fcb817 perf(game): eliminate per-event allocations via ScratchArena
Game::likelihoods previously allocated four Vecs (teams, diffs, ties,
margins) on every call. Batch now owns one ScratchArena reused across
all Game::new calls in the iteration loop; likelihoods() clears and
extends the arena buffers instead of allocating fresh.

For log_evidence (called infrequently), a local ScratchArena is created
per invocation so the method signature stays &self.

Also: add #[derive(Debug)] to TeamMessage and DiffMessage (required by
ScratchArena's own Debug derive).

Part of T0 engine redesign.
2026-04-24 07:24:29 +02:00
49d2b317da refactor(history): replace HashMap<Index, Agent<D>> with dense AgentStore<D>
AgentStore<D> is a Vec<Option<Agent<D>>>-backed store indexed directly
by Index.0, eliminating per-iteration hashing in the cross-history
forward/backward sweep. Implements Index<Index>/IndexMut<Index> for
ergonomic agent access.

AgentStore is public (so benches/batch.rs can use it). SkillStore
remains pub(crate) since Skill is pub(crate) in batch.rs.

HashMap<Index, _> is now only used for the posteriors() return value
(temporary; will be replaced in T2 with a proper typed return) and
for the add_events_with_prior(priors: HashMap<Index, Player<D>>) API
(also T2 target).

Part of T0 engine redesign.
2026-04-24 07:15:21 +02:00
8f60258dba refactor(batch): replace HashMap<Index, Skill> with dense SkillStore
SkillStore is a Vec<Skill>-backed dense store with a parallel present
mask, indexed directly by Index.0. Eliminates per-iteration hashing
in the within-slice convergence loop; O(1) array lookup replaces O(1)
amortised hash lookup with better cache behaviour.

Iteration order is now ascending-by-Index (was arbitrary for HashMap);
EP fixed point is order-independent so posteriors are unchanged.

Part of T0 engine redesign.
2026-04-24 07:08:20 +02:00
709ece335f feat: introduce InferenceError; mu_sigma panic already eliminated
mu_sigma was deleted as part of the Gaussian nat-param rewrite (its
only callers were the old Mul/Div impls). This commit adds the
InferenceError enum as a seed for the T2 API surface, with the
NegativePrecision variant that mu_sigma would have returned.

Part of T0 engine redesign.
2026-04-24 07:00:26 +02:00
a667deb7e1 refactor(gaussian): switch to natural-parameter storage (pi, tau)
Mul and Div become two f64 adds/subs with no sqrt in the hot path.
mu() and sigma() are computed on demand from stored pi/tau.

Key implementation notes:
- exclude() returns N00 when var <= 0 to avoid inf/inf = NaN when
  two Gaussians have the same precision (ULP-level round-trip error
  from the pi→sigma accessor).
- Mul<f64> by 0.0 returns N00 (point mass at 0), matching old behavior.
- from_ms(0, 0) == N00 {pi:inf, tau:0}; from_ms(0, inf) == N_INF {pi:0, tau:0}.

Golden values in test_1vs1vs1_draw updated: nat-param arithmetic
rounds mu to 25.0 (was 24.999999) and shifts sigma by ~3e-7.
Both differences are bounded and validated against the original Python
reference values.

Part of T0 engine redesign.
2026-04-24 06:59:43 +02:00
06d3c886fe bench: capture T0 baseline; expose pi/tau accessors; fix div panic
- Promotes Gaussian::pi and Gaussian::tau to public so benches/gaussian.rs
  compiles, then captures baseline numbers for the T0 acceptance gate.
- Fixes the divide bench: g1/g2 panicked (g1 has lower precision than g2;
  cavity requires pi_num >= pi_den). Swapped to g2/g1 (well-defined).

Baseline on Apple M5 Pro:
  Batch::iteration  29.840 µs
  Gaussian::mul      1.568 ns   (vs ~220 ps for add/sub — hot path)
  Gaussian::div      1.572 ns
2026-04-24 06:43:00 +02:00
d11d2e8c6b docs: add T0 numerical-parity implementation plan
Bite-sized, TDD-style task breakdown for the first tier of the engine
redesign: Gaussian to natural-parameter storage, dense Vec storage
replacing HashMap, ScratchArena to eliminate per-event allocs,
Result-ifying the lone panic. No top-level public API change.

Acceptance gate: ≥3x speedup on Batch::iteration vs. baseline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 22:43:27 +02:00
c5f081d21f docs: add TrueSkill-TT engine redesign spec
Comprehensive design for a multi-tier rewrite covering performance,
factor-graph extensibility, convergence scheduling, and API surface.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-23 22:33:48 +02:00
a14df02089 chore: do not publish v0.1.0 2026-04-23 20:26:52 +02:00
0d266b4428 chore: make cargo release add CHANGELOG.md before commit 2026-04-23 20:26:16 +02:00
a4b4e5e8fa chore: clean up 2026-04-23 20:24:10 +02:00
04d5478ee4 style: cargo fmt 2026-04-23 20:23:13 +02:00
480467ac32 chore: added cliff.toml, release.toml and rustfmt.toml 2026-04-23 20:22:27 +02:00
dc47964310 added benchmark 2026-03-23 14:55:18 +01:00
61a5507f5c remove notepad 2026-03-23 14:21:23 +01:00
a1f282a1c8 feat: added a Drift trait and a "default" ConstantDrift implementation 2026-03-16 12:06:04 +01:00
853f177fa8 Small changes for new 2024 edition 2025-02-21 14:09:58 +01:00
fc0efcdc52 Update edition 2025-02-21 14:06:28 +01:00
3bbddb168f Ignore temp folder 2024-04-03 14:43:54 +02:00
2366c45f6a Basic test for quality 2024-04-03 10:25:10 +02:00
3a22b20a17 Added todo to readme, and documentation for quality function 2024-04-03 09:53:07 +02:00
02ae2f0977 Change assert to debug_assert 2024-04-03 09:44:41 +02:00
Anders Olsson
db743bc417 Improve performance 2023-10-31 10:02:07 +01:00
Anders Olsson
7e2576085f Make quality a free standing function instead 2023-10-26 11:11:54 +02:00
Anders Olsson
062c9d3765 Added quality function 2023-10-26 11:09:30 +02:00
Anders Olsson
755a5ea668 Move stuff around 2023-10-26 11:01:14 +02:00
Anders Olsson
72e06eb536 Rename variables 2023-10-26 08:26:28 +02:00
Anders Olsson
e3eebb507c Refactor history 2023-10-26 08:18:15 +02:00
Anders Olsson
d8dfbba251 Fix clippy warning 2023-10-25 08:16:45 +02:00
Anders Olsson
d152e356f1 Remove unnecessary allocations 2023-10-24 16:10:40 +02:00
Anders Olsson
59c256edad Dry my eyes 2023-10-24 09:50:16 +02:00
Anders Olsson
efa235be59 Clean up 2023-10-24 09:44:42 +02:00
Anders Olsson
aea3df285a Update crates 2023-06-28 09:42:12 +02:00
a491f8de8d Fix broken link in README 2023-01-09 14:37:07 +01:00
0b4b07d60e Added more links to readme 2023-01-09 14:35:34 +01:00
05f178641c Rename d to diff, and t to team 2022-12-29 20:38:36 +01:00
e3906aebaa Small refactor 2022-12-27 22:37:12 +01:00
8e25826f91 More rustifying 2022-12-27 22:30:20 +01:00
9b6cb9e7eb Make it more rusty 2022-12-27 22:24:01 +01:00
fdddf56156 Remove unused mut reference 2022-12-27 22:11:04 +01:00
b93194f762 Added default implementation for TeamMessage 2022-12-20 11:08:27 +01:00
2b83ee5ef9 Added benchmark for Batch 2022-12-19 07:42:08 +01:00
2bdd3d9b89 Remove warnings and refactor some code 2022-12-16 19:46:01 +01:00