Heuristic:Google deepmind Mujoco Solver Selection Guide
| Knowledge Sources | |
|---|---|
| Domains | Optimization, Physics_Simulation |
| Last Updated | 2026-02-15 05:00 GMT |
Overview
Decision framework for choosing between CG, Newton, and PGS constraint solvers based on model complexity, hardware backend, and stability requirements.
Description
MuJoCo provides three constraint solvers: PGS (Projected Gauss-Seidel), CG (Conjugate Gradient), and Newton. Each solver has different convergence properties, computational costs, and backend compatibility. In MJX (JAX/Warp backends), only CG and Newton are implemented; PGS is not available. The choice of solver significantly affects both simulation speed and physical accuracy.
Usage
Use this heuristic when configuring solver parameters for a new model, optimizing simulation throughput, or debugging contact instability. It applies to both native MuJoCo C API and MJX workloads.
The Insight (Rule of Thumb)
- Action: Choose CG solver as default for most articulated body simulations.
- Value: Set `m.opt.solver = mujoco.mjtSolver.mjSOL_CG` with `iterations=1` and `ls_iterations=4` for MJX benchmarks.
- Trade-off: Newton converges faster per iteration for well-conditioned problems but requires Hessian computation. CG is cheaper per iteration and more robust.
- PGS: Simplest and most robust but slowest convergence. Only available in native C API, not in MJX.
- Sparse vs Dense: Use `JacobianType.AUTO` which selects sparse when `nv > 60` (especially on TPU), dense otherwise.
Reasoning
CG solver uses preconditioned conjugate gradient which is well-suited for GPU execution (GEMM-friendly operations). Newton requires explicit Hessian factorization which is more expensive but converges in fewer iterations for stiff constraint systems. PGS is sequential by nature and difficult to parallelize, hence excluded from MJX.
The MJX benchmark defaults use CG with `iterations=1, ls_iterations=4` because:
- Single CG iteration with 4 line-search steps provides good cost-accuracy trade-off for typical robotics models.
- Higher unroll values help GPU GEMM performance.
- CG naturally extends to batched (vmapped) execution without per-instance branching.
The sparse vs dense Jacobian decision threshold at `nv=60` comes from empirical observation that sparse matrix operations become faster than dense GEMM at higher degrees of freedom.
Code Evidence
Solver enumeration and PGS exclusion from `mjx/mujoco/mjx/_src/types.py:214-217`:
class SolverType(enum.IntEnum):
# unsupported: PGS
CG = mujoco.mjtSolver.mjSOL_CG
NEWTON = mujoco.mjtSolver.mjSOL_NEWTON
Solver validation in `mjx/mujoco/mjx/_src/io.py:231-232`:
if o.solver not in set(types.SolverType):
raise NotImplementedError(f'{mujoco.mjtSolver(o.solver)}')
Benchmark defaults from `mjx/mujoco/mjx/_src/test_util.py:56-58`:
def benchmark(
m: mujoco.MjModel,
nstep: int = 1000,
batch_size: int = 1024,
unroll_steps: int = 1,
solver: str = 'newton',
iterations: int = 1,
ls_iterations: int = 4,
) -> Tuple[float, float, int]:
Sparse Jacobian auto-selection from `mjx/mujoco/mjx/_src/types.py:193-200`:
class JacobianType(enum.IntEnum):
"""Type of constraint Jacobian.
Attributes:
DENSE: dense
SPARSE: sparse
AUTO: sparse if nv>60 and device is TPU, dense otherwise
"""
Unsupported solver error from `mjx/mujoco/mjx/_src/solver.py:413-414`:
raise NotImplementedError(f'unsupported solver type: {m.opt.solver}')