InfraLab
InfraLab is an open Python library in which the management of a bridge stock is a game played quarter by quarter under partial information, a budget and a regulation. The four choices behind a bridge-management study are exchangeable pieces:
| Piece | Form | Argument |
|---|---|---|
| Stock | a file of bridges with their inventory attributes (an importer reads National Bridge Inventory files) | scenario |
| Degradation law | a Python function degrade(ctx) that returns the new condition of a component |
degradation |
| Regulation | a YAML file of duties: trigger, action, deadline, enforcement | law |
| Player | a function from the observation to a plan | policy |
Every random draw is keyed to seed, process, bridge and quarter, so two settings meet the same events and are compared seed by seed in one call. A game is replayed exactly from its settings, its seed and the library version.
Install
pip install infralab # core: numpy, scipy, pandas, PyYAML
pip install "infralab[mcp]" # MCP server
pip install "infralab[anthropic]" # Claude players
pip install "infralab[openai]" # OpenAI and compatible endpoints
pip install "infralab[web]" # web platform (board for human players)
From the source: pip install . in the root of the repository.
Quick start
import infralab
env = infralab.make("regbench/aged-30", law="regbench/D1", seed=0, horizon_years=10)
obs, info = env.reset()
while not env.done:
plan = {} # {asset_id: action_name}; empty = no action
obs, reward, terminated, truncated, info = env.step(plan)
print(env.summary())
env.compact_observation() gives what the owner knows in a few hundred characters per asset;
env.feasible_actions(asset_id) the actions available with their cost; env.rules() the rules of the run;
info["report"] what happened in the quarter (accepted and dropped requests, inspections forced by the
regulation, interventions of the ethical floor, collapses).
Outcomes
run, Env.summary and compare_laws report outcomes computed on the true state, never shown to a player:
| Key | Meaning |
|---|---|
S1 |
mean over bridges of the lowest true annual reliability index reached during the game |
expected_collapses |
expected strength collapses: sum over bridges and quarters of the quarterly failure probability of the true state |
expected_hydraulic_collapses |
expected collapses from progressive hydraulic defects that matured unarrested |
bridges_below_limit, bridge_years_below_limit |
bridges, and bridge-years, with a true annual index below 3.02 |
collapses |
collapses drawn in the game |
cash_spend, user_cost, closed_share |
what the owner paid, the extra travel cost of road users, the closed share of bridge-years |
Change one piece
The player
def inspect_then_fix(observation):
bridges = observation["my_bridges"]
plan = {b["id"]: "inspect" for b in bridges if b["inspection_overdue"]}
free = [b for b in bridges if b["id"] not in plan and b["active_maintenance"] is None]
if free:
worst = min(free, key=lambda b: b["min_observed_condition"])
if worst["min_observed_condition"] < 0.3:
plan[worst["id"]] = "restore"
return plan
infralab.run(inspect_then_fix, "regbench/aged-30", law="regbench/D1", config="paper-short")
infralab.policies() lists the supplied players (passive, worst_first, typical, diligent, heuristic,
monte_carlo, q_learning, genetic, memetic); basic:<rule> reaches the other fixed rules
(infralab.basic_policies()); infralab.actions() lists the action names accepted in a plan.
The regulation
r = infralab.compare_laws("regbench/D0", "regbench/D1", policy="passive",
scenario="regbench/aged-147", config="paper",
params={"ethical_floor_enabled": True}, n_seeds=10, workers=5)
r["difference_b_minus_a"]["S1"] # mean paired difference, lower and upper bound (95 percent)
The two regulations are played on the same stock, player and random draws. A regulation is a YAML file:
pass a path instead of an identifier to test your own (examples/04_inspection_interval.py writes nine).
The degradation law
# markov.py: a Markov chain on inventory ratings
P = {9: 0.1483, 8: 0.0672, 7: 0.0334, 6: 0.0321, 5: 0.0355, 4: 0.0421, 3: 0.0428, 2: 0.0852, 1: 0.0193}
D = {9: 1.12, 8: 1.06, 7: 1.08, 6: 1.14, 5: 1.27, 4: 1.35, 3: 2.22, 2: 1.80, 1: 1.00}
def degrade(ctx):
c = ctx["condition"]
if ctx["age_increment_years"] <= 0:
return c
r = min(9, max(1, round(9 * c)))
if ctx["rand"]() < 1 - (1 - P[r]) ** 0.25:
c -= D[r] / 9
return c
infralab.compare_laws("regbench/D0", "regbench/D1", policy="passive", scenario="regbench/aged-147",
config="paper", degradation="markov.py", n_seeds=10, workers=5)
infralab.degradation_laws() lists the laws supplied: weibull (default), gamma, regbench/power,
regbench/markov-nbi.
The stock
infralab.data.nbi reads a National Bridge Inventory file and builds a scenario
(python -m infralab.data.nbi --help); infralab.load_scenario(path) reads any scenario file.
The benchmark of the paper
| Item | Identifiers |
|---|---|
| Stocks | regbench/aged-147, regbench/aged-30: aged samples of the 2023 Delaware inventory |
| Regulations | regbench/D0 no obligation; regbench/N24 routine inspection every 24 months, 12 for rating 3 or lower; regbench/D1 intervals graded by attention class; D2 post-event; D3 both; K0 flat biennial; G0–G3, J0–J1 with a practice rule |
| Configurations | paper (147 bridges, 50 years; default), paper-short (30 bridges, 5 years), paper-less-optimistic (sensitivity of the reliability calibration); earlier configurations first, second, third, calibrated, calibrated-short |
examples/ holds the examples of the paper: 01_change_the_regulation.py, 02_change_the_degradation_law.py,
03_change_the_player.py and 04_inspection_interval.py. Called as in these scripts, the library reproduces
the stored games of the paper to the last digit (tests/paper_reproduction_check.py).
The parameter values are plausible and, apart from the matching of the reliability index to load ratings, not calibrated. The reliability index serves paired comparisons between settings, not levels; results carry to a real stock only through a stock and a degradation law fitted to it.
Interfaces
Command line
infralab list
infralab run worst_first --law regbench/D1 --years 10
infralab compare regbench/D0 regbench/D1 --policy passive --seeds 10 --years 10
MCP server. Any Model Context Protocol client can manage a stock through tools.
infralab-mcp # stdio
infralab-mcp --transport sse # HTTP
{"mcpServers": {"infralab": {"command": "infralab-mcp", "env": {"INFRALAB_RUN_DIR": "runs"}}}}
Tools: list_scenarios, list_laws, describe_law, list_policies, new_run, rules, observe,
asset_actions, action_catalogue, step, score, run_policy, compare_laws. The server holds no key and
calls no model. During a run it returns only what the owner may know; the outcomes computed on the true state
are released when the run is over.
Language-model players.
from infralab.llm import play
play("anthropic:claude-opus-5-5", "regbench/aged-30", law="regbench/D1", seed=0)
play("openai:gpt-4.1-mini", "regbench/aged-30", law="regbench/D1", seed=0)
play("openai:llama3.1", base_url="http://localhost:11434/v1") # any endpoint with the same protocol
Keys are read from the environment (ANTHROPIC_API_KEY, OPENAI_API_KEY, or the variable named with api_key_env).
Web platform. A board for human players (FastAPI backend and React frontend, see docs/WEBAPP.md), and the
Streamlit interface app.py.
Tests
pip install ".[dev]"
pytest
Citation
See CITATION.cff. Model documentation: docs/MODEL_REPORT.md; numerical changes to the engine:
docs/CHANGELOG_MODEL.md.
License
MIT, see LICENSE.
Metadata
Release files for infralab 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| infralab-1.0.0.tar.gz | 434.0 kB | Without provenance | Details for infralab-1.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| infralab-1.0.0-py3-none-any.whl | Python 3 | none | any | Details for infralab-1.0.0-py3-none-any.whl |
Total release size: 816.0 kB
Release files / infralab-1.0.0.tar.gz
| Download URL | infralab-1.0.0.tar.gz |
|---|---|
| Size | 434.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1f3254258182f81ca346b3e1640ec89951113a13bdbbaf9bedcbea5f55ac040a
|
|
BLAKE2b-256 checksum How to use checksums |
6dc42aafa42f3d66ab40ee7e14e993d3789e1196fd1beb33565b56eb1c6a7e28
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Release files / infralab-1.0.0-py3-none-any.whl
| Download URL | infralab-1.0.0-py3-none-any.whl |
|---|---|
| Size | 382.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d0dd4975b0393568aaa15f471f6a3c907d938e742cf28b1512fba6eabe3756f6
|
|
BLAKE2b-256 checksum How to use checksums |
3d23315c293d9b738fc3b6b61a2011a8515688fa5bbcc816043bd6d8edd3d457
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.10
|
Security for infralab 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.