Skip to content

t5lab.run_mvprop

run_mvprop

Train the EXACT previous architecture with greedy -> MVProp planner (the deal).

Config is built through ctde_v0's OWN CLI parser (train_ctde._parse_args) for byte-parity with the proven pipeline, then the ONLY change is action_head.controller = 'mvprop' and the frozen distilled planner is injected into ppo.train(..., mvplanner=). Everything else — the central setpool critic, the lagrangian dual, local_edge_margin, the reach_fraction reward, the λ̂₂ aux head, the hard collision-mask, no connectivity hard-mask — is the previous architecture, untouched.

Grading is CONNECTIVITY-FIRST: connectivity_real (λ₂>0.5 connected-fraction, the binding mission bar) is the lead metric; a run whose graph breaks is a failure regardless of coverage.

Run (GPU): PY=$HOME/ZymeraLab/.venv/bin/python PYTHONPATH=.:../../../FiedlerValueEstimation GRID=32 NAG=10 ITERS=8000 PLANNER=mvprop_distilled.eqx $PY -m t5lab.run_mvprop

build_cfg

build_cfg()

The approved-brief architecture: setpool central critic + lagrangian + local_edge_margin + goal_head + collision-on + no hard mask, cover_r=0, 7-ch SLAM belief. controller swapped to mvprop AFTER parsing (the parser only knows greedy/navfield).

Source code in experiments/t5lab/run_mvprop.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
def build_cfg():
    """The approved-brief architecture: setpool central critic + lagrangian + local_edge_margin
    + goal_head + collision-on + no hard mask, cover_r=0, 7-ch SLAM belief. controller swapped
    to mvprop AFTER parsing (the parser only knows greedy/navfield)."""
    argv = [
        "--grid", str(GRID), "--n-agents", str(NAG), "--comm-r", str(COMMR), "--horizon", "100",
        "--terrain", TERRAIN, "--cover-r", "0",
        "--n-obstacles", str(NOBST), "--rooms", str(ROOMS),
        "--sense-walls", "--sense-free", "--boundary",
        "--critic-arch", CRITIC,
        "--mechanism", "lagrangian", "--conn-signal", "local_edge_margin",
        "--collision-mask", "on",
        "--explorer-tool", "goal_head", "--role-picker", ROLE,
        "--w-coverage", "3", "--w-connectivity", WCONN,
        "--degree-target", DEGREE, "--barrier-weight", BARRIER,
        "--iters", str(ITERS), "--rollouts", "16", "--seed", str(SEED),
    ]
    cfg, _rd, _ck, _init = train_ctde._parse_args(argv)
    # THE swap axis — the ONLY change vs the previous architecture (greedy baseline vs planner).
    cfg = dataclasses.replace(cfg, action_head=dataclasses.replace(cfg.action_head,
                                                                   controller=CONTROLLER))
    if OCCLUSION:                                          # "wall RF": walls block comms (d_eff = d + c*k)
        cfg = dataclasses.replace(cfg, world=dataclasses.replace(cfg.world, occlusion=True))
    return cfg

evaluate

evaluate(env, state, cfg, planner, key, rollouts=32)

Fresh eval rollout -> connectivity-first metrics.

Source code in experiments/t5lab/run_mvprop.py
78
79
80
81
82
83
84
85
86
87
88
89
def evaluate(env, state, cfg, planner, key, rollouts=32):
    """Fresh eval rollout -> connectivity-first metrics."""
    cfg_eval = dataclasses.replace(cfg, rollouts_per_iter=rollouts)
    stencil = ppo.make_stencil(cfg_eval)
    traj = ppo.collect(env, state.actor, state.critic, cfg_eval, stencil, key,
                       state.dual.lam, planner)
    cov = float(traj["coverage"][:, -1].mean())
    return {
        "coverage_pct": 100 * cov,
        "connectivity_real": None,   # filled from training logs (per-step grader)
        "n_rollouts": rollouts,
    }