Skip to main content

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 classical theorem-facing path is the finite-game solver with bounded vector payoffs, closed convex targets, full-information or expected-payoff updates, and exact or tolerance-controlled projection and minimax oracles. Wrappers for sampled calibration, bandit feedback, and RL-style workflows report diagnostics, but their guarantees require the additional assumptions stated in the theory notes.

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 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 Comparison Certificate
Binary calibration 0.000227565 0.000369325 (ema_alpha_0_05) 38.4% lower yes
Box target 0.000009844 0.152752 (scalar_reward_1) 99.99% lower yes
External regret 0.003623337 0.001816885 (hedge_eta_0_1) 99.4% higher yes

Lower is better; values are mean final distances to the target set. Positive comparisons mean PyBlackwell is closer to the target than the best baseline; the external-regret row is the exception after the regret-sign correction, where the tuned Hedge baseline has the lower finite-horizon distance. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyblackwell-0.1.1.tar.gz (291.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyblackwell-0.1.1-py3-none-any.whl (177.7 kB view details)

Uploaded Python 3

File details

Details for the file pyblackwell-0.1.1.tar.gz.

File metadata

  • Download URL: pyblackwell-0.1.1.tar.gz
  • Upload date:
  • Size: 291.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for pyblackwell-0.1.1.tar.gz
Algorithm Hash digest
SHA256 1d5c3ce69e76259aca7bc23e7eeb0ce4d584fe76769ee22a47a297e7527d406b
MD5 0c304724b50770368797c23df0cfbb62
BLAKE2b-256 d5ec40c5572b440cffec2c3443a6b47bbc7ca1ba6b3700001833dbc44074080e

See more details on using hashes here.

File details

Details for the file pyblackwell-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: pyblackwell-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 177.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.20

File hashes

Hashes for pyblackwell-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b15970b692c8c7cd3368c37583bddb5b48f9773700c22a0fcb765b3188bc3d4c
MD5 80e453d346d04aceb79dba12524ee2da
BLAKE2b-256 7fbbe1a68f3ad77c38237e7f1d580241804d9c975ba494233650ae2dbf390351

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page