gato-mpc 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gato_mpc-0.1.1/CHANGELOG.md +393 -0
- gato_mpc-0.1.1/CITATION.cff +31 -0
- gato_mpc-0.1.1/CMakeLists.txt +221 -0
- gato_mpc-0.1.1/LICENSE +21 -0
- gato_mpc-0.1.1/MANIFEST.in +15 -0
- gato_mpc-0.1.1/PKG-INFO +529 -0
- gato_mpc-0.1.1/README.md +470 -0
- gato_mpc-0.1.1/_build_resources.py +52 -0
- gato_mpc-0.1.1/docs/README.md +24 -0
- gato_mpc-0.1.1/docs/archaeology.md +55 -0
- gato_mpc-0.1.1/docs/constraints.md +374 -0
- gato_mpc-0.1.1/docs/consumer_contract.md +232 -0
- gato_mpc-0.1.1/docs/development.md +187 -0
- gato_mpc-0.1.1/docs/figure-refresh-2026-10-01.md +257 -0
- gato_mpc-0.1.1/docs/status.md +61 -0
- gato_mpc-0.1.1/docs/website.md +19 -0
- gato_mpc-0.1.1/examples/cpp/CMakeLists.txt +44 -0
- gato_mpc-0.1.1/examples/cpp/batched_solve.cu +121 -0
- gato_mpc-0.1.1/examples/go2_description/README.md +8 -0
- gato_mpc-0.1.1/examples/go2_description/go2.urdf +761 -0
- gato_mpc-0.1.1/examples/iiwa_description/5674K57_flange_mount_ball_transfer.stl +0 -0
- gato_mpc-0.1.1/examples/iiwa_description/assembled_ee.stl +0 -0
- gato_mpc-0.1.1/examples/iiwa_description/case_shell.stl +0 -0
- gato_mpc-0.1.1/examples/iiwa_description/iiwa14.urdf +431 -0
- gato_mpc-0.1.1/examples/iiwa_description/iiwa_base.stl +0 -0
- gato_mpc-0.1.1/examples/iiwa_description/iiwa_grid.urdf +216 -0
- gato_mpc-0.1.1/examples/iiwa_description/iiwa_link_1.stl +0 -0
- gato_mpc-0.1.1/examples/iiwa_description/iiwa_link_2.stl +0 -0
- gato_mpc-0.1.1/examples/iiwa_description/iiwa_link_3.stl +0 -0
- gato_mpc-0.1.1/examples/iiwa_description/iiwa_link_4.stl +0 -0
- gato_mpc-0.1.1/examples/iiwa_description/iiwa_link_5.stl +0 -0
- gato_mpc-0.1.1/examples/iiwa_description/iiwa_link_6.stl +0 -0
- gato_mpc-0.1.1/examples/iiwa_description/iiwa_link_7.stl +0 -0
- gato_mpc-0.1.1/examples/iiwa_description/kuka_to_sensor_mount.stl +0 -0
- gato_mpc-0.1.1/examples/iiwa_description/sensor_to_case_mount.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/indy7.urdf +378 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/collision/Indy7_0.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/collision/Indy7_1.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/collision/Indy7_2.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/collision/Indy7_3.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/collision/Indy7_4.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/collision/Indy7_5.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/collision/Indy7_6.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/collision/Indy7_eye_6.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/visual/Indy7_0.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/visual/Indy7_1.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/visual/Indy7_2.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/visual/Indy7_3.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/visual/Indy7_4.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/visual/Indy7_5.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/visual/Indy7_6.stl +0 -0
- gato_mpc-0.1.1/examples/indy7_description/meshes/visual/Indy7_eye_6.stl +0 -0
- gato_mpc-0.1.1/gato/bsqp/bsqp.cuh +1398 -0
- gato_mpc-0.1.1/gato/bsqp/kernels/admm.cuh +532 -0
- gato_mpc-0.1.1/gato/bsqp/kernels/bdsv.cuh +285 -0
- gato_mpc-0.1.1/gato/bsqp/kernels/contact_debug.cuh +154 -0
- gato_mpc-0.1.1/gato/bsqp/kernels/line_search.cuh +162 -0
- gato_mpc-0.1.1/gato/bsqp/kernels/merit.cuh +370 -0
- gato_mpc-0.1.1/gato/bsqp/kernels/pcg.cuh +81 -0
- gato_mpc-0.1.1/gato/bsqp/kernels/schur_linsys.cuh +580 -0
- gato_mpc-0.1.1/gato/bsqp/kernels/setup_kkt.cuh +484 -0
- gato_mpc-0.1.1/gato/bsqp/kernels/sim.cuh +115 -0
- gato_mpc-0.1.1/gato/bsqp/rowgroups.cuh +1156 -0
- gato_mpc-0.1.1/gato/constants.h +73 -0
- gato_mpc-0.1.1/gato/dynamics/go2/grid.cuh +50068 -0
- gato_mpc-0.1.1/gato/dynamics/go2/limits.cuh +58 -0
- gato_mpc-0.1.1/gato/dynamics/grid_plant_step.cuh +376 -0
- gato_mpc-0.1.1/gato/dynamics/iiwa14/grid.cuh +35699 -0
- gato_mpc-0.1.1/gato/dynamics/iiwa14/limits.cuh +43 -0
- gato_mpc-0.1.1/gato/dynamics/indy7/grid.cuh +34585 -0
- gato_mpc-0.1.1/gato/dynamics/indy7/limits.cuh +40 -0
- gato_mpc-0.1.1/gato/dynamics/integrator.cuh +290 -0
- gato_mpc-0.1.1/gato/dynamics/manifold.cuh +89 -0
- gato_mpc-0.1.1/gato/dynamics/plant.cuh +1131 -0
- gato_mpc-0.1.1/gato/settings.h +79 -0
- gato_mpc-0.1.1/gato/types.cuh +84 -0
- gato_mpc-0.1.1/gato/utils/cuda.cuh +42 -0
- gato_mpc-0.1.1/gato/utils/dlpack.h +366 -0
- gato_mpc-0.1.1/gato/utils/linalg.cuh +84 -0
- gato_mpc-0.1.1/pyproject.toml +137 -0
- gato_mpc-0.1.1/python/bindings.cu +765 -0
- gato_mpc-0.1.1/python/gato/__init__.py +56 -0
- gato_mpc-0.1.1/python/gato/_arrays.py +98 -0
- gato_mpc-0.1.1/python/gato/_cache.py +362 -0
- gato_mpc-0.1.1/python/gato/_grid.py +75 -0
- gato_mpc-0.1.1/python/gato/_registry.json +47 -0
- gato_mpc-0.1.1/python/gato/builder.py +367 -0
- gato_mpc-0.1.1/python/gato/certificate.py +117 -0
- gato_mpc-0.1.1/python/gato/common.py +233 -0
- gato_mpc-0.1.1/python/gato/config.py +133 -0
- gato_mpc-0.1.1/python/gato/controller.py +258 -0
- gato_mpc-0.1.1/python/gato/envs.py +121 -0
- gato_mpc-0.1.1/python/gato/estimators.py +709 -0
- gato_mpc-0.1.1/python/gato/fingerprint.py +128 -0
- gato_mpc-0.1.1/python/gato/gait.py +271 -0
- gato_mpc-0.1.1/python/gato/hypotheses.py +183 -0
- gato_mpc-0.1.1/python/gato/interface.py +1145 -0
- gato_mpc-0.1.1/python/gato/linsys_autotune.py +170 -0
- gato_mpc-0.1.1/python/gato/mpc_gato.py +673 -0
- gato_mpc-0.1.1/python/gato/paths.py +69 -0
- gato_mpc-0.1.1/python/gato/policy.py +84 -0
- gato_mpc-0.1.1/python/gato/rowkinds.py +31 -0
- gato_mpc-0.1.1/python/gato/worlds.py +293 -0
- gato_mpc-0.1.1/python/gato_mpc.egg-info/PKG-INFO +529 -0
- gato_mpc-0.1.1/python/gato_mpc.egg-info/SOURCES.txt +167 -0
- gato_mpc-0.1.1/python/gato_mpc.egg-info/dependency_links.txt +1 -0
- gato_mpc-0.1.1/python/gato_mpc.egg-info/requires.txt +41 -0
- gato_mpc-0.1.1/python/gato_mpc.egg-info/top_level.txt +1 -0
- gato_mpc-0.1.1/setup.cfg +4 -0
- gato_mpc-0.1.1/setup.py +10 -0
- gato_mpc-0.1.1/test/conftest.py +238 -0
- gato_mpc-0.1.1/test/cuda/bdsv_factor_solve.cu +364 -0
- gato_mpc-0.1.1/test/cuda/bdsv_vs_pcg.cu +312 -0
- gato_mpc-0.1.1/test/cuda/ee_rows.cu +184 -0
- gato_mpc-0.1.1/test/cuda/gamma_parity.cu +155 -0
- gato_mpc-0.1.1/test/cuda/pcg_vs_cpu.cu +182 -0
- gato_mpc-0.1.1/test/cuda/plant_shim.cuh +16 -0
- gato_mpc-0.1.1/test/dynamics_fingerprint.json +1845 -0
- gato_mpc-0.1.1/test/expected_skips.txt +6 -0
- gato_mpc-0.1.1/test/expected_tests.txt +397 -0
- gato_mpc-0.1.1/test/gpu-proof-policy.yaml +29 -0
- gato_mpc-0.1.1/test/oracles/__init__.py +0 -0
- gato_mpc-0.1.1/test/oracles/mechanisms.py +445 -0
- gato_mpc-0.1.1/test/receipt_modules.txt +31 -0
- gato_mpc-0.1.1/test/test_anchor.py +201 -0
- gato_mpc-0.1.1/test/test_api_smoke.py +185 -0
- gato_mpc-0.1.1/test/test_arrays.py +117 -0
- gato_mpc-0.1.1/test/test_bindings_shapes.py +103 -0
- gato_mpc-0.1.1/test/test_build.py +51 -0
- gato_mpc-0.1.1/test/test_codegen.py +81 -0
- gato_mpc-0.1.1/test/test_common.py +68 -0
- gato_mpc-0.1.1/test/test_contact_rows.py +245 -0
- gato_mpc-0.1.1/test/test_controller.py +271 -0
- gato_mpc-0.1.1/test/test_cpp_interface.py +60 -0
- gato_mpc-0.1.1/test/test_distribution_artifacts.py +80 -0
- gato_mpc-0.1.1/test/test_dynamics_fingerprint.py +50 -0
- gato_mpc-0.1.1/test/test_exact_hessian.py +193 -0
- gato_mpc-0.1.1/test/test_examples.py +91 -0
- gato_mpc-0.1.1/test/test_f_ext.py +600 -0
- gato_mpc-0.1.1/test/test_fig7_validation.py +94 -0
- gato_mpc-0.1.1/test/test_floating_go2.py +502 -0
- gato_mpc-0.1.1/test/test_floating_rowgroups.py +285 -0
- gato_mpc-0.1.1/test/test_floating_worlds.py +559 -0
- gato_mpc-0.1.1/test/test_gait.py +94 -0
- gato_mpc-0.1.1/test/test_kernel_gates.py +48 -0
- gato_mpc-0.1.1/test/test_limits_closed_loop.py +56 -0
- gato_mpc-0.1.1/test/test_linsys_autotune.py +108 -0
- gato_mpc-0.1.1/test/test_manifold.py +101 -0
- gato_mpc-0.1.1/test/test_mechanism_oracles.py +520 -0
- gato_mpc-0.1.1/test/test_mpc_initialization.py +78 -0
- gato_mpc-0.1.1/test/test_packaging.py +101 -0
- gato_mpc-0.1.1/test/test_parity_golden.py +160 -0
- gato_mpc-0.1.1/test/test_policy.py +47 -0
- gato_mpc-0.1.1/test/test_receipt_contract.py +76 -0
- gato_mpc-0.1.1/test/test_register_robot.py +110 -0
- gato_mpc-0.1.1/test/test_row_masks.py +220 -0
- gato_mpc-0.1.1/test/test_rowgroups.py +844 -0
- gato_mpc-0.1.1/test/test_smoke_solve.py +96 -0
- gato_mpc-0.1.1/test/test_worlds.py +225 -0
- gato_mpc-0.1.1/tools/autotune_linsys.py +124 -0
- gato_mpc-0.1.1/tools/build.sh +65 -0
- gato_mpc-0.1.1/tools/check_installed_package.py +93 -0
- gato_mpc-0.1.1/tools/common.sh +14 -0
- gato_mpc-0.1.1/tools/docker.sh +65 -0
- gato_mpc-0.1.1/tools/gen_dynamics_fingerprint.py +142 -0
- gato_mpc-0.1.1/tools/install.sh +109 -0
- gato_mpc-0.1.1/tools/native_identity.py +88 -0
- gato_mpc-0.1.1/tools/parity_baseline.py +111 -0
- gato_mpc-0.1.1/tools/regen_grid.py +65 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Installs are source-tree only (no tag, no PyPI release); the version is `gato.__version__`.
|
|
4
|
+
|
|
5
|
+
## 0.1.1 — 2026-10-13: the pip-install path
|
|
6
|
+
|
|
7
|
+
- Published on PyPI as `gato-mpc` (the name `gato` belongs to an unrelated
|
|
8
|
+
package); the import name stays `gato`.
|
|
9
|
+
|
|
10
|
+
- `gato.register_robot(name, urdf, N=[...])` generates a robot's dynamics headers
|
|
11
|
+
into a per-host cache (`GATO_CACHE_DIR` or the platform user cache, e.g.
|
|
12
|
+
`~/.cache/gato`); the first `gato.BSQP(..., plant_type=name)` for a horizon
|
|
13
|
+
compiles that module once — with a logged warning naming the one-time cost —
|
|
14
|
+
and every later process loads it from the cache. Module keys cover the URDF
|
|
15
|
+
bytes and options, the grid-rbd provenance, GATO's native sources, the GPU
|
|
16
|
+
architecture and the toolchain, so nothing stale is ever loaded. The three
|
|
17
|
+
vendored robots (Indy7, iiwa14, Go2) are pre-registered: any horizon compiles
|
|
18
|
+
from the bundled headers without a `register_robot` call.
|
|
19
|
+
- Wheels ship GATO's native sources (`gato/_native`: CMakeLists, headers, the
|
|
20
|
+
bindings TU, the vendored robot headers and URDFs) and never compiled modules;
|
|
21
|
+
`pip install` needs no checkout and no submodule. `gato.robot_urdf(name)` is
|
|
22
|
+
the URDF path that works in both a checkout and a wheel; the bundled
|
|
23
|
+
descriptions include the collision meshes, so a copy of a vendored URDF can
|
|
24
|
+
be registered as a new robot (visual-only meshes are left out).
|
|
25
|
+
- `solve()` and `MPCController.step()` accept numpy, torch or JAX arrays and
|
|
26
|
+
return the same kind. CUDA tensors take a device-pointer path (inputs read in
|
|
27
|
+
place, `xu` returned on the device through DLPack, no host round trip) that is
|
|
28
|
+
bit-identical to the host path, cold and warm-started; CPU tensors go through
|
|
29
|
+
the host path. `MPC_GATO` and the controller keep their host warm-start buffers.
|
|
30
|
+
- `[test]` extra now lists torch and jax (CPU builds suffice for the host tier).
|
|
31
|
+
- C++/CUDA tier documented as a first-class interface: `python -m gato.paths`
|
|
32
|
+
prints the include directories, defines and flags for any (robot, horizon,
|
|
33
|
+
variant) — vendored, cached or registered; `examples/cpp/` holds a real
|
|
34
|
+
batched-solve template on `BSQP<T>` with a standalone CMake that works from
|
|
35
|
+
a wheel (the headers and the example ship in it). The old `examples/bsqp.cu`
|
|
36
|
+
demo is replaced; the in-tree `build/bsqp` target builds the new source.
|
|
37
|
+
|
|
38
|
+
## 0.1.0 — 2026-10-13: wheel-based dependency, closed-loop limits gate, declared API surface
|
|
39
|
+
|
|
40
|
+
Everything below this heading down to the 2026-10-05 entry ships in 0.1.0; the
|
|
41
|
+
earlier entries were the unreleased 0.0.2 line.
|
|
42
|
+
|
|
43
|
+
- Closed-loop joint-limit enforcement: `examples/09_mpc_with_limits.py` and
|
|
44
|
+
`test/test_limits_closed_loop.py` grade the SIMULATED plant, not the planner:
|
|
45
|
+
with the ADMM box mechanism and a ±1 rad/s velocity box the Indy7 figure-8
|
|
46
|
+
peaks at 1.03–1.04 rad/s (1.6–2.0 unenforced) at N ≥ 32; horizons of 16 or
|
|
47
|
+
fewer knots cannot brake in time (measured, `docs/constraints.md`).
|
|
48
|
+
`MPC_GATO` loops now record the winning plan's `row_max_violation`.
|
|
49
|
+
- `MPCController.step()` contract (fixed iteration budget, no deadline-aware
|
|
50
|
+
exit, caller owns the schedule) and a stable/experimental API list:
|
|
51
|
+
`docs/consumer_contract.md` §4 and §8.
|
|
52
|
+
- Version 0.1.0 (was 0.0.2): the install contract changed (below), so this is a
|
|
53
|
+
minor bump under the pre-1.0 convention. Development status stays Alpha.
|
|
54
|
+
|
|
55
|
+
### GRiD and GLASS from the released `grid-rbd` wheel
|
|
56
|
+
|
|
57
|
+
- GATO no longer carries `external/GRiD` and `external/GLASS` submodules. The code
|
|
58
|
+
generator, URDFParser, the global `glass::` headers and GRiD's collision headers
|
|
59
|
+
all come from `grid-rbd==0.5.1` (PyPI); `python/gato/_grid.py` pins that version
|
|
60
|
+
and the GLASS commit it must bundle (`9e57178`, unchanged), and refuses any other
|
|
61
|
+
install at codegen, CMake configure and test time. The Go2 URDF the Go2 headers
|
|
62
|
+
are generated from is vendored at `examples/go2_description/` (the wheel ships
|
|
63
|
+
no robot assets). A fresh clone needs no submodule to build.
|
|
64
|
+
- Robot headers regenerated with the 0.5.1 generator: it adds per-kernel
|
|
65
|
+
`init_grid_kernel_attr_*_checked` registration helpers and makes the
|
|
66
|
+
collision-check hit flag an atomic exchange; dynamics, costs and sphere sets
|
|
67
|
+
are unchanged and the numerical goldens still pass.
|
|
68
|
+
- Receipts: the fingerprint drops the two gitlinks and covers the pin instead;
|
|
69
|
+
native modules embed a content identity of the wheel's headers keyed by logical
|
|
70
|
+
name (independent of the install location). pytest-gpu-proof 0.4.1.
|
|
71
|
+
|
|
72
|
+
## 2026-10-05 — Dependency integration
|
|
73
|
+
|
|
74
|
+
- Pin GRiD 8dccbfa and GLASS 9e57178 and regenerate all three robot headers.
|
|
75
|
+
This includes upstream dynamics synchronization changes and collision APIs;
|
|
76
|
+
collision sphere counts and controller defaults remain unchanged.
|
|
77
|
+
- Codegen validation now requires matching GRiD and consumer GLASS pins.
|
|
78
|
+
Collision generation rejects spherizer fallbacks independently of warning
|
|
79
|
+
wording, preserving the same geometry when optional dependencies are missing.
|
|
80
|
+
October 5 timing artifacts describe the preceding dependency revisions;
|
|
81
|
+
no performance improvement is inferred from this update.
|
|
82
|
+
|
|
83
|
+
## 2026-10-04 — Audit evidence and reproducibility
|
|
84
|
+
|
|
85
|
+
- Signed GPU receipts now require the full test inventory, wider source coverage
|
|
86
|
+
and content identities matching all receipt-profile native modules. Missing
|
|
87
|
+
receipts and partial test selections fail closed; numerical goldens are unchanged.
|
|
88
|
+
- A frozen Fig-7 holdout records arm-arrival outcomes separately from applied
|
|
89
|
+
effort, velocity and position limits, including a torque-clamped stop arm.
|
|
90
|
+
See the [figure refresh](docs/figure-refresh-2026-10-01.md) for interpretation.
|
|
91
|
+
- The optional CPU comparison baseline builds in its own pinned Pinocchio 3.8
|
|
92
|
+
environment, with a two-arm numerical check and the matching Python launcher.
|
|
93
|
+
- An opt-in quiet-window lane pairs controller-call wall time with internal
|
|
94
|
+
solver time. Documentation distinguishes simulated task quality, feasibility
|
|
95
|
+
and timing boundaries; no new performance claim follows from correctness runs.
|
|
96
|
+
|
|
97
|
+
## 2026-10-03 — Fig-7 refresh: two task settings, identified-weight hypothesis batch
|
|
98
|
+
|
|
99
|
+
- `reproduce_fig7_pickplace.py --task {stop,pass-through}` presets. `stop` (default): the EE
|
|
100
|
+
reference ramps to each goal over 1.5 s (minimum jerk) and the success gates must hold 100 ms,
|
|
101
|
+
with the paper's exploration sampler — 15/100/99/98 % at B = 1/8/32/128 on 100 corrected
|
|
102
|
+
scenarios. `pass-through`: the paper's protocol verbatim with the identified-weight sampler —
|
|
103
|
+
26/83/97/95 % (the paper's sampler: 6/62/84/82 %). `--success-plot` renders both panels.
|
|
104
|
+
- `gato.estimators.IdentifiedWrenchSampler` and `MPC_GATO(estimator="wid")`: the hypothesis
|
|
105
|
+
batch is the least-squares identified payload weight, a zero row and bounded Fibonacci-sphere
|
|
106
|
+
perturbations with an adaptive radius (`inertial_rows=True` adds the full identified wrench
|
|
107
|
+
and its blends — off by default: they fling the arm). The API default stays `estimator="fe"`.
|
|
108
|
+
- `MPC_GATO.run_mpc_goals(settle_time=, goal_ramp=)`: optional dwell on the success gates and a
|
|
109
|
+
minimum-jerk EE reference between goals (both 0 by default = the paper's loop); exposed on
|
|
110
|
+
`reproduce_fig7_pickplace.py` as `--settle-time`, `--goal-ramp`, `--qd-cost`, `--estimator`.
|
|
111
|
+
- Fig-3 Indy7 lane re-run in an exclusive window (October 3); Fig-7 findings and the reasons
|
|
112
|
+
the gate stays instantaneous are in `docs/figure-refresh-2026-10-01.md`.
|
|
113
|
+
|
|
114
|
+
## 2026-10-02 — Fig-3 harness: `--robot indy7` + fig8 driver stop-condition fix
|
|
115
|
+
|
|
116
|
+
- `MPC_GATO.run_mpc_fig8` stopped `6N` goal steps early instead of `N`: a goal of exactly
|
|
117
|
+
sim-steps + N knots produced 148 control steps at N = 32 and none at N ≥ 64. The long
|
|
118
|
+
MPCGPU goal file (1202 steps) hid it on the iiwa14 lane; the wipe task padded around it.
|
|
119
|
+
Fixed (`eepos_offset + N > steps`), regression test `test_mpc_gato_run_mpc_fig8_uses_whole_goal`.
|
|
120
|
+
No committed number changes: every existing caller's goal is far longer than its sim time.
|
|
121
|
+
- The FAIR fig8 harness is robot-parameterized: `iiwa_fig8_shared.robot(name)` carries URDF,
|
|
122
|
+
registry EE frame, q0 and whether MPCGPU's goal file applies; `sweep_batch_iiwa_fig8.py`,
|
|
123
|
+
`track_iiwa_fig8_gato.py`, `baselines/track_iiwa_fig8_bt.py` and `reproduce_fig3_fair.py`
|
|
124
|
+
take `--robot {iiwa14,indy7}`. iiwa14 outputs are unchanged (same goal hashes as every
|
|
125
|
+
recorded run); Indy7 uses the same fig8 at `INDY7_START_CONFIGS["ready"]`, a synthesized
|
|
126
|
+
goal (MPCGPU has no Indy7 trajfile) and `_indy7`-suffixed CSV/figure names. Indy7 numbers
|
|
127
|
+
are recorded in `docs/figure-refresh-2026-10-01.md` once measured in a quiet window.
|
|
128
|
+
|
|
129
|
+
## 2026-10-01 — Release-hygiene batch (no numeric change: all 42 goldens bit-identical)
|
|
130
|
+
|
|
131
|
+
- Cooperative row kinds are described once. `gato/bsqp/rowgroups.cuh` lost the per-kind
|
|
132
|
+
EE_POS / COLLISION / CONTACT_POS sections (scratch sizers, `has_*_rows`, `*_eval*`, six
|
|
133
|
+
fold/value wrappers, the three telemetry branches and the collision-only AL dual branch):
|
|
134
|
+
the `CooperativeRows<T, KIND>` trait now owns the FK call, the scratch carve and its sizes,
|
|
135
|
+
the Jacobian layout, the bound slot and the state index, and `dispatch_cooperative_kind`
|
|
136
|
+
routes the telemetry, AL dual-update and ADMM kernels to it. setup_kkt / merit call
|
|
137
|
+
`cooperative_row_grad_hess<KIND>` / `cooperative_row_cost_value<KIND>` directly
|
|
138
|
+
(`__noinline__` kept: the cicc expansion cliff). −180 lines across rowgroups.cuh, admm.cuh,
|
|
139
|
+
setup_kkt.cuh, merit.cuh (the handoff's −250 estimate predated the 09-26 trait landing). Gated bitwise FIRST: four new arm `collision_{al,admm}` goldens
|
|
140
|
+
(indy7 / iiwa14 N16, sphere parked on the reach goal so the rows bind) join the existing
|
|
141
|
+
masked-CONTACT_POS and ADMM/EE cases — 38 → 42 goldens, all unchanged by the refactor.
|
|
142
|
+
- `python/bindings.cu` 720 → 632 lines: one `DenseArray` alias, `checked_ptr` /
|
|
143
|
+
`optional_ptr` for the per-solve and per-joint setters, one `state_dict` behind the four
|
|
144
|
+
dual/ADMM getters, `per_iter_array` for the (iters, B) stats. Same Python surface; the
|
|
145
|
+
per-joint vector size errors now print the expected count instead of the constant's name.
|
|
146
|
+
- Scratch sizers follow the tree's snake_case `*_smem_ct` convention:
|
|
147
|
+
`stepValueFloating_TempMemCt` → `step_value_floating_smem_ct`, `stepGradFloating_TempMemCt`
|
|
148
|
+
→ `step_grad_floating_smem_ct`, `simStep_TempMemCt` → `sim_step_smem_ct`,
|
|
149
|
+
`linearizedDynamics_TempMemCt` → `linearized_dynamics_smem_ct`, `integratorError_TempMemCt`
|
|
150
|
+
→ `integrator_error_smem_ct` (integrator.cuh / grid_plant_step.cuh and their kernel callers).
|
|
151
|
+
- Retired `examples/archive/` (the June indy7 fig3 chain, the pinocchio-sim baseline, the
|
|
152
|
+
bdsv timing session; nothing imported it — recover from git history). The bundled Fig-4
|
|
153
|
+
data moved next to its only consumer: `examples/paper-figures/gato_hparam_batch_results.pkl`
|
|
154
|
+
(`reproduce_fig4_hparam.py --replot`).
|
|
155
|
+
- New `docs/development.md`: install, capped builds, test tiers and goldens, the signed
|
|
156
|
+
receipt and its local verify command, the quiet-window timing rule. Linked from
|
|
157
|
+
`docs/README.md` and the README Tests section.
|
|
158
|
+
|
|
159
|
+
## 2026-10-01 — Main integration candidate and figure refresh
|
|
160
|
+
|
|
161
|
+
- Pinned GRiD `main` (0a14c0f); all vendored headers regenerate byte-identically. Merged the
|
|
162
|
+
remote README citation and funding edits. Quick start, package URL and the GRiD submodule
|
|
163
|
+
branch now point at `main`.
|
|
164
|
+
- Seed A/B timing: the benchmark's seed change explains nearly all of the September gap;
|
|
165
|
+
about 3% (B8) and 4% (B128) remain unattributed (docs/figure-refresh-2026-10-01.md).
|
|
166
|
+
- Fixed Fig-4, which plotted nothing: best-merit curves are now padded past early SQP stops
|
|
167
|
+
instead of truncated to the shortest. Refreshed Fig-3, Fig-4 and Fig-5 with the current code;
|
|
168
|
+
Fig-3's MPCGPU lane now imports MPCGPU's own timing-harness output. Results and limits:
|
|
169
|
+
`docs/figure-refresh-2026-10-01.md`. Fig-7 / Table I stay as published.
|
|
170
|
+
- Timing launchers no longer need ripgrep.
|
|
171
|
+
- Fixed a solver bug: the merit's terminal-knot cost read the unwritten control slot with
|
|
172
|
+
zero weight, so NaN or Inf left in shared memory by an earlier kernel (for example a
|
|
173
|
+
diverging tiny-rho solve) made 0 * NaN = NaN. That solve's initial merit became NaN and its
|
|
174
|
+
line search never accepted a step, nondeterministically and only after such a kernel. The
|
|
175
|
+
slot is now zeroed; all 38 goldens are bit-identical and a regression test replays the
|
|
176
|
+
triggering sequence. Found because Fig-4 batches up to 128 with rho down to 1e-8.
|
|
177
|
+
|
|
178
|
+
## 2026-09-27 — Checkpoint follow-up fixes (no new timing claims)
|
|
179
|
+
|
|
180
|
+
- Fixed floating effort-vector uploads/checks to use actuator width, not stored
|
|
181
|
+
configuration width; default/fc KKT gates cover the contract and scalar reset.
|
|
182
|
+
- Fixed spherical-payload initialization: axis-angle is integrated on the
|
|
183
|
+
manifold into a unit quaternion, and augmented robot q/v offsets are separate.
|
|
184
|
+
Both simulation task loops share this assembly. New pick-place data is marked
|
|
185
|
+
`unit-quaternion-pendulum-v2`; historical pools remain preserved, not relabeled
|
|
186
|
+
as corrected results. Added fixed-pacing traces and per-goal event diagnostics.
|
|
187
|
+
- Added explicit controller reset seeds and restored the batch benchmark's
|
|
188
|
+
historical zero-tail initial guess. Hold remains an explicit comparison mode;
|
|
189
|
+
correctness-only raw/controller parity and frozen reference provenance guard
|
|
190
|
+
future comparisons. Added a guarded seed A/B timing suite; execution deferred.
|
|
191
|
+
- Recorded the overnight checkpoint and its limitations; reconciled preferred
|
|
192
|
+
citation metadata with the README's ICRA entry. No production tuning changes.
|
|
193
|
+
- Fresh lean-install validation exposed a missing SciPy codegen dependency:
|
|
194
|
+
trimesh fell back to a different collision sphere cover. SciPy is now a base
|
|
195
|
+
build dependency, fallback geometry is rejected, and old codegen cache keys
|
|
196
|
+
are invalidated. No upstream sources or vendored headers were changed.
|
|
197
|
+
|
|
198
|
+
## 2026-09-27 — Merge-readiness documentation and example validation
|
|
199
|
+
|
|
200
|
+
- Added a documentation index, feature-status boundaries, API migration notes
|
|
201
|
+
and a bounded merge checklist. Corrected standing, ADMM dispatch, receipt
|
|
202
|
+
coverage and paper-protocol claims; restored main's citation/acknowledgement
|
|
203
|
+
in the README. Quick start builds one module with capped concurrency.
|
|
204
|
+
- Fixed the gym example's indentation error and added introductory syntax
|
|
205
|
+
gates. The basic MPC example now uses fixed simulation pacing. Added a short
|
|
206
|
+
masked-contact AL/barrier/ADMM gate suitable for race instrumentation.
|
|
207
|
+
- Added a GATO-only, opt-in quiet-window checkpoint runner with a GPU-free
|
|
208
|
+
dry run, unique result paths and source/binary/environment provenance. It
|
|
209
|
+
samples Fig-3 and Fig-7, not a full research reproduction or autotune run.
|
|
210
|
+
- Corrected the distribution contract: Git checkout plus pinned submodules
|
|
211
|
+
is the supported native build; the sdist does not bundle external trees.
|
|
212
|
+
Excluded local working notes from sdists and added a packaging canary gate.
|
|
213
|
+
|
|
214
|
+
## 2026-09-26 — GRiD integration and cooperative-row cleanup
|
|
215
|
+
|
|
216
|
+
- GRiD pinned to `65fd051`: public HTTPS nested dependencies, declared trimesh
|
|
217
|
+
dependency, and updated integrator/plant surfaces. Regenerated all three robot
|
|
218
|
+
headers. GATO's floating adapter continues to select Euler/semi-implicit Euler
|
|
219
|
+
by enum name; its integration scheme is unchanged.
|
|
220
|
+
- Added masked floating CONTACT_POS goldens for AL and ADMM before consolidating
|
|
221
|
+
the cooperative EE, collision and contact fold/merit/ADMM implementations.
|
|
222
|
+
Traits retain each evaluator's scratch layout, Jacobian layout, bounds, masks
|
|
223
|
+
and dual-state indexing. Existing noinline boundaries are preserved.
|
|
224
|
+
- Consolidated binding input uploads and row-state downloads, named owned
|
|
225
|
+
scratch counts consistently, and shared the plant's linalg arena padding.
|
|
226
|
+
- Corrected notebook package shadowing, documented contact-wipe reproduction and
|
|
227
|
+
the local-only stale data archives, and added package project URLs. Stance
|
|
228
|
+
documentation now distinguishes moving prediction targets from measured slip.
|
|
229
|
+
|
|
230
|
+
## 2026-09-26 — Closed-loop foot rows: non-PD regularization bump, re-anchored stance targets; release hygiene
|
|
231
|
+
|
|
232
|
+
- Solver: a non-PD direct factor (`stats.pcg_iters == 2`, the f32 Cholesky of the Schur
|
|
233
|
+
system failing once stiff row groups are folded into Q) now multiplies the trust-region
|
|
234
|
+
rho by `NON_PD_RHO_FACTOR` (settings.h, 100: 1e-3 -> 0.1 in one step) independent of the
|
|
235
|
+
AL mode's frozen adaptation. Measured on the go2 stance rows at AL rho 1e3: every
|
|
236
|
+
iteration non-PD before, none after the first iteration of a solve now. The two
|
|
237
|
+
exact-Hessian goldens moved (each hits one non-PD factor mid-solve) and end at a lower
|
|
238
|
+
merit; re-baselined.
|
|
239
|
+
- `GaitProgrammer`: stance targets are RE-ANCHORED to the measured feet every tick (the
|
|
240
|
+
no-slip contact semantics) instead of frozen at touchdown; the static stand with stance
|
|
241
|
+
rows now holds height within 2 mm at 2-5 mm residual (gate:
|
|
242
|
+
`test_fc_mpc_stands_with_foot_rows`). The swing itself remains open: lifting a foot without
|
|
243
|
+
a support-polygon base plan tips the model (docs/constraints.md, closed-loop section).
|
|
244
|
+
- Bug fix: masked-off COLLISION knots no longer fold gradient/Hessian/merit (the row-mask
|
|
245
|
+
contract already promised it; the fold and value sites lacked the gate).
|
|
246
|
+
- `test_build` compiles in its own CMake tree (it used to reconfigure the shared `build/`
|
|
247
|
+
to the test plant).
|
|
248
|
+
- Release hygiene: `gato.rowkinds` (the row-kind / mechanism ids, shared by the API, the KKT
|
|
249
|
+
certificate — now covering LIN_U / COLLISION / CONTACT_POS — and the tests);
|
|
250
|
+
`gato.fingerprint` / `gato.worlds` / `gato.gait` reachable as attributes; the seven
|
|
251
|
+
constraint docstrings that duplicated docs/constraints.md now summarize and point there;
|
|
252
|
+
`add_contact_pos_rows` defaults to knots 1..N-1; batch accessors, the four limit enables,
|
|
253
|
+
the mechanism/rho boilerplate and six copies of the test reach problem deduplicated;
|
|
254
|
+
dangling references to internal notes removed from tracked code and docs; dead
|
|
255
|
+
`tools/clean.sh` and unused helpers deleted (`test/expected_skips.txt` stays: it is the CI
|
|
256
|
+
verifier's empty allow-list of skips, i.e. the zero-skip gate); README/docs corrected
|
|
257
|
+
(import forms, submodule story, Fig-3 reproduction, contact-frame order, telemetry
|
|
258
|
+
semantics); `docs/baselines.md` (orphaned, self-contradictory) removed and
|
|
259
|
+
`docs/archaeology.md` trimmed to the provenance table; sdist now ships docs/ and the
|
|
260
|
+
changelog; packaging metadata (authors, license, classifiers) completed.
|
|
261
|
+
|
|
262
|
+
## 2026-09-26 — CL-4: contact-frame POSITION rows (stance/swing feet), solver-level gates
|
|
263
|
+
|
|
264
|
+
- Row kind `CONTACT_POS` (`BSQP.add_contact_pos_rows`, `set_row_group_targets`,
|
|
265
|
+
`contact_positions`): per-knot residual rows `p_f(q_k) - tgt_k` on the baked contact
|
|
266
|
+
frames over GRiD's new `contact_frame_positions[_gradient]` surface, folded at every
|
|
267
|
+
active knot (AL / relaxed barrier / ADMM / telemetry), with a per-knot target table on
|
|
268
|
+
the row-group descriptor and the CL-4 masks selecting (knot, foot) rows. The dedicated
|
|
269
|
+
cooperative carve of setup_kkt / merit is shared with the collision rows (sized when
|
|
270
|
+
either kind is registered; defaults untouched — goldens bitwise).
|
|
271
|
+
- `GaitProgrammer.install_foot_rows`: a stance group (footholds frozen at touchdown, at
|
|
272
|
+
ground height) and a swing group (swing-curve tracking to the planned landing);
|
|
273
|
+
`apply(t, q)` retargets and re-masks both every tick beside the fc pins and the fn
|
|
274
|
+
reference. Default AL rho 100 (loop-stable; see below).
|
|
275
|
+
- Gates (test_contact_rows.py): device residual == pinocchio, per-knot target table,
|
|
276
|
+
AL/ADMM move an arm EE to a violated target within 3 mm on the active knots only,
|
|
277
|
+
masks select knots, go2 keeps its feet < 1 mm under a lateral goal, solver-only S3
|
|
278
|
+
(FR lifts ~3 cm at knot 12 with the stance feet held), programmer plumbing.
|
|
279
|
+
- OPEN (measured, docs/constraints.md, closed-loop section): the closed loop. The stiffness that holds feet within
|
|
280
|
+
mm (AL rho 1e3) makes the loop's SQP reject every line-search step on 26/150 ticks of a
|
|
281
|
+
static stand (base sags 4 cm); every ADMM variant collapses; AL rho 100 stands with a
|
|
282
|
+
1.8 cm residual. S2 weight shift / S3 lift-a-foot closed-loop gates are not shipped.
|
|
283
|
+
- `pyproject`: mujoco pinned `<3.14` (3.14.0 segfaults inside MjSpec compile of the go2
|
|
284
|
+
URDF with the welded root; CI cpu-lane at 2b03a38, reproduced locally 6/6).
|
|
285
|
+
|
|
286
|
+
## 2026-09-26 — GRiD pin 3af782e → 5904dbd (contact-frame positions), GLASS e83b086 → 8ce68a2
|
|
287
|
+
|
|
288
|
+
- GRiD `modernizing-tests` tip: the contact-frame position surface GATO asked for on
|
|
289
|
+
2026-09-20 (`grid_plant::contact_frame_positions[_gradient]`, world positions of the
|
|
290
|
+
baked contact origins + tangent Jacobians, receipt-covered upstream @8aac88e) and the raw
|
|
291
|
+
`grid_plant::multi_target_position[_gradient]` evaluators (GATO nit 2). The three plants
|
|
292
|
+
are regenerated (`tools/regen_grid.py`); `gato.build` idempotency key recorded for go2.
|
|
293
|
+
GLASS moved by docs/figures only (headers byte-identical).
|
|
294
|
+
- iiwa14 goldens RE-BASELINED: URDFParser 29d3d78 no longer rationalizes transform
|
|
295
|
+
coefficients, so iiwa14's emitted transforms carry ±1.6e-15 terms the old parser snapped
|
|
296
|
+
to 0 (indy7/go2: bit-identical). The golden problems are unconverged 10-iteration solves
|
|
297
|
+
that amplify any ULP change to O(1) (a 1e-7 input nudge moves xu by ~1%), so the drift was
|
|
298
|
+
attributed with the referee gates (dynamics fingerprint, f_ext, exact Hessian, row groups
|
|
299
|
+
vs the pinocchio-pinned tables: 54 passed) and a clean compute-sanitizer memcheck of
|
|
300
|
+
iiwa14 N8 + both go2 modules. Sensitivity note in test_parity_golden.py.
|
|
301
|
+
|
|
302
|
+
## 2026-09-21 — D14: the Fig-3 CPU baseline pin is public
|
|
303
|
+
|
|
304
|
+
- `examples/benchmarks/baselines/sqpcpu` now points at `A2R-Lab/sqpcpu` (the public
|
|
305
|
+
fork of the upstream sqpcpu), branch `fig3-fair-sigma` = upstream master + the two
|
|
306
|
+
fair-comparison commits GATO pins. The `update = none` opt-in gating is gone: a plain
|
|
307
|
+
recursive clone and `tools/install.sh` fetch it like every other submodule.
|
|
308
|
+
|
|
309
|
+
## 2026-09-20 — CL-4 groundwork: gait oracle, per-knot row masks, per-knot fc reference
|
|
310
|
+
|
|
311
|
+
- `gato.gait.GaitSchedule`: the fixed-gait ORACLE (trot/bound/pace/walk/stand; period,
|
|
312
|
+
duty, phase offsets) → rolling per-knot stance masks, fc pin masks, per-knot fn
|
|
313
|
+
references, Raibert-lite footholds, swing curves, base references. Pure numpy.
|
|
314
|
+
- Row groups carry a per-knot row-activity mask (`BSQP.set_row_group_mask(g, mask)`,
|
|
315
|
+
`get_row_groups()[g]["active"]`): an inactive (knot, row) is treated like a knot
|
|
316
|
+
below the group's window (ADMM keeps its proximal fold, everything else contributes
|
|
317
|
+
nothing) and its AL dual is reset. All-True is bitwise the previous behaviour.
|
|
318
|
+
- `set_fc_ref` accepts an (N, n_fc) per-knot table (a 1-D wrench still broadcasts,
|
|
319
|
+
bitwise); the device buffer is per knot.
|
|
320
|
+
|
|
321
|
+
## 2026-09-20 — Wave F: contact forces on the floating base (go2 fc-on-feet)
|
|
322
|
+
|
|
323
|
+
- `bsqpN16_go2_fc`: the fc variant now builds on the floating base (was a
|
|
324
|
+
`static_assert`). The fc tail (one world-aligned `[n; f]` wrench per baked foot
|
|
325
|
+
frame, `FC_SIZE = 24`) enters the grid step as the mapped per-body wrench; the
|
|
326
|
+
linearization gains the fc columns of B and the dfext/dq chain term, composed from
|
|
327
|
+
the grid step's full-force B block; the floating cost composition carries the fc
|
|
328
|
+
regularization/reference terms. Gated against pinocchio central FD at 25 N
|
|
329
|
+
wrenches, bitwise the default module at fc = 0. `go2 16 fc` joins the receipt
|
|
330
|
+
profile (+2 goldens).
|
|
331
|
+
- API: `BSQP.contact_frames`, `BSQP.fc_slots(frame, part)`, module attr
|
|
332
|
+
`NUM_CONTACT_FRAMES`, `MuJoCoWorld.last_contact["fn_by_body"]`.
|
|
333
|
+
- Fixed: `debug_contact_dynamics` returned silently wrong numbers on floating
|
|
334
|
+
modules (fixed-base composition) — it now raises there. Kernel launches past the
|
|
335
|
+
48 KB dynamic-smem default are opted in at every launch site via one helper
|
|
336
|
+
(the Schur assembly kernel had no opt-in: 64 KB on go2-fc failed to launch);
|
|
337
|
+
the setup_kkt/merit collision sizers under-allocated the dedicated carve by the
|
|
338
|
+
temp tail (latent — every generated robot's carve fit the tail). setup_kkt's
|
|
339
|
+
terminal cost blocks overlay the dead dynamics scratch (offsets only, −10 KB:
|
|
340
|
+
the device opt-in maximum is ~99 KB, go2 default sat at 94 KB).
|
|
341
|
+
- Fixed (found by memcheck once that slack was gone): the fixed-base setup_kkt and
|
|
342
|
+
merit kernels sized their dynamics scratch from the plant adapter's arena alone,
|
|
343
|
+
omitting the integrator layer's own qdd|dqdd / qdd|err prefix (114 floats on
|
|
344
|
+
indy7 N8) — the ID-gradient inner wrote past the launch by up to that much, hidden
|
|
345
|
+
for months by the prepended terminal chain. `linearizedDynamics_TempMemCt` /
|
|
346
|
+
`integratorError_TempMemCt` / `simStep_TempMemCt` (integrator.cuh) are now the
|
|
347
|
+
sizers. Results are bitwise unchanged (goldens).
|
|
348
|
+
|
|
349
|
+
## 2026-09-20 — audit waves 0–2
|
|
350
|
+
|
|
351
|
+
Breaking (clean-break API, no shims):
|
|
352
|
+
- `gato.SolverParams` is the ONE solver configuration; `BSQP(model, B, N, dt, params=...)`
|
|
353
|
+
(field keywords accepted). The constructor's second default set and `kkt_tol` are gone;
|
|
354
|
+
defaults = the paper/MPC values (`max_sqp_iters=1`, `mu=10`, `rho=0.01`, `qd_cost=1e-2`, …).
|
|
355
|
+
- `BSQP.solve(x, ref, xu_warm=None)` is stateless in the trajectory (None = hold-at-x cold
|
|
356
|
+
start; pass `res.xu` to warm-start); caller arrays are never mutated; `SolveResult.xu` is
|
|
357
|
+
a fresh array. `BSQP.XU_B` / `clear_cost_weights_per_knot` removed
|
|
358
|
+
(`set_cost_weights_per_knot(None)` clears).
|
|
359
|
+
- `MPC_GATO(params=..., linsys=..., bdsv_threshold=..., reseed_threshold=..., variant=...)`
|
|
360
|
+
replaces the `solver_params` dict; `StepResult.u` is the ACTUATED control (`StepResult.fc`
|
|
361
|
+
carries wrench slots on fc variants).
|
|
362
|
+
- Module variants have their own names: `bsqpN{N}_{plant}[_fc|_eh].so`, side by side;
|
|
363
|
+
`BSQP(..., variant=)`, `gato.available(variant)`, `gato.build(contact_forces=, exact_hessian=)`,
|
|
364
|
+
`-DMODULES="plant:N[:variant]"`, `./tools/build.sh --variant`. The `.so`-swap workflow is gone.
|
|
365
|
+
- `enable_limit_*` after an appended row group raises (used to drop the group silently).
|
|
366
|
+
- C++: `BSQP` constructor drops `dt`/`kkt_tol`; every hand-written device/host function is
|
|
367
|
+
snake_case; raw bindings constructor has 14 args.
|
|
368
|
+
- `gato.config.{STANDARD_BATCH_SIZES, EXPERIMENT_BATCH_SIZES, BATCH_COLORS}` moved to
|
|
369
|
+
`examples/paper-figures/_common.py`.
|
|
370
|
+
|
|
371
|
+
Fixed:
|
|
372
|
+
- Strided / broadcast / f64 numpy inputs were copied through their strides (garbage reads):
|
|
373
|
+
every binding array parameter is now `c_style|forcecast`.
|
|
374
|
+
- `TrajectoryReference.done()` fired 5N knots early (knot/element unit mix).
|
|
375
|
+
- Max-dynamic-shared-memory attribute was latched at the first request; a later larger carve
|
|
376
|
+
(collision after exact-Hessian) launched over-ceiling. Post-launch checks on every launch.
|
|
377
|
+
- Dead L2 persisting carve-out reservation removed; pinocchio no longer required to construct
|
|
378
|
+
a solver; `gato.build` no longer silently overridden by a cached receipt-profile configure.
|
|
379
|
+
|
|
380
|
+
Infrastructure:
|
|
381
|
+
- pytest-gpu-proof 0.4.0 (schema 3, restricted signer, weekly CI cron); receipt module
|
|
382
|
+
profile `test/receipt_modules.txt` (arms × 6 horizons + go2 N16 + fc/eh arms N16); golden
|
|
383
|
+
bitwise gate (`test/golden/`, 36 cases); kernel harnesses run from pytest; distribution
|
|
384
|
+
contract (pure-python wheel, buildable sdist) gated; HTTPS submodules; one `.venv`.
|
|
385
|
+
- GRiD → 3af782e, GLASS → e83b086; regen emits only the consumed families (headers −21%).
|
|
386
|
+
- CUDA: GLASS banded block movers in the Schur assembly, shared gamma/BDSV/ADMM helpers,
|
|
387
|
+
shared-memory layout structs (sizer == carve), dead solver state removed; all bitwise.
|
|
388
|
+
|
|
389
|
+
## 0.0.2 (2026-06 → 2026-08)
|
|
390
|
+
Modernization: GRiD/GLASS pins, runtime batch size, `gato.build`, pytest + signed receipts,
|
|
391
|
+
constraint row-group layer (boxes, EE rows, cones, collision; barrier/ADMM/AL), exact-Hessian
|
|
392
|
+
SO-SQP, contact-force controls (fc), floating base (go2), hybrid pcg/bdsv + autotune plumbing,
|
|
393
|
+
MuJoCo worlds, wipe contact task, paper figure reproduction.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use GATO, please cite the paper below."
|
|
3
|
+
title: "GATO: GPU-Accelerated and Batched Trajectory Optimization for Scalable Edge Model Predictive Control"
|
|
4
|
+
type: software
|
|
5
|
+
repository-code: "https://github.com/A2R-Lab/GATO"
|
|
6
|
+
license: MIT
|
|
7
|
+
authors:
|
|
8
|
+
- family-names: Du
|
|
9
|
+
given-names: Alexander
|
|
10
|
+
- family-names: Adabag
|
|
11
|
+
given-names: Emre
|
|
12
|
+
- family-names: Bravo
|
|
13
|
+
given-names: Gabriel
|
|
14
|
+
- family-names: Plancher
|
|
15
|
+
given-names: Brian
|
|
16
|
+
preferred-citation:
|
|
17
|
+
type: conference-paper
|
|
18
|
+
title: "GATO: GPU-Accelerated and Batched Trajectory Optimization for Scalable Edge Model Predictive Control"
|
|
19
|
+
authors:
|
|
20
|
+
- family-names: Du
|
|
21
|
+
given-names: Alexander
|
|
22
|
+
- family-names: Adabag
|
|
23
|
+
given-names: Emre
|
|
24
|
+
- family-names: Bravo
|
|
25
|
+
given-names: Gabriel
|
|
26
|
+
- family-names: Plancher
|
|
27
|
+
given-names: Brian
|
|
28
|
+
year: 2026
|
|
29
|
+
month: 6
|
|
30
|
+
collection-title: "IEEE International Conference on Robotics and Automation (ICRA)"
|
|
31
|
+
url: "https://arxiv.org/abs/2510.07625"
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
#
|
|
2
|
+
# cmake -S . -B build [-DPLANT="indy7;iiwa14"] [-DKNOTS="8;16;32;64;128"]
|
|
3
|
+
# cmake --build build --parallel 4
|
|
4
|
+
#
|
|
5
|
+
|
|
6
|
+
cmake_minimum_required(VERSION 3.22)
|
|
7
|
+
project(GATO LANGUAGES CXX CUDA)
|
|
8
|
+
|
|
9
|
+
set(CMAKE_CXX_STANDARD 17)
|
|
10
|
+
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
|
11
|
+
set(CMAKE_CUDA_STANDARD 17)
|
|
12
|
+
set(CMAKE_CUDA_STANDARD_REQUIRED True)
|
|
13
|
+
|
|
14
|
+
if(NOT CMAKE_BUILD_TYPE)
|
|
15
|
+
set(CMAKE_BUILD_TYPE Release)
|
|
16
|
+
endif()
|
|
17
|
+
|
|
18
|
+
option(GATO_FAST_MATH "Compile CUDA with -use_fast_math (disable for tight-tolerance validation)" ON)
|
|
19
|
+
option(GATO_BUILD_DEMO "Build the bsqp C++ demo executable" ON)
|
|
20
|
+
option(GATO_EXACT_HESSIAN "Compile the exact-Hessian (SO-SQP) stage-projection path; OFF keeps the device tree preprocessor-identical to the GN-only solver" OFF)
|
|
21
|
+
option(GATO_CONTACT_FORCES "Append a per-knot contact wrench to the control vector (f_c extends u; a module-ABI change, so it builds as the separate _fc module variant); OFF keeps the baseline solver bit-identical" OFF)
|
|
22
|
+
|
|
23
|
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
|
|
24
|
+
# NOTE: -G is an nvcc flag and lives in the CUDA debug flags only; ASan on a CUDA
|
|
25
|
+
# pybind module is fraught, so host debug flags stay plain.
|
|
26
|
+
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g -fPIC -fno-omit-frame-pointer")
|
|
27
|
+
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -fPIC -DNDEBUG")
|
|
28
|
+
set(CMAKE_CUDA_FLAGS_DEBUG "${CMAKE_CUDA_FLAGS_DEBUG} -G -g")
|
|
29
|
+
set(CMAKE_CUDA_FLAGS_RELEASE "${CMAKE_CUDA_FLAGS_RELEASE} -O3")
|
|
30
|
+
if(GATO_FAST_MATH)
|
|
31
|
+
set(CMAKE_CUDA_FLAGS_RELEASE "${CMAKE_CUDA_FLAGS_RELEASE} -use_fast_math")
|
|
32
|
+
endif()
|
|
33
|
+
|
|
34
|
+
# "native" (CMake 3.24+) detects the local GPU at configure time and compiles
|
|
35
|
+
# only for that architecture. On older CMake (e.g. 3.22 on Ubuntu 22.04), fall
|
|
36
|
+
# back to a broad list of recent arches. Override at configure time with: cmake
|
|
37
|
+
# -DCMAKE_CUDA_ARCHITECTURES="75;86;87;89;100;120" ..
|
|
38
|
+
if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
|
|
39
|
+
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24")
|
|
40
|
+
set(CMAKE_CUDA_ARCHITECTURES native)
|
|
41
|
+
else()
|
|
42
|
+
# No silent fallback to a stale arch list (the old 75;86;89 default could
|
|
43
|
+
# not even target the sm_120 boxes this repo is developed on): older CMake
|
|
44
|
+
# cannot detect the GPU, so the caller must say which one to build for.
|
|
45
|
+
message(FATAL_ERROR "CMake < 3.24 cannot detect the CUDA arch ('native'); pass "
|
|
46
|
+
"-DCMAKE_CUDA_ARCHITECTURES=<sm> explicitly (e.g. 120 for RTX 50xx, 89 for RTX 40xx)")
|
|
47
|
+
endif()
|
|
48
|
+
endif()
|
|
49
|
+
message(STATUS "Targeting CUDA Architectures: ${CMAKE_CUDA_ARCHITECTURES}")
|
|
50
|
+
|
|
51
|
+
find_package(Python3 REQUIRED COMPONENTS Interpreter Development)
|
|
52
|
+
find_package(pybind11 CONFIG REQUIRED)
|
|
53
|
+
find_package(CUDAToolkit REQUIRED)
|
|
54
|
+
# Headers from the pinned grid-rbd wheel: GLASS (global `glass::`, distinct from
|
|
55
|
+
# grid.cuh's vendored `grid::glass`) and GRiD's collision primitives. gato._grid
|
|
56
|
+
# refuses an unpinned install, so a build never silently compiles against the wrong GLASS.
|
|
57
|
+
# `gato` is importable from the configured python (editable checkout or installed wheel).
|
|
58
|
+
execute_process(COMMAND ${Python3_EXECUTABLE} -m gato._grid
|
|
59
|
+
OUTPUT_VARIABLE GATO_GRID_INCLUDE_DIRS OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
60
|
+
COMMAND_ERROR_IS_FATAL ANY)
|
|
61
|
+
message(STATUS "grid-rbd include dirs: ${GATO_GRID_INCLUDE_DIRS}")
|
|
62
|
+
|
|
63
|
+
include_directories(${CMAKE_SOURCE_DIR}/gato)
|
|
64
|
+
|
|
65
|
+
# --- Executable Targets ---
|
|
66
|
+
if(GATO_BUILD_DEMO)
|
|
67
|
+
add_executable(bsqp examples/cpp/batched_solve.cu)
|
|
68
|
+
target_compile_definitions(bsqp PRIVATE
|
|
69
|
+
KNOT_POINTS=16
|
|
70
|
+
GATO_PLANT_NAME=indy7
|
|
71
|
+
GATO_PLANT_NAME_STR="indy7"
|
|
72
|
+
GATO_PLANT_HEADER="dynamics/plant.cuh")
|
|
73
|
+
if(GATO_EXACT_HESSIAN)
|
|
74
|
+
target_compile_definitions(bsqp PRIVATE USE_EXACT_HESSIAN=1)
|
|
75
|
+
endif()
|
|
76
|
+
if(GATO_CONTACT_FORCES)
|
|
77
|
+
target_compile_definitions(bsqp PRIVATE GATO_CONTACT_FORCES=1)
|
|
78
|
+
endif()
|
|
79
|
+
# The per-robot dir supplies grid.cuh + limits.cuh to the generic plant header.
|
|
80
|
+
target_include_directories(bsqp PRIVATE ${CMAKE_SOURCE_DIR}/gato/dynamics/indy7
|
|
81
|
+
${GATO_GRID_INCLUDE_DIRS})
|
|
82
|
+
target_link_libraries(bsqp PRIVATE CUDA::cudart)
|
|
83
|
+
endif()
|
|
84
|
+
|
|
85
|
+
# --- Python Bindings ---
|
|
86
|
+
|
|
87
|
+
# horizon length and plant options (configurable via -D at configure time).
|
|
88
|
+
# Plants are discovered by convention: gato/dynamics/<name>/{grid.cuh,limits.cuh}
|
|
89
|
+
# (generated) + the shared gato/dynamics/plant.cuh adapter — adding a robot
|
|
90
|
+
# requires NO CMake edits.
|
|
91
|
+
set(KNOTS_DEFAULT "8;16;32;64;128")
|
|
92
|
+
set(PLANT_DEFAULT "indy7;iiwa14")
|
|
93
|
+
# Where the built modules land. Default = the python package (import gato picks
|
|
94
|
+
# them up). Point it elsewhere for side-by-side variant builds (e.g. an
|
|
95
|
+
# exact-Hessian A/B) so a variant configure can't clobber the default modules.
|
|
96
|
+
set(GATO_MODULE_OUTPUT_DIR "${CMAKE_SOURCE_DIR}/python/gato" CACHE PATH "Output directory for the bsqp python modules")
|
|
97
|
+
# Where <plant>/{grid.cuh,limits.cuh} live: the checkout's vendored robots by default;
|
|
98
|
+
# gato.register_robot points this at its per-host cache for user robots.
|
|
99
|
+
set(GATO_PLANT_ROOT "${CMAKE_SOURCE_DIR}/gato/dynamics" CACHE PATH "Directory holding <plant>/{grid.cuh,limits.cuh}")
|
|
100
|
+
set(KNOTS "${KNOTS_DEFAULT}" CACHE STRING "Semicolon-separated horizon lengths (e.g., 32;64;128)")
|
|
101
|
+
set(PLANT "${PLANT_DEFAULT}" CACHE STRING "Semicolon-separated plant targets (e.g., indy7;iiwa14)")
|
|
102
|
+
# Explicit per-plant horizons: 'plant:N,N;plant:N' (overrides the PLANT x KNOTS
|
|
103
|
+
# cross-product — needed whenever plants have DIFFERENT supported horizons,
|
|
104
|
+
# e.g. go2 is N16-only while the arms carry the full ladder).
|
|
105
|
+
set(MODULES "" CACHE STRING "Explicit module list 'indy7:8,16;go2:16;indy7:16:fc' = plant:knots[:variant] (overrides PLANT x KNOTS)")
|
|
106
|
+
# Module VARIANTS are separate ABIs with their own module names (plan 2.A,
|
|
107
|
+
# 2026-09-20): bsqpN{N}_{plant} (default) | _fc (GATO_CONTACT_FORCES: contact-
|
|
108
|
+
# force controls appended to u) | _eh (GATO_EXACT_HESSIAN: SO-SQP path). They
|
|
109
|
+
# all land in GATO_MODULE_OUTPUT_DIR side by side — no more .so-swap. The
|
|
110
|
+
# global options set the variant for a PLANT x KNOTS cross-product; an explicit
|
|
111
|
+
# MODULES / receipt-profile entry carries its own variant per target.
|
|
112
|
+
if(GATO_CONTACT_FORCES AND GATO_EXACT_HESSIAN)
|
|
113
|
+
message(FATAL_ERROR "GATO_CONTACT_FORCES and GATO_EXACT_HESSIAN are separate module variants — build one at a time (or list them per target in MODULES)")
|
|
114
|
+
endif()
|
|
115
|
+
set(GATO_DEFAULT_VARIANT "default")
|
|
116
|
+
if(GATO_CONTACT_FORCES)
|
|
117
|
+
set(GATO_DEFAULT_VARIANT "fc")
|
|
118
|
+
elseif(GATO_EXACT_HESSIAN)
|
|
119
|
+
set(GATO_DEFAULT_VARIANT "eh")
|
|
120
|
+
endif()
|
|
121
|
+
# The receipt profile = exactly test/receipt_modules.txt (the set the signed
|
|
122
|
+
# gpu-proof receipt attests); run_gpu_proof.sh preflights the same file.
|
|
123
|
+
option(GATO_RECEIPT_PROFILE "Configure exactly the receipt module set (test/receipt_modules.txt)" OFF)
|
|
124
|
+
# Normalize to semicolon lists (accept commas/spaces)
|
|
125
|
+
string(REPLACE "," ";" KNOTS "${KNOTS}")
|
|
126
|
+
string(REPLACE " " ";" KNOTS "${KNOTS}")
|
|
127
|
+
string(REPLACE "," ";" PLANT "${PLANT}")
|
|
128
|
+
string(REPLACE " " ";" PLANT "${PLANT}")
|
|
129
|
+
|
|
130
|
+
# Resolve the module set into a list of "plant:knot" pairs.
|
|
131
|
+
set(GATO_MODULE_PAIRS "")
|
|
132
|
+
if(GATO_RECEIPT_PROFILE)
|
|
133
|
+
file(STRINGS "${CMAKE_SOURCE_DIR}/test/receipt_modules.txt" _receipt_lines REGEX "^[a-z0-9_]+[ \t]+[0-9]+")
|
|
134
|
+
foreach(_line ${_receipt_lines})
|
|
135
|
+
string(REGEX MATCH "^([a-z0-9_]+)[ \t]+([0-9]+)[ \t]*([a-z]*)" _m "${_line}")
|
|
136
|
+
set(_var "${CMAKE_MATCH_3}")
|
|
137
|
+
if(NOT _var)
|
|
138
|
+
set(_var "default")
|
|
139
|
+
endif()
|
|
140
|
+
list(APPEND GATO_MODULE_PAIRS "${CMAKE_MATCH_1}:${CMAKE_MATCH_2}:${_var}")
|
|
141
|
+
endforeach()
|
|
142
|
+
message(STATUS "Receipt profile: ${GATO_MODULE_PAIRS}")
|
|
143
|
+
elseif(MODULES)
|
|
144
|
+
string(REPLACE " " ";" _entries "${MODULES}")
|
|
145
|
+
foreach(_entry ${_entries})
|
|
146
|
+
string(REGEX MATCH "^([a-z0-9_]+):([0-9,]+)(:([a-z]+))?$" _m "${_entry}")
|
|
147
|
+
if(NOT _m)
|
|
148
|
+
message(FATAL_ERROR "MODULES entry '${_entry}' is not 'plant:N,N[:variant]'")
|
|
149
|
+
endif()
|
|
150
|
+
set(_var "${CMAKE_MATCH_4}")
|
|
151
|
+
if(NOT _var)
|
|
152
|
+
set(_var "${GATO_DEFAULT_VARIANT}")
|
|
153
|
+
endif()
|
|
154
|
+
string(REPLACE "," ";" _ks "${CMAKE_MATCH_2}")
|
|
155
|
+
foreach(_k ${_ks})
|
|
156
|
+
list(APPEND GATO_MODULE_PAIRS "${CMAKE_MATCH_1}:${_k}:${_var}")
|
|
157
|
+
endforeach()
|
|
158
|
+
endforeach()
|
|
159
|
+
message(STATUS "Explicit modules: ${GATO_MODULE_PAIRS}")
|
|
160
|
+
else()
|
|
161
|
+
foreach(plant ${PLANT})
|
|
162
|
+
foreach(knot ${KNOTS})
|
|
163
|
+
list(APPEND GATO_MODULE_PAIRS "${plant}:${knot}:${GATO_DEFAULT_VARIANT}")
|
|
164
|
+
endforeach()
|
|
165
|
+
endforeach()
|
|
166
|
+
message(STATUS "Configuring Python modules for PLANT='${PLANT}' KNOTS='${KNOTS}'")
|
|
167
|
+
endif()
|
|
168
|
+
|
|
169
|
+
foreach(pair ${GATO_MODULE_PAIRS})
|
|
170
|
+
string(REPLACE ":" ";" _pk "${pair}")
|
|
171
|
+
list(GET _pk 0 plant)
|
|
172
|
+
list(GET _pk 1 knot)
|
|
173
|
+
list(GET _pk 2 variant)
|
|
174
|
+
if(NOT variant MATCHES "^(default|fc|eh)$")
|
|
175
|
+
message(FATAL_ERROR "module ${pair}: variant must be default|fc|eh")
|
|
176
|
+
endif()
|
|
177
|
+
foreach(gen_header grid.cuh limits.cuh)
|
|
178
|
+
if(NOT EXISTS "${GATO_PLANT_ROOT}/${plant}/${gen_header}")
|
|
179
|
+
message(FATAL_ERROR "Plant '${plant}': missing ${GATO_PLANT_ROOT}/${plant}/${gen_header} "
|
|
180
|
+
"(generate it with gato.register_robot / gato.build / tools/regen_grid.py)")
|
|
181
|
+
endif()
|
|
182
|
+
endforeach()
|
|
183
|
+
block()
|
|
184
|
+
set(VARIANT_SUFFIX "")
|
|
185
|
+
if(NOT variant STREQUAL "default")
|
|
186
|
+
set(VARIANT_SUFFIX "_${variant}")
|
|
187
|
+
endif()
|
|
188
|
+
set(MODULE_NAME "bsqpN${knot}_${plant}${VARIANT_SUFFIX}")
|
|
189
|
+
message(STATUS "Configuring Python module: ${MODULE_NAME}")
|
|
190
|
+
pybind11_add_module(${MODULE_NAME} SHARED python/bindings.cu)
|
|
191
|
+
# Bind the module to actual native inputs, not their mtimes. Reconfigure
|
|
192
|
+
# after source changes (tools/build.sh does this) before signing a receipt.
|
|
193
|
+
execute_process(COMMAND ${Python3_EXECUTABLE} ${CMAKE_SOURCE_DIR}/tools/native_identity.py
|
|
194
|
+
--plant ${plant} --plant-root ${GATO_PLANT_ROOT} OUTPUT_VARIABLE _native_id
|
|
195
|
+
OUTPUT_STRIP_TRAILING_WHITESPACE COMMAND_ERROR_IS_FATAL ANY)
|
|
196
|
+
target_compile_definitions(${MODULE_NAME} PRIVATE GATO_NATIVE_SOURCE_ID="${_native_id}")
|
|
197
|
+
|
|
198
|
+
# The per-robot dir supplies grid.cuh + limits.cuh to the generic plant
|
|
199
|
+
# header; the wheel's collision dir supplies grid_collision_geometry.cuh
|
|
200
|
+
# (SDF primitives grid.cuh includes when built with collision_res).
|
|
201
|
+
target_include_directories(${MODULE_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/gato
|
|
202
|
+
${GATO_PLANT_ROOT}/${plant}
|
|
203
|
+
${GATO_GRID_INCLUDE_DIRS})
|
|
204
|
+
|
|
205
|
+
target_compile_definitions(${MODULE_NAME} PRIVATE
|
|
206
|
+
KNOT_POINTS=${knot}
|
|
207
|
+
GATO_PLANT_NAME=${plant}
|
|
208
|
+
GATO_MODULE_VARIANT=${VARIANT_SUFFIX}
|
|
209
|
+
GATO_PLANT_HEADER="dynamics/plant.cuh")
|
|
210
|
+
if(variant STREQUAL "eh")
|
|
211
|
+
target_compile_definitions(${MODULE_NAME} PRIVATE USE_EXACT_HESSIAN=1)
|
|
212
|
+
elseif(variant STREQUAL "fc")
|
|
213
|
+
target_compile_definitions(${MODULE_NAME} PRIVATE GATO_CONTACT_FORCES=1)
|
|
214
|
+
endif()
|
|
215
|
+
|
|
216
|
+
set_target_properties(
|
|
217
|
+
${MODULE_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY
|
|
218
|
+
${GATO_MODULE_OUTPUT_DIR})
|
|
219
|
+
target_link_libraries(${MODULE_NAME} PRIVATE CUDA::cudart)
|
|
220
|
+
endblock()
|
|
221
|
+
endforeach()
|