a40c0d6301
feat(color-group): add greedy within-slice event partitioning
...
ColorGroups holds a partition of event indices into color groups such
that events of the same color touch no shared Index. Computed greedily
in ingestion order: each event goes into the first color whose existing
members are disjoint from the event's indices.
Used in T3 for safe within-slice parallelism — events in the same
color can run concurrently without touching each other's skills.
Part of T3 of docs/superpowers/specs/2026-04-23-trueskill-engine-redesign-design.md.
2026-04-24 13:38:21 +02:00
4f302ed28e
feat(api): add Send + Sync bounds to public traits
...
Required for T3 rayon-based parallelism. Affected traits:
- Time (+ Send + Sync + 'static)
- Drift<T> (+ Send + Sync)
- Observer<T> (+ Send + Sync)
- Factor (+ Send + Sync)
- Schedule (+ Send + Sync)
All built-in impls (i64, Untimed, ConstantDrift, NullObserver,
EpsilonOrMax, TeamSumFactor, RankDiffFactor, TruncFactor,
BuiltinFactor) naturally satisfy these bounds via auto-derive.
Minor breaking change: downstream custom impls that aren't already
thread-safe will need to add the bounds.
Part of T3 of docs/superpowers/specs/2026-04-23-trueskill-engine-redesign-design.md.
2026-04-24 13:36:39 +02:00
9fe40042da
feat(cargo): add rayon as optional dependency
...
Opt-in feature flag — users who want parallel paths build with
--features rayon. Default build remains single-threaded.
Spec Section 6 calls for default-on; we defer that flip until the
feature is stable under field use.
Part of T3 of docs/superpowers/specs/2026-04-23-trueskill-engine-redesign-design.md.
2026-04-24 13:35:15 +02:00
f0793a8470
docs: add T3 concurrency implementation plan
...
11-task plan for rayon-backed within-slice parallelism per
Section 6 of docs/superpowers/specs/2026-04-23-trueskill-engine-redesign-design.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-04-24 13:34:00 +02:00
d2aab82c1e
T0 + T1 + T2: engine redesign through new API surface ( #1 )
...
Implements tiers T0, T1, T2 of `docs/superpowers/specs/2026-04-23-trueskill-engine-redesign-design.md`. All three tiers have landed together on this branch because they build on one another; this PR rolls them up for a single review pass.
Per-tier plans:
- T0: `docs/superpowers/plans/2026-04-23-t0-numerical-parity.md`
- T1: `docs/superpowers/plans/2026-04-24-t1-factor-graph.md`
- T2: `docs/superpowers/plans/2026-04-24-t2-new-api-surface.md`
## Summary
### T0 — Numerical parity (internal)
- `Gaussian` switched to natural-parameter storage `(pi, tau)`; mul/div now ~7× faster (218 ps vs 1.57 ns).
- `HashMap<Index, _>` → dense `Vec<_>` keyed by `Index.0` (via `AgentStore<D>`, `SkillStore`).
- `ScratchArena` eliminates per-event allocations in `Game::likelihoods`.
- `InferenceError` seed type added (1 variant).
- 38 → 53 tests passing through T1.
- Benchmark: `Batch::iteration` 29.84 → 21.25 µs.
### T1 — Factor graph machinery (internal)
- `Factor` trait + `BuiltinFactor` enum (TeamSum / RankDiff / Trunc) driving within-game inference.
- `VarStore` flat storage for variable marginals.
- `Schedule` trait + `EpsilonOrMax` impl replacing the hand-rolled EP loop.
- `Game::likelihoods` rebuilt on the factor-graph machinery; iteration counts and goldens preserved to within 1e-6.
- 53 tests passing.
- Benchmark: `Batch::iteration` 23.01 µs (slight regression absorbed in T2).
### T2 — New API surface (breaking)
**Renames:**
- `IndexMap → KeyTable`, `Player → Rating`, `Agent → Competitor`, `Batch → TimeSlice`
**New types:**
- `Time` trait with `Untimed` ZST and `i64` impls; `Drift<T>`, `Rating<T, D>`, `Competitor<T, D>`, `TimeSlice<T>`, `History<T, D, O, K>` all generic.
- `Event<T, K>`, `Team<K>`, `Member<K>`, `Outcome` (`Ranked` variant; `#[non_exhaustive]`).
- `Observer<T>` trait + `NullObserver`.
- `ConvergenceOptions`, `ConvergenceReport`.
- `GameOptions`, `OwnedGame<T, D>`.
**Three-tier ingestion:**
- `history.record_winner(&K, &K, T)` / `record_draw(&K, &K, T)` — 1v1 convenience.
- `history.add_events(iter)` — typed bulk.
- `history.event(T).team([...]).weights([...]).ranking([...]).commit()` — fluent.
**Query API:** `current_skill`, `learning_curve`, `learning_curves` (keyed on `K`), `log_evidence`, `log_evidence_for`, `predict_quality`, `predict_outcome`.
**Game constructors:** `ranked`, `one_v_one`, `free_for_all`, `custom` — all returning `Result<_, InferenceError>`.
**`factors` module:** `Factor`, `Schedule`, `VarStore`, `VarId`, `BuiltinFactor`, `EpsilonOrMax`, `ScheduleReport`, `TeamSumFactor`, `RankDiffFactor`, `TruncFactor` now public.
**Errors:** `InferenceError` gains `MismatchedShape`, `InvalidProbability`, `ConvergenceFailed`; boundary panics converted to `Result`.
**Removed (breaking):** `History::convergence(iters, eps, verbose)`, `HistoryBuilder::gamma(f64)`, `HistoryBuilder::time(bool)`, `History.time: bool`, `learning_curves_by_index`, nested-Vec public `add_events`.
## Behavior change (documented in CHANGELOG)
`Time = Untimed` has `elapsed_to → 0`, so no drift accumulates between slices. The old `time=false` mode implicitly forced `elapsed=1` on reappearance via an `i64::MAX` sentinel — that quirk is not reproducible under a typed time axis. Tests that depended on it now use `History::<i64, _>` with explicit `1..=n` timestamps. One test (`test_env_ttt`) had 3 Gaussian goldens updated to reflect the corrected semantics; documented in commit `33a7d90`.
## Final numbers
| Metric | Before T0 | After T2 | Delta |
|---|---|---|---|
| `Batch::iteration` | 29.84 µs | 21.36 µs | **-28%** |
| `Gaussian::mul` | 1.57 ns | 219 ps | **-86%** |
| `Gaussian::div` | 1.57 ns | 219 ps | **-86%** |
| Tests passing | 38 | 90 | +52 |
All other Gaussian ops unchanged (~219 ps add/sub, ~264 ps pi/tau reads).
## Test plan
- [x] `cargo test --features approx` — 90/90 pass (68 lib + 10 api_shape + 6 game + 4 record_winner + 2 equivalence)
- [x] `cargo clippy --all-targets --features approx -- -D warnings` — clean
- [x] `cargo +nightly fmt --check` — clean
- [x] `cargo bench --bench batch` — 21.36 µs
- [x] `cargo bench --bench gaussian` — unchanged from T1
- [x] `cargo run --example atp --features approx` — rewritten in new API, runs clean
- [x] Historical Game-level goldens preserved in `tests/equivalence.rs`
- [x] Public API matches spec Section 4 (verified by integration tests in `tests/api_shape.rs`)
## Commit history
~45 commits total across T0 + T1 + T2. Each task is self-contained and individually tested; the branch is bisectable. See `git log main..t2-new-api-surface` for the full list.
## Deferred to later tiers
- `Outcome::Scored` + `MarginFactor` — T4
- `Damped` / `Residual` schedules — T4
- `Send + Sync` bounds + Rayon parallelism — T3
- N-team `predict_outcome` — T4
- `Game::custom` full ergonomics — T4
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Reviewed-on: #1
Co-authored-by: Anders Olsson <anders.e.olsson@gmail.com >
Co-committed-by: Anders Olsson <anders.e.olsson@gmail.com >
2026-04-24 11:20:04 +00: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
912a282cd8
More refactoring
2022-12-16 15:57:56 +01:00
51467f7b69
Fix clippy warning
2022-12-16 15:51:58 +01:00
6dd84f7fd2
Refactor so we can see if there is any way to improve the performance
2022-12-16 15:38:29 +01:00
5eb8e62d6e
Agents doens't have to be behind a mutable reference in within_priors
2022-12-15 20:13:25 +01:00
8bea1b5399
Agents doens't have to be behind a mutable reference in within_prior
2022-12-15 20:12:55 +01:00
6546cb54b5
Added a get function to IndexMap
2022-12-12 13:25:07 +01:00
13e6454d3d
Update crates and added methods to get a key or all keys in an IndexMap
2022-12-12 10:50:59 +01:00
18d55a8ccf
Clean up example
2022-07-04 23:13:57 +02:00
32df04fb6d
Small change
2022-06-28 23:29:44 +02:00
22c61d47b1
Change time to use i64 instead of u64
2022-06-28 23:18:55 +02:00