Order fields in mjxmacro like in mjmodel and mjdata headers, add tests.

PiperOrigin-RevId: 798848000
Change-Id: Id1a41f6a0a4e3e6f3bb197f096061bd1d72a4b51
This commit is contained in:
Yuval Tassa
2025-08-24 11:16:47 -07:00
committed by Copybara-Service
parent 7479312218
commit 1c1bb14e1c
3 changed files with 170 additions and 17 deletions
+12 -12
View File
@@ -387,20 +387,17 @@
X ( float, flex_texcoord, nflextexcoord, 2 ) \
X ( int, mesh_vertadr, nmesh, 1 ) \
X ( int, mesh_vertnum, nmesh, 1 ) \
X ( int, mesh_normaladr, nmesh, 1 ) \
X ( int, mesh_normalnum, nmesh, 1 ) \
X ( int, mesh_texcoordadr, nmesh, 1 ) \
X ( int, mesh_texcoordnum, nmesh, 1 ) \
X ( int, mesh_faceadr, nmesh, 1 ) \
X ( int, mesh_facenum, nmesh, 1 ) \
X ( int, mesh_bvhadr, nmesh, 1 ) \
X ( int, mesh_bvhnum, nmesh, 1 ) \
X ( int, mesh_octadr, nmesh, 1 ) \
X ( int, mesh_octnum, nmesh, 1 ) \
X ( int, mesh_normaladr, nmesh, 1 ) \
X ( int, mesh_normalnum, nmesh, 1 ) \
X ( int, mesh_texcoordadr, nmesh, 1 ) \
X ( int, mesh_texcoordnum, nmesh, 1 ) \
X ( int, mesh_graphadr, nmesh, 1 ) \
X ( mjtNum, mesh_scale, nmesh, 3 ) \
X ( mjtNum, mesh_pos, nmesh, 3 ) \
X ( mjtNum, mesh_quat, nmesh, 4 ) \
XNV ( float, mesh_vert, nmeshvert, 3 ) \
XNV ( float, mesh_normal, nmeshnormal, 3 ) \
XNV ( float, mesh_texcoord, nmeshtexcoord, 2 ) \
@@ -408,6 +405,9 @@
XNV ( int, mesh_facenormal, nmeshface, 3 ) \
XNV ( int, mesh_facetexcoord, nmeshface, 3 ) \
XNV ( int, mesh_graph, nmeshgraph, 1 ) \
X ( mjtNum, mesh_scale, nmesh, 3 ) \
X ( mjtNum, mesh_pos, nmesh, 3 ) \
X ( mjtNum, mesh_quat, nmesh, 4 ) \
X ( int, mesh_pathadr, nmesh, 1 ) \
XNV ( int, mesh_polynum, nmesh, 1 ) \
XNV ( int, mesh_polyadr, nmesh, 1 ) \
@@ -670,8 +670,8 @@
X ( int, ten_J_rownnz, ntendon, 1 ) \
X ( int, ten_J_rowadr, ntendon, 1 ) \
X ( int, ten_J_colind, ntendon, MJ_M(nv) ) \
X ( mjtNum, ten_length, ntendon, 1 ) \
X ( mjtNum, ten_J, ntendon, MJ_M(nv) ) \
X ( mjtNum, ten_length, ntendon, 1 ) \
X ( int, wrap_obj, nwrap, 2 ) \
X ( mjtNum, wrap_xpos, nwrap, 6 ) \
X ( mjtNum, actuator_length, nu, 1 ) \
@@ -741,8 +741,8 @@
X ( mjtNum, efc_vel, MJ_D(nefc), 1 ) \
X ( mjtNum, efc_aref, MJ_D(nefc), 1 ) \
X ( mjtNum, efc_b, MJ_D(nefc), 1 ) \
X ( mjtNum, efc_force, MJ_D(nefc), 1 ) \
X ( int, efc_state, MJ_D(nefc), 1 )
X ( int, efc_state, MJ_D(nefc), 1 ) \
X ( mjtNum, efc_force, MJ_D(nefc), 1 )
// array fields of mjData that are used in the dual problem
#define MJDATA_ARENA_POINTERS_DUAL \
@@ -826,12 +826,12 @@
// vector fields of mjData
#define MJDATA_VECTOR \
X( size_t, maxuse_threadstack, mjMAXTHREAD, 1 ) \
X( mjWarningStat, warning, mjNWARNING, 1 ) \
X( mjTimerStat, timer, mjNTIMER, 1 ) \
X( mjSolverStat, solver, mjNISLAND, mjNSOLVER ) \
X( int, solver_niter, mjNISLAND, 1 ) \
X( int, solver_nnz, mjNISLAND, 1 ) \
X( mjtNum, solver_fwdinv, 2, 1 ) \
X( mjWarningStat, warning, mjNWARNING, 1 ) \
X( mjTimerStat, timer, mjNTIMER, 1 ) \
X( mjtNum, energy, 2, 1 )
// alias XNV to be the same as X
+2 -2
View File
@@ -667,12 +667,12 @@ class MjWrapper<raw::MjData>: public WrapperBase<raw::MjData> {
py_array_or_tuple_t<mjContact> contact;
py_array_or_tuple_t<size_t> maxuse_threadstack;
py_array_or_tuple_t<raw::MjWarningStat> warning;
py_array_or_tuple_t<raw::MjTimerStat> timer;
py_array_or_tuple_t<raw::MjSolverStat> solver;
py_array_or_tuple_t<int> solver_niter;
py_array_or_tuple_t<int> solver_nnz;
py_array_or_tuple_t<mjtNum> solver_fwdinv;
py_array_or_tuple_t<raw::MjWarningStat> warning;
py_array_or_tuple_t<raw::MjTimerStat> timer;
py_array_or_tuple_t<mjtNum> energy;
protected:
+156 -3
View File
@@ -15,20 +15,33 @@
// Tests for structures in the public headers.
#include <cstddef>
#include <cstring>
#include <string>
#include <cstdint>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
#include <mujoco/mjdata.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjrender.h>
#include <mujoco/mjui.h>
#include <mujoco/mjvisualize.h>
#include <mujoco/mjxmacro.h>
#include "test/fixture.h"
namespace mujoco {
namespace {
// check that a vector of named pointers are ordered by address
void CheckAddressOrdering(
const std::vector<std::pair<const void*, const char*>>& pointers,
const char* category_name) {
for (size_t i = 0; i < pointers.size() - 1; ++i) {
EXPECT_LT(reinterpret_cast<uintptr_t>(pointers[i].first),
reinterpret_cast<uintptr_t>(pointers[i + 1].first))
<< category_name << " '" << pointers[i].second
<< "' should be declared before '" << pointers[i + 1].second << "'.";
}
}
using HeaderTest = MujocoTest;
TEST_F(HeaderTest, IntsHave4Bytes) {
@@ -84,5 +97,145 @@ TEST_F(HeaderTest, EnumsAreInts) {
EXPECT_EQ(sizeof(mjtStereo), sizeof(int));
}
TEST_F(HeaderTest, MjOptionFloatsOrdered) {
mjOption o;
std::vector<std::pair<const void*, const char*>> floats;
#define X(type, name) \
floats.push_back({static_cast<const void*>(&o.name), #name});
MJOPTION_FLOATS
#undef X
CheckAddressOrdering(floats, "MJOPTION_FLOATS");
}
TEST_F(HeaderTest, MjOptionVectorsOrdered) {
mjOption o;
std::vector<std::pair<const void*, const char*>> vectors;
#define X(name, dim) \
vectors.push_back({static_cast<const void*>(&o.name), #name});
MJOPTION_VECTORS
#undef X
CheckAddressOrdering(vectors, "MJOPTION_VECTORS");
}
TEST_F(HeaderTest, MjModelIntsOrdered) {
mjModel m;
std::vector<std::pair<const void*, const char*>> ints;
#define X(name) ints.push_back({static_cast<const void*>(&m.name), #name});
MJMODEL_INTS
#undef X
CheckAddressOrdering(ints, "MJMODEL_INT");
}
TEST_F(HeaderTest, MjModelPointersOrdered) {
mjModel m;
std::vector<std::pair<const void*, const char*>> pointers;
#define X(type, name, dim1, dim2) \
pointers.push_back({static_cast<const void*>(&m.name), #name});
#define XNV X
MJMODEL_POINTERS
#undef XNV
#undef X
CheckAddressOrdering(pointers, "MJMODEL_POINTER");
}
TEST_F(HeaderTest, MjDataPointersOrdered) {
mjData d;
std::vector<std::pair<const void*, const char*>> pointers;
#define X(type, name, dim1, dim2) \
pointers.push_back({static_cast<const void*>(&d.name), #name});
#define XNV X
MJDATA_POINTERS
#undef XNV
#undef X
CheckAddressOrdering(pointers, "mjData pointer");
}
TEST_F(HeaderTest, MjDataArenaPointersSolverOrdered) {
mjData d;
std::vector<std::pair<const void*, const char*>> pointers;
#define X(type, name, dim1, dim2) \
pointers.push_back({static_cast<const void*>(&d.name), #name});
#define XNV X
#undef MJ_D
#define MJ_D(n) 0
MJDATA_ARENA_POINTERS_SOLVER
#undef MJ_D
#define MJ_D(n) n
#undef XNV
#undef X
CheckAddressOrdering(pointers, "MJDATA_ARENA_POINTERS_SOLVER");
}
TEST_F(HeaderTest, MjDataArenaPointersDualOrdered) {
mjData d;
std::vector<std::pair<const void*, const char*>> pointers;
#define X(type, name, dim1, dim2) \
pointers.push_back({static_cast<const void*>(&d.name), #name});
#define XNV X
#undef MJ_D
#define MJ_D(n) 0
MJDATA_ARENA_POINTERS_DUAL
#undef MJ_D
#define MJ_D(n) n
#undef XNV
#undef X
CheckAddressOrdering(pointers, "MJDATA_ARENA_POINTERS_DUAL");
}
TEST_F(HeaderTest, MjDataArenaPointersIslandOrdered) {
mjData d;
std::vector<std::pair<const void*, const char*>> pointers;
#define X(type, name, dim1, dim2) \
pointers.push_back({static_cast<const void*>(&d.name), #name});
#define XNV X
#undef MJ_D
#define MJ_D(n) 0
MJDATA_ARENA_POINTERS_ISLAND
#undef MJ_D
#define MJ_D(n) n
#undef XNV
#undef X
CheckAddressOrdering(pointers, "MJDATA_ARENA_POINTERS_ISLAND");
}
TEST_F(HeaderTest, MjDataScalarsOrdered) {
mjData d;
std::vector<std::pair<const void*, const char*>> scalars;
#define X(type, name) \
scalars.push_back({static_cast<const void*>(&d.name), #name});
MJDATA_SCALAR
#undef X
CheckAddressOrdering(scalars, "mjData scalar");
}
TEST_F(HeaderTest, MjDataVectorsOrdered) {
mjData d;
std::vector<std::pair<const void*, const char*>> vectors;
#define X(type, name, dim1, dim2) \
vectors.push_back({static_cast<const void*>(&d.name), #name});
MJDATA_VECTOR
#undef X
CheckAddressOrdering(vectors, "mjData vector");
}
} // namespace
} // namespace mujoco