newton.ik · dylanturpin/trajectory-ik

Trajectory IK in Newton

newton.ik.IKSolverTrajectory solves every frame of a joint trajectory jointly — one nonlinear least-squares problem over all frames — instead of frame by frame. Existing per-frame objectives work unchanged; new temporal objectives couple consecutive frames and make the system block-banded, which is what the GPU solve exploits.

python -m newton.examples ik_trajectory · branch dylanturpin/trajectory-ik · numbers on RTX PRO 6000 Blackwell, July 2026

90-frame pick-and-place trajectory re-optimized jointly every viewer frame while the pick waypoint is dragged. Warm-started, CUDA-graph captured.

What was added

Why it's fast: the problem is block-banded

Per-frame costs touch one frame; smoothness costs touch k+1 consecutive frames. So the Gauss–Newton Hessian is block-banded — tridiagonal for velocity costs, wider for acceleration/jerk — and the Newton step costs O(T), not O(T³).

path 1 · direct

Batched block-tridiagonal Cholesky

  • Block Thomas: one CUDA block per trajectory, sequential over frames inside a single wp.tile_cholesky kernel — exact solve.
  • Higher-order stencils reblocked into k·n superblocks, so accel/jerk costs reuse the same tridiagonal kernel.
  • Sequential-in-T cost hidden by batch parallelism: 64 trajectories cost about the same as one.
path 2 · cg

Block-Jacobi preconditioned CG

  • Block-banded Hessian in BSR form (warp.sparse, fixed topology, values rewritten in place) + batched warp.optim.linear.cg.
  • Hand-rolled block-Jacobi preconditioner (per-frame n×n blocks inverted with tile_cholesky_solve), warm-started across LM iterations.
  • Parallel over frames — wins for long horizons; inexact but agrees with direct to ~1e-6.

Results — trajectory solve

Shared task: Franka FR3, T=120 frames @ 30 fps, 4 trajectories, end-effector path through pick-and-place waypoints, 16 LM iterations, analytic Jacobians. The frame-by-frame baseline is the per-frame IKSolver, warm-started and batched across the 4 trajectories.

Humanoid retargeting (G1, soma-retargeter data)

soma-retargeter today drives newton.ik frame by frame to retarget human motion (it produced the G1 motions in BONES-SEED). Same front end here — SOMA BVH clips scaled to 14 world-frame effector targets — but the whole clip is solved jointly on a floating-base 29-DoF G1 (free joint, so the lever-arm coupling matters).

Dance clip retargeted to G1 from the same 14 effector targets. The robot with the orange target markers is the joint trajectory solve; the other replays the raw frame-by-frame loop (soma's production approach, without its post-processing) — watch its arms and knees twitch.

Cross-library check: single-frame IK still holds up

Re-run of the earlier single-frame comparison (Newton IK paper protocol: random reachable targets from FK of uniform-random configurations; success = position < 5 mm and orientation < 0.05 rad). Original numbers were measured on an RTX 4090; these are on this box's RTX PRO 6000, so compare ratios, not absolutes.

Appendix

Design space: who solves the banded system how

Everyone in trajectory optimization sits at one of four points on how they solve the block-banded Gauss–Newton system (bandwidth 2(k+1)n−1 for k-order costs; the banded Newton step is O(T·k²n³) — linear in T, same structure as Riccati/DDP and factor-graph message passing):

ApproachWhoLinear algebraParallel over T?Batch?
Direct banded / RiccatiKOMO, GPMP2, Crocoddyl/Aligator, OCS2banded/block-tridiag Cholesky, exactno (sequential sweep)rare (CPU)
Iterative CG on normal eqspyroki/jaxls, MPCGPUmatrix-free or BSR SpMVyesyes
Quasi-Newton, no linear solvecuRobo (L-BFGS on B-spline knots)two-loop recursion onlyyesexcellent
SamplingSTOMP, MPPI, MJPCnonerollouts parallelexcellent

Newton's prototype ships the first two as selectable backends (direct is new territory for GPU-batch; jaxls has no banded direct solver — its only sparse direct option is CHOLMOD via a CPU host-callback). cuRobo never forms a Jacobian: temporal structure lives in its B-spline knots (16 knots × 7 DoF = 112 variables, small enough that sparsity stops mattering), with linear-ish convergence and ~100 fixed iterations in exchange. Parallel-in-time direct methods (associative-scan LQR, cyclic reduction) exist but only pay off for single very long trajectories; batch parallelism is the cheaper GPU win.

Warp assessment: what worked, gaps, proposed extensions

Worked out of the box (pinned 1.15.0.dev)

Gaps & bugs hit

Small warp extensions worth proposing

Benchmark protocol & caveats
Pointers