Skip to content

Commit a230aa6

Browse files
yuvaltassacopybara-github
authored andcommitted
Improve mj_addM and associated test
- Updated docs to clarify that only the lower triangle is touched - The function was unnecessarily adding the upper triangle in the sparse case - The test used an unnecessarily large model and stepping it leading to timeouts under ASAN PiperOrigin-RevId: 798528736 Change-Id: I592cc17dfb62379bb0cd6b332a8eb7e8b0ef6355
1 parent a64a26c commit a230aa6

File tree

6 files changed

+20
-22
lines changed

6 files changed

+20
-22
lines changed

doc/APIreference/functions.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ Multiply vector by (inertia matrix)^(1/2).
492492

493493
.. mujoco-include:: mj_addM
494494

495-
Add inertia matrix to destination matrix.
495+
Add inertia matrix to destination matrix (lower triangle only).
496496

497497
Destination can be sparse or dense when all int* are NULL.
498498

include/mujoco/mujoco.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ MJAPI void mj_mulM(const mjModel* m, const mjData* d, mjtNum* res, const mjtNum*
512512
// Multiply vector by (inertia matrix)^(1/2).
513513
MJAPI void mj_mulM2(const mjModel* m, const mjData* d, mjtNum* res, const mjtNum* vec);
514514

515-
// Add inertia matrix to destination matrix.
515+
// Add inertia matrix to destination matrix (lower triangle only).
516516
// Destination can be sparse or dense when all int* are NULL.
517517
// Nullable: rownnz, rowadr, colind
518518
MJAPI void mj_addM(const mjModel* m, mjData* d, mjtNum* dst, int* rownnz, int* rowadr, int* colind);

python/mujoco/introspect/functions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3001,7 +3001,7 @@
30013001
nullable=True,
30023002
),
30033003
),
3004-
doc='Add inertia matrix to destination matrix. Destination can be sparse or dense when all int* are NULL.', # pylint: disable=line-too-long
3004+
doc='Add inertia matrix to destination matrix (lower triangle only). Destination can be sparse or dense when all int* are NULL.', # pylint: disable=line-too-long
30053005
)),
30063006
('mj_applyFT',
30073007
FunctionDecl(

src/engine/engine_support.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1038,7 +1038,7 @@ void mj_addM(const mjModel* m, mjData* d, mjtNum* dst,
10381038

10391039
// dense
10401040
else {
1041-
mju_addToSymSparse(dst, d->M, nv, m->M_rownnz, m->M_rowadr, m->M_colind, /*flg_upper=*/ 1);
1041+
mju_addToSymSparse(dst, d->M, nv, m->M_rownnz, m->M_rowadr, m->M_colind, /*flg_upper*/ 0);
10421042
}
10431043
}
10441044

src/engine/engine_support.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ MJAPI void mj_mulM(const mjModel* m, const mjData* d, mjtNum* res, const mjtNum*
129129
// multiply vector by (inertia matrix)^(1/2)
130130
MJAPI void mj_mulM2(const mjModel* m, const mjData* d, mjtNum* res, const mjtNum* vec);
131131

132-
// add inertia matrix to destination matrix
132+
// add inertia matrix to destination matrix (lower triangle only)
133133
// destination can be sparse or dense when all int* are NULL
134134
MJAPI void mj_addM(const mjModel* m, mjData* d, mjtNum* dst,
135135
int* rownnz, int* rowadr, int* colind);

test/engine/engine_support_test.cc

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -743,24 +743,24 @@ TEST_F(SupportTest, GetSetStateStepEqual) {
743743

744744
using InertiaTest = MujocoTest;
745745

746-
TEST_F(InertiaTest, DenseSameAsSparse) {
747-
mjModel* m = LoadModelFromPath("humanoid/humanoid100.xml");
748-
mjData* d = mj_makeData(m);
746+
static const char* const kInertiaPath = "engine/testdata/inertia.xml";
747+
748+
TEST_F(InertiaTest, AddMdenseSameAsSparse) {
749+
const std::string xml_path = GetTestDataFilePath(kInertiaPath);
750+
char error[1024];
751+
mjModel* m = mj_loadXML(xml_path.c_str(), nullptr, error, sizeof(error));
752+
ASSERT_THAT(m, NotNull()) << "Failed to load model: " << error;
749753
int nv = m->nv;
750754

751-
// force use of sparse matrices
752-
m->opt.jacobian = mjJAC_SPARSE;
755+
mjData* d = mj_makeData(m);
753756

754-
// warm-up rollout to get a typical state
755-
while (d->time < 2) {
756-
mj_step(m, d);
757-
}
757+
mj_step(m, d);
758758

759-
// dense zero matrix
760-
vector<mjtNum> dst_sparse(nv * nv, 0.0);
759+
// dense matrix, all values are 3.0
760+
vector<mjtNum> dst_dense(nv * nv, 3.0);
761761

762-
// sparse zero matrix
763-
vector<mjtNum> dst_dense(nv * nv, 0.0);
762+
// sparse matrix, all values are 3.0
763+
vector<mjtNum> dst_sparse(nv * nv, 3.0);
764764
vector<int> rownnz(nv, nv);
765765
vector<int> rowadr(nv, 0);
766766
vector<int> colind(nv * nv, 0);
@@ -780,9 +780,9 @@ TEST_F(InertiaTest, DenseSameAsSparse) {
780780
// dense addM
781781
mj_addM(m, d, dst_dense.data(), nullptr, nullptr, nullptr);
782782

783-
// dense comparison, lower triangle should match
783+
// dense comparison (lower triangle)
784784
for (int i=0; i < nv; i++) {
785-
for (int j=0; j < i; j++) {
785+
for (int j=0; j < nv; j++) {
786786
EXPECT_EQ(dst_dense[i*nv+j], dst_sparse[i*nv+j]);
787787
}
788788
}
@@ -792,8 +792,6 @@ TEST_F(InertiaTest, DenseSameAsSparse) {
792792
mj_deleteModel(m);
793793
}
794794

795-
static const char* const kInertiaPath = "engine/testdata/inertia.xml";
796-
797795
TEST_F(InertiaTest, mulM) {
798796
const std::string xml_path = GetTestDataFilePath(kInertiaPath);
799797
char error[1024];

0 commit comments

Comments
 (0)