Blackwell approachability primitives for finite vector-payoff games.
Project description
PyBlackwell
PyBlackwell provides reusable Blackwell approachability primitives for finite vector-payoff games, target-set geometry, minimax action selection, and convergence certificates.
The base install uses NumPy and SciPy only:
python -m pip install pyblackwell
Quickstart
import numpy as np
from pyblackwell import (
BlackwellApproachability,
MatrixGame,
PointTarget,
convergence_summary,
summary_to_log_record,
)
payoffs = np.array(
[
[[-1.0], [1.0]],
[[1.0], [-1.0]],
]
)
game = MatrixGame(payoffs)
target = PointTarget([0.0])
solver = BlackwellApproachability(game=game, target=target)
for env_action in [0, 1] * 50:
strategy = solver.strategy()
payoff = game.payoff(strategy, env_action)
solver.update(payoff, env_action=env_action)
print(solver.summary())
print(summary_to_log_record(solver.summary()))
print(solver.certificate().to_dict())
diagnostics = convergence_summary(solver.trace(), distance_tolerance=1e-6)
print(diagnostics.to_dict())
Trace diagnostics can be summarized without optional dependencies.
For long runs where only aggregate diagnostics are needed, construct solvers
with summary_only=True. The solver still updates summary() and
certificate(), while trace() returns empty histories instead of retaining
per-iteration arrays.
Install pyblackwell[plot] to use Matplotlib diagnostics such as
plot_convergence_summary, plot_distance_trace, and
plot_payoff_averages_2d.
Feedback Modes
Explicit feedback helpers distinguish full-information payoff tables from bandit observations:
from pyblackwell import BanditFeedbackMode, FullInformationFeedbackMode
full = FullInformationFeedbackMode(expected_actions=2, expected_dim=1)
full_feedback = full.observe([[1.0], [0.0]])
print(full_feedback.diagnostics.to_dict())
bandit = BanditFeedbackMode(n_actions=2, exploration=0.1, rng=0)
action, probabilities = bandit.sample([0.75, 0.25])
bandit_feedback = bandit.observe(action, [1.0])
print(probabilities)
print(bandit_feedback.diagnostics.to_dict())
Bandit diagnostics report the sampling probability, exploration setting, and importance-weight variance proxy so estimator caveats are visible in logs.
Command-line utilities
Packaged example configurations can be run without writing a Python script:
pyblackwell-example matching-pennies-point
Game-theoretic reduction examples are packaged too:
pyblackwell-example external-regret-orthant
pyblackwell-example correlated-equilibrium-deviation-regret
Use pyblackwell-example --list to show available example names. The command
prints JSON with the run summary, metadata, and final certificate. Runtime
options can override the packaged solver, target set, iteration count,
tolerance, seed, and output directory:
pyblackwell-example matching-pennies-point --solver oco --target-set ball \
--iterations 50 --tolerance 1e-6 --seed 42 --output-dir runs
When --output-dir is provided, the command writes summary.json in that
directory. Add --save-trace to also write a compressed trace.npz archive
with the same run metadata.
Saved .npz traces can be inspected from the command line:
pyblackwell-trace-summary path/to/trace.npz
The command prints JSON with run metadata, history lengths, distance and residual diagnostics, and final payoff averages.
Benchmark configurations can be run and summarized without importing Python helpers:
pyblackwell-benchmark run --mode smoke --iterations 20 --output-dir runs/bench
pyblackwell-benchmark run --mode research --group box-target
pyblackwell-benchmark summarize runs/bench/benchmark_results.json
Benchmark filtering accepts repeatable --include, --exclude, and --group
options. The command prints JSON and writes benchmark_results.json when
--output-dir is provided.
Showcase experiment
The 0.1.0 showcase compares target-set approachability against scalar, fixed-policy, no-regret, and empirical-rate baselines on a multi-objective box target, external regret, and binary calibration task:
OMP_NUM_THREADS=1 MKL_NUM_THREADS=1 OPENBLAS_NUM_THREADS=1 \
python experiments/showcase_0_1_0.py --profile smoke \
--output-dir runs/showcase_smoke
Use --profile full for the longer single-CPU run. Use --profile extended
for the broader run with more seeds, more iterations, additional baselines, and
sparse distance-curve output configured for the same three-hour budget:
OMP_NUM_THREADS=1 MKL_NUM_THREADS=1 OPENBLAS_NUM_THREADS=1 \
python experiments/showcase_0_1_0.py --profile extended \
--output-dir runs/showcase_extended
Add --seed-variation when seeds should sample perturbed game instances and
late-shift calibration streams instead of repeating the deterministic fixture:
OMP_NUM_THREADS=1 MKL_NUM_THREADS=1 OPENBLAS_NUM_THREADS=1 \
python experiments/showcase_0_1_0.py --profile extended --seed-variation \
--output-dir runs/showcase_extended_seed_variation
The command prints a compact JSON summary and writes manifest.json,
summary.json, summary.md, results.jsonl, and distance_curves.csv into
the output directory. The primary metric is final distance to the task's target
set; per-run calibration diagnostics are kept in results.jsonl. Use
--curve-stride N to thin curve rows for custom long runs.
Representative seed-varied extended result:
profile: extended
seed_variation: true
seeds: 20
iterations per task: 10,000
calibration grid: 15
curve stride: 20
recorded runtime: 1004.9 seconds
| Task | PyBlackwell | Best baseline | Reduction | Certificate |
|---|---|---|---|---|
| Binary calibration | 0.000227565 | 0.000369325 | 38.4% | yes |
| Box target | 0.000009844 | 0.152752 | 99.99% | yes |
| External regret | 0.003623337 | 0.530723 | 99.3% | yes |
Lower is better; values are mean final distances to the target set. The seed-varied run produces spread in the box-target and external-regret tasks. Binary calibration PyBlackwell final distance is identical across the sampled late-shift streams, while several calibration baselines vary.
The public API is exported from pyblackwell. A compatibility module named
approachability re-exports the same core objects for examples that follow the
original implementation plan. The API reference documents which module import
paths are stable, which are experimental, and which implementation modules are
private.
Scope
PyBlackwell is not a general extensive-form game solver or a generic convex optimization toolkit. Its core object is an approachable target set, with projection, separation, support, repeated-game solvers, and explicit numerical certificates. Extensive-form integrations should stay adapter-based: external game solvers own tree construction, CFR or sequence-form updates, and equilibrium claims, while PyBlackwell can receive validated payoff, strategy-regret, and diagnostic records.
Development
make check
make package-check
make package-check builds the source distribution and wheel, runs strict
metadata validation on both artifacts, then installs the wheel into an isolated
environment and imports the package.
The base package avoids importing optional CVXPY, PyTorch, JAX, pandas,
Matplotlib, CVXPYLayers, JAXopt, scikit-learn, and Gymnasium dependencies at
import time.
CVXPY-backed convex and SDP target projections remain behind the cvx extra;
differentiable-optimization projection adapters remain behind the diffopt
extra; other optional integrations should remain behind extras and lazy
imports.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyblackwell-0.1.0.tar.gz.
File metadata
- Download URL: pyblackwell-0.1.0.tar.gz
- Upload date:
- Size: 268.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b7f20cc73d40dcf12a19b8f4dc30a74aaffe3b2b6dc4e82535e684a0a9f5d366
|
|
| MD5 |
c2466b6343da3fd8eabe19502ded1abb
|
|
| BLAKE2b-256 |
6ba352d816438825c5d500389bb63f5472897609db2201b30a7e744f9f04398c
|
File details
Details for the file pyblackwell-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pyblackwell-0.1.0-py3-none-any.whl
- Upload date:
- Size: 171.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.20
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6865487c1fe62fc063f48e9f2a4e6c7764552e2eef19325015eedea9aa62b85b
|
|
| MD5 |
2e5e1c98824548c04e7324ab6dde580f
|
|
| BLAKE2b-256 |
af82e73e5c7ff88f6e69cab36904bfd7d16ff2e7e455c16ad58d6a9e5134d2db
|