From f9f1db1e0a176da2c398458f3b17cd2c47527b38 Mon Sep 17 00:00:00 2001 From: Alessio Quaglino Date: Mon, 11 May 2026 10:09:37 -0700 Subject: [PATCH] Replace the banded Cholesky solver for implicit flex interpolation with a preconditioned Conjugate Gradient (CG) solver that operates on the full system matrix. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous approach extracted flex DOFs into a reduced banded system, factored it separately, and overwrote the global solve. This required precomputed bandwidth (makeFlexBandwidth), parent-joint detection, coupling corrections, and a FlexInterpContext struct — and only worked for standalone flex trees without parent joints. The new CG solver uses the already-factored global system (M - h*qDeriv) as a preconditioner and adds the flex stiffness contribution via matrix-free products (mjd_flexInterp_mulKD/mulK). This handles any kinematic configuration — including flexes attached to articulated chains or with parent joints — without sparsity pattern restrictions. Before (`bunny_multicell`): ``` Simulation time : 50.80 s Steps per second : 197 Realtime factor : 0.20 x Time per step : 5080.3 µs CG iters / step : 3.16 Contacts / step : 31.04 Constraints / step : 124.15 Degrees of freedom : 178 Dynamic memory usage : 0.4% of 100M ``` After: ``` Simulation time : 9.52 s Steps per second : 1051 Realtime factor : 1.05 x Time per step : 951.7 µs CG iters / step : 3.21 Contacts / step : 30.90 Constraints / step : 123.61 Degrees of freedom : 178 Dynamic memory usage : 0.3% of 100M ``` PiperOrigin-RevId: 913758038 Change-Id: If5aa617b2d535c86aec9bd71c9e0003a2b38bdd7 --- doc/includes/references.h | 1 - include/mujoco/mjmodel.h | 1 - include/mujoco/mjxmacro.h | 1 - model/flex/bunny_multicell.xml | 4 +- python/mujoco/introspect/structs.py | 8 - src/engine/engine_derivative.c | 12 +- src/engine/engine_derivative.h | 8 +- src/engine/engine_forward.c | 347 ++++++++------------------ src/engine/engine_setconst.c | 131 +--------- test/engine/engine_derivative_test.cc | 56 +++-- unity/Runtime/Bindings/MjBindings.cs | 1 - wasm/codegen/generated/bindings.cc | 4 - 12 files changed, 152 insertions(+), 422 deletions(-) diff --git a/doc/includes/references.h b/doc/includes/references.h index d106b4b6..c226304b 100644 --- a/doc/includes/references.h +++ b/doc/includes/references.h @@ -1316,7 +1316,6 @@ struct mjModel_ { int* flex_matid; // material id for rendering (nflex x 1) int* flex_group; // group for visibility (nflex x 1) int* flex_interp; // interpolation (0: vertex, 1: nodes) (nflex x 1) - int* flex_bandwidth; // precomputed solver bandwidth (nflex x 1) int* flex_cellnum; // finite cell num per dimension (nflex x 3) int* flex_nodeadr; // first node address (nflex x 1) int* flex_nodenum; // number of nodes (nflex x 1) diff --git a/include/mujoco/mjmodel.h b/include/mujoco/mjmodel.h index ec2c8250..565358d0 100644 --- a/include/mujoco/mjmodel.h +++ b/include/mujoco/mjmodel.h @@ -979,7 +979,6 @@ struct mjModel_ { int* flex_matid; // material id for rendering (nflex x 1) int* flex_group; // group for visibility (nflex x 1) int* flex_interp; // interpolation (0: vertex, 1: nodes) (nflex x 1) - int* flex_bandwidth; // precomputed solver bandwidth (nflex x 1) int* flex_cellnum; // finite cell num per dimension (nflex x 3) int* flex_nodeadr; // first node address (nflex x 1) int* flex_nodenum; // number of nodes (nflex x 1) diff --git a/include/mujoco/mjxmacro.h b/include/mujoco/mjxmacro.h index 080cbc07..c11ff844 100644 --- a/include/mujoco/mjxmacro.h +++ b/include/mujoco/mjxmacro.h @@ -455,7 +455,6 @@ X ( int, flex_matid, nflex, 1 ) \ X ( int, flex_group, nflex, 1 ) \ X ( int, flex_interp, nflex, 1 ) \ - X ( int, flex_bandwidth, nflex, 1 ) \ X ( int, flex_cellnum, nflex, 3 ) \ X ( int, flex_nodeadr, nflex, 1 ) \ X ( int, flex_nodenum, nflex, 1 ) \ diff --git a/model/flex/bunny_multicell.xml b/model/flex/bunny_multicell.xml index 730cbc5d..5f4d9f1d 100644 --- a/model/flex/bunny_multicell.xml +++ b/model/flex/bunny_multicell.xml @@ -16,9 +16,9 @@ -