Results: layout, files, and how to read them
Nothing computes and plots in one step. Solvers/scripts call
storage.save_run to write a structured dict file; plotting.py is a
pure consumer that reads those files and draws figures. So any figure can be regenerated from
a saved run without recomputing.
Directory layout
results/
<env>/<solver>.{json,npz,png} # one training run (scripts/run.py)
sweeps/<env>_sweep_N.{json,png} # N-sweep (scripts/sweep_N.py)
surfaces/<env>_surface_delay_nu.{json,png} # 3-D surface (scripts/surface_delay_nu.py)
compare/comparison.{json,md} # the comparison table (scripts/compare.py)
The run-file schema (JSON)
Every stored run is a dict with four sections. Small values live in the readable
.json; bulky arrays are offloaded to a sidecar .npz and stitched
back by storage.load_run.
{
"config": {env, solver, N, seeds, horizon, iters, nu, delay, ...}, # what was run
"metrics": {final_return, random, oracle, ...}, # scalar summaries
"curves": {return_curve: [...], ...}, # arrays over iterations / N / grid
"meta": {timestamp, note, ...} # free-form
}
The numbers
- random — mean per-step team reward of a uniform-random policy. The floor.
- oracle — the best simple decentralized relay policy (copy the freshest target). The achievable ceiling given the staleness in the channel.
- final_return — a solver's greedy mean per-step team reward over the last 10% of iterations.
- p (in the comparison table) — fraction of the gap captured:
p = (solver - random) / (oracle - random). p=0 is no better than random; p=1 reaches the oracle.
How to read each figure
| figure | axes | what to look for |
|---|---|---|
| <env>/<solver>.png | reward vs iteration | the learning curve rising between the random and oracle lines |
| sweeps/..._sweep_N.png | reward vs N | static stays flat; under the wall the oracle sinks toward random as N grows |
| surfaces/..._surface_delay_nu.png | reward over (delay, drift), per N | the surface caves in as either axis increases, and deeper at larger N |
The comparison table
results/compare/comparison.md is a Markdown table, rows = (env, N), columns =
random, oracle, then each solver's final return and its p. It is regenerable and
version-controllable — the baselines table to grow as solvers are added.
Loading results in Python
from coadapt.storage import load_run
from coadapt.plotting import plot_learning_curve
run = load_run("results/relay_discrete/ppo.json")
print(run["metrics"]) # {'final_return':..., 'random':..., 'oracle':...}
plot_learning_curve(run, "out.png") # redraw from the saved run