Skip to content

Commit

Permalink
Don't return ndarray with empty shape through named indexers.
Browse files Browse the repository at this point in the history
NumPy arrays with an empty shape cannot be assigned via the usual syntax.

Fixes: #238.
Related: #237.
PiperOrigin-RevId: 441265437
Change-Id: Ib0de22c83f9babe9a97682dc5a32660c198ad68c
  • Loading branch information
saran-t committed Apr 12, 2022
1 parent 0d5d1f5 commit 55c1c91
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 1 deletion.
21 changes: 20 additions & 1 deletion python/mujoco/bindings_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
<body>
<inertial pos="0 0 0" mass="1" diaginertia="1 1 1"/>
<site pos="0 0 -1" name="mysite" type="sphere"/>
<joint type="hinge" axis="0 1 0"/>
<joint name="myhinge" type="hinge" axis="0 1 0"/>
</body>
<body>
<inertial pos="0 0 0" mass="1" diaginertia="1 1 1"/>
Expand All @@ -51,6 +51,9 @@
<geom type="sphere" size="0.1"/>
</body>
</worldbody>
<actuator>
<position name="myactuator" joint="myhinge"/>
</actuator>
</mujoco>
"""

Expand Down Expand Up @@ -144,6 +147,22 @@ def test_array_keeps_struct_alive(self):
del qpos_spring
self.assertEqual(sys.getrefcount(capsule) - base_refcount, 1)

def test_named_indexing_actuator_ctrl(self):
actuator_id = mujoco.mj_name2id(
self.model, mujoco.mjtObj.mjOBJ_ACTUATOR, 'myactuator')
self.assertIs(self.data.actuator('myactuator'),
self.data.actuator(actuator_id))
self.assertIs(self.data.actuator('myactuator').ctrl,
self.data.actuator(actuator_id).ctrl)
self.assertEqual(self.data.actuator('myactuator').ctrl.shape, (1,))

# Test that the indexer is returning a view into the underlying struct.
ctrl_from_indexer = self.data.actuator('myactuator').ctrl
self.data.ctrl[actuator_id] = 5
np.testing.assert_array_equal(ctrl_from_indexer, [5])
self.data.actuator('myactuator').ctrl = 7
np.testing.assert_array_equal(self.data.ctrl[actuator_id], [7])

def test_named_indexing_geom_size(self):
box_id = mujoco.mj_name2id(self.model, mujoco.mjtObj.mjOBJ_GEOM, 'mybox')
self.assertIs(self.model.geom('mybox'), self.model.geom(box_id))
Expand Down
5 changes: 5 additions & 0 deletions python/mujoco/indexers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ py::array_t<T> MakeArray(T* base_ptr, int index, std::vector<int>&& shape,
offset = m.tuple_adr[index];
shape.insert(shape.begin(), m.tuple_size[index]);
} else {
// Do not return a NumPy array with shape () since these aren't very nice
// to work with. Instead, always return singleton arrays with shape (1,).
if (shape.empty()) {
shape.push_back(1);
}
int size = 1;
for (int s : shape) {
size *= s;
Expand Down

0 comments on commit 55c1c91

Please sign in to comment.