Repository navigation
Home
regret is a general-purpose, game-agnostic Rust implementation of the
Counterfactual Regret Minimization (CFR / MCCFR) family for imperfect-information
extensive-form games. The solver knows nothing about poker, dice, or cards: you
bring a game that implements the Game trait and the trainer learns a Profile
(a strategy).
New to the crate? Start with Getting Started for a minimal compiling example, then come back here for orientation.
Guides (the learning path, in order):
- Getting started: a minimal compiling example, end to end.
-
Implementing a game: the
Gametrait, the correctness contract, chance semantics, and validation. -
Training a strategy:
Trainer, the algorithms, regret variants, pruning, parallelism semantics, and curriculum blending. - Evaluating agents: self-play, head-to-head, and match play.
Reference:
-
Profiles:
Profile, the versioned checkpoint format, provenance, shape tags, and thePolicytrait. - Analytics: exact exploitability, best response, and NashConv, plus the sampled estimator for large games and its limits.
- Subgames: safe subgame solving, blueprints, depth-limited and compositional re-solving.
- Abstraction: action abstraction.
-
Interior-perturbed strategies: the
rtcfrmodule for near-Nash strategies that keep every action strictly positive. -
Deep CFR: the optional
deepfeature (Deep CFR, ESCHER, DREAM, and more). - Reference games: the example games used by the tests.
Trainer::new(game) defaults to external-sampling MCCFR with Discounted CFR+ (DCFR+), a general-purpose configuration that works well across game sizes. The
single-call Profile::train(game, iters) covers the common case;
Getting Started walks through it end to end.
The DCFR+ default is not the right blueprint variant for safe subgame solving, where strict idempotency needs a CFR-family variant. See Subgames.
-
regret(root crate): the solver, withGame(src/game.rs),Trainer(src/trainer/mod.rs), andProfile(src/profile/mod.rs).src/lib.rsre-exports the prelude. -
regret-games(workspace member,publish = false): reference games (Kuhn, RPS, Goofspiel, Liar's Dice, Leduc, and others). It is a dev-dependency, socargo testcompiles every reference game and the first build is slow. -
regret-pyis excluded from the workspace (it pulls in pyo3 / Python). Do not expect it to build under plaincargo, and do not runcargofrom inside it without a Python toolchain.
-
parallel(default): rayon multi-worker ensemble training in the tabularTrainer. -
deep: neural-net / sampled Deep CFR (src/deep/,tests/deep.rs), not in default.cargo test --features deepcompiles and runs it. -
f32-tables: store accumulators asf32(memory-bound games); the math staysf64.
Edition 2024, MSRV 1.85.
-
exploitability_2p_zerosumis a Nash proof (goes to 0) for 2-player zero-sum games only. - For N > 2 or non-zero-sum games,
best_responses/exploitability_*are a quality signal and do not prove Nash. Averaging independent parallel runs is only exact for 2p zero-sum; for N > 2 treat it as variance reduction. -
regret::sampledgives a sampled best response / exploitability with a confidence interval for games too large for an exact full-tree traversal.
See Analytics for the dispatcher logic and its caveats.
- The crate uses Greek/math glyphs in its formulas (σ, π, Δ, R⁺). This wiki keeps that convention rather than ASCII-fying it.
- Doc comments in the source state behavior, panics, and complexity, including where a function panics.
- For a current, version-pinned API, check docs.rs for the dependency versions
actually in
Cargo.lock, not whatever is latest.
cargo test # default features (parallel on); unit + proptest
cargo test --features deep # also compiles + runs the Deep CFR path
cargo test --no-default-features # parallel OFF: CI checks this and --all-features
cargo test --test unit # one focused test file
cargo test --release -- --ignored --test-threads=1 # convergence suite (slow)
cargo clippy --all-targets --all-features -- -W clippy::all
cargo fmt --all -- --check # formatting gate (CI fails on this)
cargo bench --all-features # benches/suite.rsThe convergence tests in tests/convergence.rs are #[ignore]d: they train real
games to equilibrium, so run them only with --ignored --release --test-threads=1.
Plain cargo test does not compile the deep path; add --features deep.
regret-py is excluded from the workspace, so a plain cargo at the root will not
build it; it needs a Python toolchain.
Build gotcha: a git stash / stash pop shifts file mtimes and can leave a stale
compiled build, so a following cargo test may report against old objects (seen
with the sampled_* tests). Force a fresh rebuild before trusting results after
any mtime-shifting operation.