The primal cost has curvature of at least M in every zone, making it strongly
convex in the M-norm and bounding the suboptimality of any point by the
Fenchel duality gap at its constraint forces:
cost(qacc) - cost* <= 0.5*grad'*M^-1*grad
Since M's factorization always exists, this certificate is evaluable before
the solver does any work: one triangular solve and one dot product. When the
warmstarted solution is already certified to satisfy the tolerance, CG and
Newton now return with zero iterations; for Newton this skips building and
factorizing the Hessian. If the certificate declines, Newton gets a second
exit after factorization: the Newton decrement, checked before the first
line search.
Because the gap bounds cost suboptimality, stiff constraints can convert it
into force errors of order sqrt(2*gap*stiffness). Newton solutions are
characteristically force-accurate, so Newton zero-iteration exits also
require the gradient criterion, preserving constraint-force accuracy at
rest; CG solutions are characteristically cost-accurate and exit on the gap
alone.
On a settling pile of 50 boxes (300 dofs, ~200 contacts), end-to-end time
per step drops 13% over a settle-then-rest run and 27% in the quiescent
limit, with Newton iterations falling from 0.98 to 0.40 per step.
Tests: WarmstartZeroIterations sweeps solver/cone/jacobian on a settled box,
asserting zero iterations, forward/inverse consistency, and agreement with a
tolerance=0 control solve from the same state. WarmstartZeroIterationsIslands
checks per-island exits with a kicked box next to a settled one.
RefsiteConservesMomentum now requests an exact solve (tolerance=0), since it
asserts momentum conservation tighter than the solver tolerance contract.
PiperOrigin-RevId: 947993735
Change-Id: I2fd855774bff619709b2c386f1ba2714286e0821
After an accepted line-search step, the solver has already rebuilt the gradient
and Hessian and solved for the next search direction, so the Newton decrement
0.5*g'*H^-1*g -- the quadratic model's predicted cost improvement of the next
iteration -- costs one dot product. Terminating when it falls below tolerance
avoids running one more iteration only to observe a correspondingly small
actual improvement.
This is a C port of Alain's proposal in MJWarp:
https://github.com/google-deepmind/mujoco_warp/pull/1520
PiperOrigin-RevId: 947768034
Change-Id: I94e5c71a4e2b4a7775611edd1dad254bba2633b4
mju_factorLU6/mju_solveLU6: same algorithm as mju_factorLU/mju_solveLU
with compile-time size, allowing full unrolling. At n=6, factor+solve is
25% faster than the runtime-sized version (93 vs 124 ns), and fixed-size
LU factorization is faster than generic dense Cholesky (55 vs 61 ns):
at this size, runtime-n loop overhead outweighs Cholesky's 2x flop
advantage. See new lu_benchmark_test. Results agree with the generic
version to rounding, not bitwise: the compiler may fuse (FMA) the
unrolled version differently.
Also add two DenseLU tests: a pivoting-required matrix with zero
diagonal, and fixed-vs-generic agreement.
PiperOrigin-RevId: 947705056
Change-Id: I24c54c9510964aa376886e9dd721890eda9889d3
The mid-phase BVH descent filter prunes body pairs using body_margin,
which was compiled as the max over geom margins, excluding gap. Broadphase
and the leaf-level test both use margin+gap, so any multi-geom body relying
on gap could silently lose its in-gap contacts when raw AABBs don't
overlap. Single-geom bodies take the leaf-leaf path and were unaffected.
PiperOrigin-RevId: 946967548
Change-Id: I6d92baa296f1a83be68b4dbfd64a96d1c7efd3c4
Reformulate the cost difference calculation (`ellipticCostDif`) to use mathematically equivalent formulas that avoid subtracting large, nearly equal values (cancellation errors) in single precision at high normal forces.
This is a C port of Alain's formulation in MJWarp:
https://github.com/google-deepmind/mujoco_warp/pull/1512
Also adds an integration test (`EllipticLineSearchPrecisionDiagnostics`) that reproduces the precision issue under large normal forces in the sliding regime, and asserts that the solver does not produce large negative improvements in either precision. This test failed before the change.
PiperOrigin-RevId: 946137815
Change-Id: Ia8fc1c4823b5fee770140c8989b9465737d22ad7
The flexcomp compiler previously rejected pins on dim-2 flexes with
bending (elastic2d bend/both). Allow them: mj_flexPassiveBend treats a
pinned vertex (body without 3 free slide dofs) as static -- zero
velocity, and no bending force applied to it (the reaction is carried
by the pin) -- while its position still enters every neighbor's
bending force, which is exactly what the pin constrains.
PiperOrigin-RevId: 944410969
Change-Id: Ib0a69c8d5fb6f64d3e2a76af3b6b2c7be1898191
Deletes mj_factorI_legacy and mj_solveLD_legacy from the engine and headers.
Updates factorI, solveLD, and inertia benchmarks to remove legacy targets
and only benchmark CSR.
Rewrites engine_core_smooth_test to verify CSR solver against mj_mulM
instead of legacy solver.
PiperOrigin-RevId: 942507341
Change-Id: I4281decb7018cfa3e46cb446efd5fe1179f6ae1f
The `body_sameframe`, `geom_sameframe`, and `site_sameframe` flags are now recomputed within `mj_setConst` based on the current model geometry. This allows these flags to be updated if the model's body/geom/site frames are modified after the initial compilation. Tests are added to verify the correct recomputation and its effect on forward kinematics. The compiler also checks that its initial computation matches the result of `mj_setConst`.
Fixes#3029, #1628.
PiperOrigin-RevId: 941758649
Change-Id: I7b995f8c67ad305bca5b52732436ba578c905d73
Compiler warnings are now accumulated in a vector of strings within the mjSpec object. New API functions `mjs_numWarnings` and `mjs_getWarning` are added to access these warnings. The compiler's log handler now chains warnings to the global log handler, ensuring they are still displayed immediately. Call sites in `mj_loadXML`, `mj_compile`, and the Python and WASM bindings have been updated to use the new warning API.
PiperOrigin-RevId: 933361650
Change-Id: I47cab98a460c57b0898c0a1a43fce2a5b9648eb1
The test verifies that contact sensors on subtrees and touch sensors on sites correctly register contacts involving Flex components.
PiperOrigin-RevId: 929109418
Change-Id: I1865311a6da838d75ef33989ac7f3c2d975cdbff
Previously shell mode required cellcount=1 along at least one axis. This CL
adds support for cellcount > 1 in all three axes by pinning interior grid nodes
to the parent body and reconstructing their positions from boundary nodes via
Transfinite Interpolation (TFI).
PiperOrigin-RevId: 924314800
Change-Id: I8c2438f4866dd4133feed65f535a1ab69f0c9188
The field now stores either an approximate or exact diagonal of the constraint matrix A, so the name is made more general.
PiperOrigin-RevId: 924244954
Change-Id: I62b2f76531fb88b7b3bf96e6769940197596702b
Fixes#2313
This CL combines two complementary improvements to the Conjugate Gradient (CG) solver, significantly improving numerical precision, stability, and efficiency, particularly in single precision (float32).
1. Line Search Cost Evaluation Refactor: Previously, solver improvement was calculated by subtracting absolute costs: cost(alpha) - cost(0). In highly converged states or single precision, this is susceptible to catastrophic cancellation. We refactor PrimalSearch to compute the cost delta directly, dramatically improving precision.
2. Improved Solver Termination Condition: Near the float32 precision limit, line search deltas can occasionally be slightly negative due to numerical noise. Previously, any value below m->opt.tolerance (including negative values) triggered termination, halting the solver and locking in destabilizing steps. We update the termination condition to require positive improvement (0 < improvement < m->opt.tolerance), allowing the solver to continue iterating and recover stability.
Together, these changes yield substantial improvements, see reduced tolerances herein.
PiperOrigin-RevId: 924229669
Change-Id: Ic0bbefaed090f3a8b1e79ab8d45422c3e86fb56c
Also add MJTOL_SCALE to fixture to allow tests to be run with zero tolerance. This is useful when assesing the impact of code changes (A/B comparison of failure values)
PiperOrigin-RevId: 924219083
Change-Id: Ifdd09ac850904ca8dd79179930ce738a4b37d284
The MSVC fallback path in safeAddToBufferSize() performed unchecked
arithmetic (type_size*nr*nc) on attacker-controlled values read from
.mjb binary model files. This could cause integer overflow, leading
to an undersized heap allocation followed by a heap buffer overflow
when data is copied into the buffer.
The fix adds manual overflow detection using SIZE_MAX/INTPTR_MAX
comparisons, matching the behavior of the existing __builtin_*_overflow
path used on GCC/Clang.
Also adds a regression test that crafts a binary model buffer with
overflow-inducing size fields and asserts safe rejection.
The normal component of the tactile sensor now reports the maximum penetration depth at each taxel, instead of a derived normal force. The depth is negated so that positive values indicate penetration.
PiperOrigin-RevId: 921980899
Change-Id: Ide4103c0aff465e25a81cfdda650f6a0e2da9e0b