2. Valid, transfers and a certified hold gate
Critical-path step 2: which edits the planner may propose, and a support test that proves its answer either way.
Code. Branch phase1/planar of Symplectomorphism/c-gnn, commit d810e32. New: marking/edits.py, physics/planar_hold.py, tests/test_planar_step2.py (17 tests); changed: Cand, the solver’s success check and the search’s acceptance, for planar scenes only. Angelo’s 3D path is untouched.
What step 2 changes
Step 1 made the contact labels right. Step 2 makes the planner’s menu of edits right. Cand proposes an edit only when it passes the paper’s checks:
- The edit is an edge of the marking graph: both the current formation and the new one are Valid. No two excluded contacts ({g, t}, {gv, s}, {g, sv}, {g, mz}), and at most one contact per body pair.
- Near: a contact it adds is already within the gap gate.
- H: the contacts that persist through the edit hold the box at the current pose.
The menu now has five kinds of edit:
| Edit | Changes | Example |
|---|---|---|
| make(c), break(c) | one contact | make(s): push the box against the riser |
| transport | nothing (moves the pose) | slide the box along the floor |
| transfer(c → d) (new) | one contact for a neighbouring one in the same pair | g → gv: the box starts to tip onto its corner |
| pass-through (new) | two transfers that cannot be separated | the pivot: g → gv and s → sv at once |
Transport is now offered only when the current formation is supported, as the paper defines it; before, it was always legal.
At the start ({g}, box flat on the floor), Cand no longer offers a second floor contact, t, sv or mz (all excluded with g), or the transfer g → gv. That last one is refused by H: during the swap only the box’s corner would still touch the floor, and one corner cannot hold a flat box.
Pass-through, made precise
Decision 7 adopted pass-through edges for the pivot: from {mx, g, s} the box can only reach {mx, gv, sv} by changing two contacts at once, because both one-at-a-time intermediates, {gv, s} and {g, sv}, are excluded. Taken literally (“some sequence of steps through invalid markings”), the definition would also let any contact replace any other contact of its pair in one edit: make the new one first, which is invalid because the pair then has two, then break the old one. That would make transfer adjacency pointless.
Implemented: two single steps in different body pairs whose intermediates are invalid in both orders. Both must then be transfers with crossed exclusions. On the step scene the only pass-throughs are the pivot and its reverse. A brute-force search over all 12,393 markings with at most one contact per pair finds exactly the same 128 pass-through edges. This reading is up for review.
H: persistent contacts, decided exactly
H asks whether the contacts that persist through the edit hold the box (Decision 7). For a make or a break that is the paper’s rule (the contacts kept). For a transfer, only the part of the old contact set that the new one still covers persists: for g → gv, the box’s corner.
Background tutorial: Deciding support exactly derives this test step by step, with a worked example, proofs of the witness, certificate and margin, and exercises. The hold test as a linear program poses the same question as LPs that also serve the 3D build. That backbone is now built (PlanarHold(method="lp"), linrax in float32); the exact test stays the default until the margin is chosen.
The test. In the plane, every contact force is a nonnegative mix of the two edges of its friction cone. So “the contacts hold the box” means that the wrench cancelling gravity (x force, z force, moment) lies in a cone in 3D generated by at most 16 vectors. That is decided exactly, with proof either way:
- Supported: a nonnegative combination of at most three generators that reproduces the wrench, by Carathéodory’s theorem. This is the witness.
- Not supported: a plane through the origin with every generator on one side and the gravity wrench on the other, by Farkas’s lemma. This is the certificate. Every face of the cone is spanned by two generators, so the candidate planes are few.
- Margin: the signed distance from the gravity wrench to the cone’s boundary, with forces in units of mg and moments in mg·a/2. Inside the cone it is the largest disturbance the contacts absorb in every direction; outside, minus the distance to the cone. A flat box on the floor: 0.196, which is μ/√(1+μ²) for μ = 0.2. With the disk in the formation the cone often fills all of 3D, because the disk’s force is unbounded. A finite margin there needs the manipulator’s force limits, an open item of Decision 6.
The same function takes a lower friction coefficient and mass and center-of-mass vertices, and returns the worst-case margin (the robust margin of Decision 6).
The pivot needs the disk low
The chain’s canonical pose for σ3 puts the disk at the middle of −xB. There, H refuses break(gv): pushing at mid-height, the disk cannot keep the box on the step corner without the floor. With the disk pushing low (toward the floor), the same edit is admitted up to about 60° of tilt. A search gets there by transport: moving the disk down the face within the formation. A float64 LP confirms the refusal at mid-height, so this is a fact about the physics, not about the test. The same holds for make(t) at σ4.
With that, Cand offers every step of the paper’s chain from a pose in its formation: make(mx), make(s), the pivot pass-through, break(gv), make(t), break(mx), make(mz), break(sv). Theorem relocate holds: with σ = {mx, s}, break(mx) is never offered.
Which hold solver
The plan was to build H on MPAX, Angelo’s LP solver, then benchmark and switch if a solver won clearly. One did. The benchmark covers 1,000 random cases and 416 cases within 2 mm of the support boundary. Every answer is checked against a float64 LP (SciPy’s HiGHS) on an independently coded formulation.
| Backend | Random (1,000) | Near the boundary (416) | ms per 256, CPU / GPU |
|---|---|---|---|
| Old 6-row MPAX LP | 998 | 220 (194 false rejections) | 3,879 / 313 |
| 3-row MPAX LP | 999 | 222 (192 false rejections) | 63 / 110 |
| Exact, certified | 1,000 | 393 on CPU, 389 on GPU (21–26 false rejections, 1–2 false acceptances) | 4.3 / 2.0 |
Every error of the exact test lies within 0.33 mm (of disk height) of the boundary on CPU, and within 0.67 mm on GPU, where float32 geometry decides. Everywhere 0.7 mm or more away it is right, on both. One GPU pitfall was caught on the way: JAX runs float32 matrix products on the GPU in reduced precision (TF32), which broke the test’s check of supporting planes; it now forms every dot product elementwise. The step-1 contact layer is not affected: on 5,721 poses its gaps agree between CPU and GPU to 2.7 µm, and its on-sets exactly. Both LPs reject supported formations across the whole 2 mm band: their “not supported” often meant “ran out of iterations”. The exact test is now the hold gate for planar scenes; the MPAX version stays in the code for comparison.
εpen and ties
Step 1 left a known issue: with εpen = 10 mm, two contacts of one pair can both count as touching under deep penetration. Step 2 was to set εpen from the penetration measured in the solver’s rollouts. The measurement says not yet:
- In 24 full MPPI rollouts of the chain’s edits, the pushing edits penetrate up to 9.9 mm (95th percentiles 4–8 mm); the passive breaks stay under 1.6 mm.
- The cause is MPPI’s cost, whose arrival term rewards penetration (the shove on walkthrough page 7). A tighter εpen now would fail every pushing rollout.
- So εpen moves to step 3, after the cost.
Done now: a pose with a tie can neither count as a solver success nor become a search node. A stress test in the suite tracks ties on 4,000 jittered demo poses (357 today).
One more finding for step 3: all 24 rollouts fail the solver’s success check, the passive breaks included, and not because of ties.
Checks
- The marking graph, exhaustively (11,959 valid markings): every edge lands on a valid formation; every edge has its reverse; the degree bound holds; the graph is connected, and its distance is between a quarter of the Hamming distance and the Hamming distance. These are the claims of the restated Lemma
markgraph-structin the paper. - Supported against the float64 LP: 250 random cases and the pivot scan, all certified, all equal.
- The cone test against HiGHS on 400 random cones in 3D, plus the degenerate cases (wedge, ray, empty, all of 3D).
- The full suite, 48 tests, passes on Python 3.14 (CPU and GPU) and 3.12.
For review
- The pass-through reading (two inseparable transfers).
- The persistent set of a transfer uses the old contact’s normal and friction.
- The margin’s definition (signed distance to the cone’s boundary, in mg and mg·a/2), and its cap when the disk’s force is unbounded.
- The exact test replacing MPAX for planar scenes.
Reproduce
cd ~/repos/research/c-gnn && git switch phase1/planar && git pull && cd cmg
source .venv314/bin/activate
JAX_PLATFORMS=cpu PYTHONPATH=tests python -m pytest -q tests/test_planar_step2.py
JAX_PLATFORMS=cpu python <website>/research/nonprehensile/planar-build/scripts/02_hold_gate.py <out dir>← 1. The planar contact layer · Known issues · Back to the planar build