Life-cycle-cost-optimal maintenance planning for a deteriorating bridge element, framed as a Markov Decision Process and solved with Dynamic Programming (an exact baseline) and PPO actor-critic Reinforcement Learning β with interpretable soft/oblique decision-tree policies and a statistical front-end that fits the initial condition-state distribution from real National Bridge Element (NBE) inspection data.
π Companion code for: S. A. Moayyedi and D. Y. Yang, "Interpretable Deep Reinforcement Learning for Element-level Bridge Life-cycle Optimization," Portland State University, 2026 β arXiv:2604.02528 (under review). See Citation.
- Motivation
- What this repository does
- Problem formulation
- Repository structure
- Installation
- Usage
- Methodology
- Results
- Roadmap
- Citation
- License
The 2022 Specifications for the National Bridge Inventory (SNBI) represent a bridge element's condition as a four-dimensional array of condition-state (CS) proportions rather than a single categorical rating. This granularity is valuable, but it dramatically expands the state space over which owners must decide when and how to intervene β do nothing, maintain, repair, rehabilitate, or replace β to minimize the risk-included life-cycle cost (LCC): the discounted sum of intervention costs plus the expected cost of failure.
This project treats that decision problem as a Markov Decision Process (MDP). It is the companion code for the paper above and focuses on two concrete goals:
Goal 1 β Model the initial condition. Fit Dirichlet and Multinomial models to real bridge-element inspection data, compare both against the data (in 1-D, 2-D, and 3-D), pick the better-fitting distribution, and use its parameters (the Dirichlet concentration vector Ξ±) as the environment's initial condition-state distribution.
Goal 2 β Compare DP with PPO. Solve the maintenance MDP with Dynamic Programming (value iteration β the exact optimum) and evaluate it in the same environment used to train PPO actor-critic RL, so the two approaches are compared on identical dynamics, costs, and initial conditions.
The inspection data are real FHWA InfoBridge records for Oregon state-highway steel-girder bridges; the distributions are fit via Maximum Likelihood (L-BFGS-B with analytic gradients) and the Method of Moments.
| Component | File(s) | Description |
|---|---|---|
| Environment | bridge_gym/example_nbe107/ |
A gymnasium MDP for a single steel girder/beam element (NBE 107): 4 condition states, 5 maintenance actions, cost-shaped reward. |
| Dynamic Programming | DPvsPPO.py |
Finite-horizon and stationary value iteration; the exact optimal baseline. Includes a hand-verified toy example. |
| PPO actor-critic | softtree_ppo/ |
A TorchRL PPO trainer (PPOTrainer) plus a soft-tree variant with entropy/L1/L2/group-L1 regularization and Ξ²-annealing. |
| Interpretable policies | softtree/ |
Soft decision-tree classifier, pruning, and conversion to a compact oblique decision tree with text/Graphviz visualization. |
| Data modeling (MLE/MoM) | Dir_MLE_MOM_MultiNomin.py |
Fits Dirichlet (MLE with analytic gradient, L-BFGS-B) and Multinomial models to NBE condition-state percentages; ternary/marginal diagnostics and KS goodness-of-fit. |
| Convergence & stats | convergence.py, eval_stats.py |
Mean Β± 95% CI of episode returns and a precision-based stopping rule for the number of evaluation episodes. |
-
State β a probability distribution over 4 condition states
[CS1, CS2, CS3, CS4](best β worst), optionally augmented with normalized time. The initial state is sampled from aDirichlet(Ξ±)fitted to real data. -
Actions β
{0: Do nothing, 1: Maintenance, 2: Repair, 3: Rehabilitation, 4: Replacement}, each with its own Markov transition matrix and unit cost. -
Dynamics β
s' = Pα΅(a) Β· s, renormalized for numerical stability. -
Reward β the negative of the per-step cost,
cost(s, a) = unit_cost(a)Β·s + (p_failΒ·s)Β·failure_cost reward = βcost (discounted by Ξ³ = 1/1.03) -
Objective β maximize expected discounted return β minimize LCC.
Deterioration and cost assumptions are documented inline in
bridge_gym/example_nbe107/settings.py (transition matrices adapted from
Thompson et al. 1998, CoRe element 107, migrated to the NBE convention per the
AASHTO Bridge Element Inspection Manual).
actCrit-vs-DynPrg-RL-MLE/
βββ DPvsPPO.py # DP value iteration + evaluation in the RL env
βββ Dir_MLE_MOM_MultiNomin.py # Dirichlet/Multinomial fitting to NBE data
βββ convergence.py # Episode-count convergence analysis
βββ eval_stats.py # Mean & confidence-interval helper
β
βββ bridge_gym/ # Gymnasium environment package
β βββ debug_example_nbe107.py # Manual rollout / env-spec sanity checks
β βββ example_nbe107/
β βββ settings.py # Transition matrices, costs, failure probs
β βββ rl_env.py # SingleElement gym.Env
β βββ cost_util.py # Cost β reward transforms
β
βββ softtree/ # Interpretable decision-tree tooling
β βββ softtree_classification.py # Differentiable soft decision tree
β βββ training_util.py # Supervised soft-tree training loop
β βββ extraction_util.py # Node pruning
β βββ oblique_tree.py # Soft tree β compact oblique tree (+viz)
β
βββ softtree_ppo/ # PPO actor-critic training
β βββ training.py # PPOTrainer / SofttreePPOTrainer
β βββ rl_util.py # Actor & critic networks
β βββ settings.py
β
βββ V1_.. V4_Datainfobridge*/ # NBE inspection exports (input data)
βββ plot/ # Generated figures
βββ requirements.txt
βββ CITATION.cff
βββ LICENSE
Requires Python 3.10+.
git clone https://github.com/SAMIRHOSEIN/actCrit-vs-DynPrg-RL-MLE.git
cd actCrit-vs-DynPrg-RL-MLE
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txtTorchRL note.
torchrlandtensordictare tightly version-coupled; install matching releases. The code targets a recent TorchRL (β0.11) β see the comments insofttree_ppo/training.pyfor the older 0.9.2 API equivalents.Graphviz note. Rendering oblique-tree diagrams needs the Graphviz system package in addition to the
graphvizPython binding (apt install graphviz/brew install graphviz).
1 β Fit the initial condition-state distribution from inspection data
python Dir_MLE_MOM_MultiNomin.pyEstimates Dirichlet(Ξ±) and Multinomial parameters, runs a synthetic
parameter-recovery sanity check, and writes marginal-fit figures to plot/.
The fitted Ξ± feeds the environment's dirichlet_alpha reset distribution.
2 β Solve and evaluate the Dynamic-Programming policy
python DPvsPPO.pyRuns value iteration (stationary by default; set ELE_DP_INC_STEP = True for
finite-horizon), evaluates the DP policy in the environment over many episodes,
and reports mean episode return with a 95% confidence interval.
3 β Assess evaluation-count convergence
python convergence.pyParses the printed mean / 95% CI / SD / N summary lines and reports the
smallest N whose CI half-width falls within the relative tolerance.
4 β Sanity-check the environment
python -m bridge_gym.debug_example_nbe107Manual rollout plus a TorchRL check_env_specs integrity test.
The PPO trainer lives in
softtree_ppo/training.py(PPOTrainer/SofttreePPOTrainer) and is driven programmatically; see Roadmap.
Dynamic Programming (exact baseline). Both finite-horizon backward induction and infinite-horizon discounted value iteration are implemented from first principles for transparency, and validated against a 2-state / 2-action example with hand-computed values.
PPO actor-critic (learned policy). Built on TorchRL with GAE, clipped surrogate loss, optional entropy bonus, and L1/L2/group-L1 actor regularization. A soft-tree variant additionally anneals the routing temperature (Ξ²) during training so the policy sharpens toward hard, interpretable splits.
Interpretable policies. The PPO actor can be a differentiable soft decision tree, which is pruned and converted into a compact oblique decision tree whose splits are linear rules on the condition-state vector β small enough to read and audit.
Data modeling (MLE / MoM). The Dirichlet fit uses L-BFGS-B with an analytic gradient and a method-of-moments initialization (Minka / Ronning); fit quality is checked against the Multinomial model with ternary KDE plots (2-D and 3-D), per-CS marginals, and KS goodness-of-fit.
All figures below are produced directly by the scripts in this repository.
Dir_MLE_MOM_MultiNomin.py fits a Dirichlet and a Multinomial model to the real
inspection data and compares them against the data. Two views make the
difference clear (reducing the four condition states to three,
CS3_new = CS3 + CS4, lets the compositions be drawn on the probability
simplex):
3-D density on the simplex β real vs. Dirichlet vs. Multinomial. The real data piles up near the CS1 corner and along the CS1βCS2 edge. The Dirichlet reproduces this boundary-concentrated shape; the Multinomial collapses to a single narrow spike.
1-D marginal for CS1 β real (red) vs. Dirichlet (blue) vs. Multinomial (green). The real marginal is U-shaped (mass at 0 and 1); the Dirichlet tracks it, while the Multinomial forms an incorrect central bump.
Why the Dirichlet is chosen. A bridge element's condition is a vector of four
condition-state proportions that sum to one β a composition on the probability
simplex β and the Dirichlet is the natural distribution over such compositions.
The Multinomial instead models integer counts and, for a fixed number of cells,
is far too concentrated to represent the true diversity of bridge conditions.
This diversity matters for training: a policy trained only from a brand-new
element (s = [1, 0, 0, 0]) leaves most of the state space unexplored, so each
training episode is instead restarted from a Dirichlet-sampled condition, which
exposes the policy to the full range of realistic (and worse-than-average)
conditions. The fitted concentration vector Ξ±Μ is therefore adopted as the
environment's initial condition-state distribution.
The Dirichlet-implied Beta marginal for each condition state (orange) against the real data (blue):
DPvsPPO.py solves the MDP with value iteration and evaluates the resulting
policy in the same SingleElement environment that PPO trains and is
evaluated in, so both methods see identical dynamics, costs, and (Dirichlet-
sampled) initial conditions. Below, each point is one of 1,000 validation
episodes: as the initial reliability index Ξ² increases (a healthier
starting element), the episode life-cycle cost drops sharply β the DP policy
spends less on interventions when the element starts in good condition.
DPvsPPO.py also reports the mean episode return with a 95% confidence
interval, the action distribution, and a color-coded action timeline;
convergence.py shows how the return estimate tightens as the evaluation-episode
count grows. The head-to-head DP-vs-PPO comparison under this shared environment
is presented in the accompanying paper.
- Add a runnable PPO training entry-point script (train β evaluate β compare against the DP baseline in one command).
- Publish a consolidated DP-vs-PPO results table and figures.
- Package the modules (
pyproject.toml) forpip install -e .. - Add unit tests for the environment dynamics and value-iteration correctness.
If you use this code or its results, please cite the accompanying paper (see
also CITATION.cff):
S. A. Moayyedi and D. Y. Yang, "Interpretable Deep Reinforcement Learning for Element-level Bridge Life-cycle Optimization," Portland State University, 2026. arXiv:2604.02528 (under review).
Released under the MIT License. Β© 2025 Amir Moayyedi.






