TargetGym¶
Reach a setpoint. Hold it forever. Against disturbances.
24 JAX environments for target MDPs, the control problems industry actually has.

One example task from each family, under PID control.
24 environments: 10 aircraft, 6 process control, 6 industrial / energy, 2 renewable energy. Every one of them is in the gallery with its own page and clip, and its recorded baseline numbers are in Baseline results.
Until 0.7.0 is on PyPI
TargetGym is in active development: PyPI releases are the stable line, and
main can change quickly between them. This site documents main, whose
API (starting with tg.make) is not on PyPI until 0.7.0. Until then,
install from GitHub to use it:
pip install "git+https://github.com/YannBerthelot/TargetGym".
Or try it in the browser: Colab quickstart.
import jax
import numpy as np
import target_gym as tg
env, params = tg.make("plane") # the scored configuration
pid = tg.make_expert("plane").host() # the shipped expert; keeps its own memory
obs, state = env.reset(jax.random.PRNGKey(0), params)
for t in range(200):
action = np.atleast_1d(pid(np.asarray(obs)))
obs, state, reward, terminated, truncated, info = env.step(
jax.random.PRNGKey(t), state, action, params
)
if terminated or truncated:
break
Browse the twenty-four environments → Getting started →
Why these environments¶
Holding a setpoint forever breaks differently than reaching a goal once, and these are the failure modes that come with it:
| Irrecoverable states | A boiler drum that carries water into the turbine, a reactor past runaway, a kiln that has gone cold |
| Partial observability | The furnace hides 6 of 9 states, the reactor 7 of 11, the kiln 64 behind 8 measurements |
| Non-minimum phase | Drum level rises as mass leaves; the four-tank's obvious loop pairing is unstable |
| Transport delay | Half the kiln's response to a fuel change takes a full 25-minute residence time |
| Multi-timescale | Millisecond neutronics against hour-long xenon; sub-second flame gas against 30 h glass residence |
| Finite budgets | A battery whose charge limits trip the pack, though exact dispatch tracking stays inside them for a 30-minute episode, so tracking costs wear rather than later tracking |
| Open-loop instability | A stirred-tank reactor held on its unstable middle steady state, where an uncontrolled error grows e-fold every 19 to 43 s (derived, scripts/unstable_cstr_numbers.py --section targets) |
| A trip the reward does not track | A compressor trips when its flow margin to surge runs out. No reward term reads that margin, and the recycle valve that protects it has no tracked output of its own |
Every environment ships a tuned PID and an MPC (on patrol_bearing_only the MPC
reads the true state, a full-state bound), so a learned policy has something real
to beat. And where a baseline is weak, the docs say how weak.
Documentation¶
-
Use it
-
Beat the baselines
-
Trust the numbers
Physics methodology · Model review checklist · Reward shaping · Testing
-
Contribute
Contributing · Roadmap and known gaps · Functional structure