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 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


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.0.tar.gz (268.5 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.0-py3-none-any.whl (171.5 kB view details)

Uploaded Python 3

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

Hashes for pyblackwell-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b7f20cc73d40dcf12a19b8f4dc30a74aaffe3b2b6dc4e82535e684a0a9f5d366
MD5 c2466b6343da3fd8eabe19502ded1abb
BLAKE2b-256 6ba352d816438825c5d500389bb63f5472897609db2201b30a7e744f9f04398c

See more details on using hashes here.

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

Hashes for pyblackwell-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6865487c1fe62fc063f48e9f2a4e6c7764552e2eef19325015eedea9aa62b85b
MD5 2e5e1c98824548c04e7324ab6dde580f
BLAKE2b-256 af82e73e5c7ff88f6e69cab36904bfd7d16ff2e7e455c16ad58d6a9e5134d2db

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