Skip to content

Commit 31d1415

Browse files
authored
Add full non-BabyAI MiniGrid support (#356)
## Description This PR expands EnvPool's MiniGrid support from the `Empty` family to the full non-BabyAI `MiniGrid-*` set in `minigrid==3.0.0`, using a pure C++ backend. It adds the missing MiniGrid task implementations, mission plumbing, Python registrations, per-environment align coverage, deterministic coverage, and documentation updates. It also fixes a couple of header-level ODR/link issues that surfaced once the larger MiniGrid binding target was linked together. ## Motivation and Context EnvPool currently exposes only a small subset of upstream MiniGrid registrations. This change brings the package much closer to upstream coverage without routing task logic back through Python. - [ ] I have raised an issue to propose this change ([required](https://envpool.readthedocs.io/en/latest/pages/contributing.html) for new features and bug fixes) ## Types of changes - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds core functionality) - [x] New environment (non-breaking change which adds 3rd-party environment) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation (update in the documentation) - [ ] Example (update in the folder of example) ## Implemented Tasks - [x] Add pure C++ implementations and registrations for all non-BabyAI `MiniGrid-*` environments in `minigrid==3.0.0`. - [x] Add MiniGrid align and deterministic coverage so every registered environment is exercised against upstream behavior. - [x] Update MiniGrid documentation and `make_test` coverage for the expanded environment set. ## Checklist - [ ] I have read the [CONTRIBUTION](https://envpool.readthedocs.io/en/latest/pages/contributing.html) guide (**required**) - [x] My change requires a change to the documentation. - [x] I have updated the tests accordingly (*required for a bug fix or a new feature*). - [x] I have updated the documentation accordingly. - [ ] I have reformatted the code using `make format` (**required**) - [ ] I have checked the code using `make lint` (**required**) - [x] I have ensured `make bazel-test` pass. (**required**) ## Validation Notes - `make bazel-test` passed on `dev`. - `make lint` is still running on `dev`; at PR creation time it is down to the final clang-tidy pass for `envpool/minigrid/impl/minigrid_env.cc`.
1 parent 411294a commit 31d1415

18 files changed

Lines changed: 3705 additions & 420 deletions

.clang-tidy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,5 @@ CheckOptions:
5353
- { key: readability-identifier-naming.StructCase, value: CamelCase }
5454
- { key: readability-identifier-naming.UnionCase, value: CamelCase }
5555
- { key: readability-identifier-naming.VariableCase, value: lower_case }
56-
WarningsAsErrors: '*,-clang-diagnostic-deprecated-declarations'
56+
WarningsAsErrors: '*,-clang-diagnostic-bitwise-instead-of-logical,-clang-diagnostic-deprecated-declarations'
5757
HeaderFilterRegex: '/envpool/'

docs/env/minigrid.rst

Lines changed: 238 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,245 @@ Minigrid
44
We use ``minigrid==3.0.0`` as the codebase.
55
See https://github.com/Farama-Foundation/Minigrid/tree/v3.0.0
66

7+
EnvPool supports all non-BabyAI ``MiniGrid-*`` environments registered by
8+
upstream ``minigrid==3.0.0``. That is 75 task IDs in total. ``BabyAI-*``
9+
environments are not implemented.
10+
11+
12+
Options
13+
-------
14+
15+
* ``task_id (str)``: see the available tasks below;
16+
* ``num_envs (int)``: how many environments you would like to create;
17+
* ``batch_size (int)``: the expected batch size for return result, default to
18+
``num_envs``;
19+
* ``num_threads (int)``: the maximum thread number for executing the actual
20+
``env.step``, default to ``batch_size``;
21+
* ``seed (int | Sequence[int])``: the environment seed. When a sequence is
22+
provided, it must contain exactly one seed per environment. Default to
23+
``42``;
24+
* ``max_episode_steps (int)``: the maximum number of steps for one episode.
25+
The default value depends on ``task_id`` and follows the upstream MiniGrid
26+
registration.
27+
28+
29+
Observation Space
30+
-----------------
31+
32+
Each MiniGrid observation contains:
33+
34+
* ``obs["image"]``: a ``(agent_view_size, agent_view_size, 3)`` uint8 tensor
35+
using the standard MiniGrid object/color/state encoding;
36+
* ``obs["direction"]``: the agent direction in ``[0, 3]``;
37+
* ``obs["mission"]``: a fixed-size uint8 byte buffer with length 96;
38+
* ``info["agent_pos"]``: the agent position in the full grid;
39+
* ``info["mission_id"]``: a stable integer ID when the mission comes from a
40+
finite canonical set, otherwise ``-1``.
41+
42+
Use ``envpool.minigrid.decode_mission(...)`` to decode the mission buffer back
43+
to a Python string:
44+
45+
.. code-block:: python
46+
47+
import envpool
48+
from envpool.minigrid import decode_mission
49+
50+
env = envpool.make_gymnasium("MiniGrid-DoorKey-8x8-v0", num_envs=1)
51+
obs, info = env.reset()
52+
mission = decode_mission(obs["mission"][0])
53+
54+
55+
Action Space
56+
------------
57+
58+
Most tasks expose the standard MiniGrid discrete action space with values in
59+
``[0, 6]``:
60+
61+
* ``0``: turn left
62+
* ``1``: turn right
63+
* ``2``: move forward
64+
* ``3``: pick up an object
65+
* ``4``: drop an object
66+
* ``5``: toggle / interact
67+
* ``6``: done
68+
69+
``MiniGrid-Dynamic-Obstacles-*`` follows upstream and only uses the movement
70+
subset ``[0, 2]``.
71+
72+
73+
Available Tasks
74+
---------------
775

876
Empty
9-
-----
77+
~~~~~
78+
79+
* ``MiniGrid-Empty-5x5-v0``
80+
* ``MiniGrid-Empty-Random-5x5-v0``
81+
* ``MiniGrid-Empty-6x6-v0``
82+
* ``MiniGrid-Empty-Random-6x6-v0``
83+
* ``MiniGrid-Empty-8x8-v0``
84+
* ``MiniGrid-Empty-16x16-v0``
85+
86+
DoorKey
87+
~~~~~~~
88+
89+
* ``MiniGrid-DoorKey-5x5-v0``
90+
* ``MiniGrid-DoorKey-6x6-v0``
91+
* ``MiniGrid-DoorKey-8x8-v0``
92+
* ``MiniGrid-DoorKey-16x16-v0``
93+
94+
DistShift
95+
~~~~~~~~~
96+
97+
* ``MiniGrid-DistShift1-v0``
98+
* ``MiniGrid-DistShift2-v0``
99+
100+
Crossing
101+
~~~~~~~~
102+
103+
* ``MiniGrid-LavaCrossingS9N1-v0``
104+
* ``MiniGrid-LavaCrossingS9N2-v0``
105+
* ``MiniGrid-LavaCrossingS9N3-v0``
106+
* ``MiniGrid-LavaCrossingS11N5-v0``
107+
* ``MiniGrid-SimpleCrossingS9N1-v0``
108+
* ``MiniGrid-SimpleCrossingS9N2-v0``
109+
* ``MiniGrid-SimpleCrossingS9N3-v0``
110+
* ``MiniGrid-SimpleCrossingS11N5-v0``
111+
112+
LavaGap
113+
~~~~~~~
114+
115+
* ``MiniGrid-LavaGapS5-v0``
116+
* ``MiniGrid-LavaGapS6-v0``
117+
* ``MiniGrid-LavaGapS7-v0``
118+
119+
Dynamic Obstacles
120+
~~~~~~~~~~~~~~~~~
121+
122+
* ``MiniGrid-Dynamic-Obstacles-5x5-v0``
123+
* ``MiniGrid-Dynamic-Obstacles-Random-5x5-v0``
124+
* ``MiniGrid-Dynamic-Obstacles-6x6-v0``
125+
* ``MiniGrid-Dynamic-Obstacles-Random-6x6-v0``
126+
* ``MiniGrid-Dynamic-Obstacles-8x8-v0``
127+
* ``MiniGrid-Dynamic-Obstacles-16x16-v0``
128+
129+
Fetch
130+
~~~~~
131+
132+
* ``MiniGrid-Fetch-5x5-N2-v0``
133+
* ``MiniGrid-Fetch-6x6-N2-v0``
134+
* ``MiniGrid-Fetch-8x8-N3-v0``
135+
136+
FourRooms
137+
~~~~~~~~~
138+
139+
* ``MiniGrid-FourRooms-v0``
140+
141+
GoToDoor
142+
~~~~~~~~
143+
144+
* ``MiniGrid-GoToDoor-5x5-v0``
145+
* ``MiniGrid-GoToDoor-6x6-v0``
146+
* ``MiniGrid-GoToDoor-8x8-v0``
147+
148+
GoToObject
149+
~~~~~~~~~~
150+
151+
* ``MiniGrid-GoToObject-6x6-N2-v0``
152+
* ``MiniGrid-GoToObject-8x8-N2-v0``
153+
154+
KeyCorridor
155+
~~~~~~~~~~~
156+
157+
* ``MiniGrid-KeyCorridorS3R1-v0``
158+
* ``MiniGrid-KeyCorridorS3R2-v0``
159+
* ``MiniGrid-KeyCorridorS3R3-v0``
160+
* ``MiniGrid-KeyCorridorS4R3-v0``
161+
* ``MiniGrid-KeyCorridorS5R3-v0``
162+
* ``MiniGrid-KeyCorridorS6R3-v0``
163+
164+
LockedRoom
165+
~~~~~~~~~~
166+
167+
* ``MiniGrid-LockedRoom-v0``
168+
169+
Memory
170+
~~~~~~
171+
172+
* ``MiniGrid-MemoryS17Random-v0``
173+
* ``MiniGrid-MemoryS13Random-v0``
174+
* ``MiniGrid-MemoryS13-v0``
175+
* ``MiniGrid-MemoryS11-v0``
176+
* ``MiniGrid-MemoryS9-v0``
177+
* ``MiniGrid-MemoryS7-v0``
178+
179+
MultiRoom
180+
~~~~~~~~~
181+
182+
* ``MiniGrid-MultiRoom-N2-S4-v0``
183+
* ``MiniGrid-MultiRoom-N4-S5-v0``
184+
* ``MiniGrid-MultiRoom-N6-v0``
185+
186+
ObstructedMaze
187+
~~~~~~~~~~~~~~
188+
189+
* ``MiniGrid-ObstructedMaze-1Dl-v0``
190+
* ``MiniGrid-ObstructedMaze-1Dlh-v0``
191+
* ``MiniGrid-ObstructedMaze-1Dlhb-v0``
192+
* ``MiniGrid-ObstructedMaze-2Dl-v0``
193+
* ``MiniGrid-ObstructedMaze-2Dlh-v0``
194+
* ``MiniGrid-ObstructedMaze-2Dlhb-v0``
195+
* ``MiniGrid-ObstructedMaze-1Q-v0``
196+
* ``MiniGrid-ObstructedMaze-2Q-v0``
197+
* ``MiniGrid-ObstructedMaze-Full-v0``
198+
* ``MiniGrid-ObstructedMaze-2Dlhb-v1``
199+
* ``MiniGrid-ObstructedMaze-1Q-v1``
200+
* ``MiniGrid-ObstructedMaze-2Q-v1``
201+
* ``MiniGrid-ObstructedMaze-Full-v1``
202+
203+
Playground
204+
~~~~~~~~~~
205+
206+
* ``MiniGrid-Playground-v0``
207+
208+
PutNear
209+
~~~~~~~
210+
211+
* ``MiniGrid-PutNear-6x6-N2-v0``
212+
* ``MiniGrid-PutNear-8x8-N3-v0``
213+
214+
RedBlueDoors
215+
~~~~~~~~~~~~
216+
217+
* ``MiniGrid-RedBlueDoors-6x6-v0``
218+
* ``MiniGrid-RedBlueDoors-8x8-v0``
219+
220+
Unlock
221+
~~~~~~
222+
223+
* ``MiniGrid-Unlock-v0``
224+
225+
UnlockPickup
226+
~~~~~~~~~~~~
227+
228+
* ``MiniGrid-UnlockPickup-v0``
229+
230+
BlockedUnlockPickup
231+
~~~~~~~~~~~~~~~~~~~
232+
233+
* ``MiniGrid-BlockedUnlockPickup-v0``
234+
235+
236+
Validation
237+
----------
10238

11-
Registered Configurations
239+
All registered MiniGrid task IDs are covered by:
12240

13-
- `MiniGrid-Empty-5x5-v0`
14-
- `MiniGrid-Empty-Random-5x5-v0`
15-
- `MiniGrid-Empty-6x6-v0`
16-
- `MiniGrid-Empty-Random-6x6-v0`
17-
- `MiniGrid-Empty-8x8-v0`
18-
- `MiniGrid-Empty-16x16-v0`
241+
* ``//envpool/minigrid:minigrid_align_test`` for upstream behavioral
242+
alignment. ``Dynamic Obstacles`` is aligned by transition replay rather than
243+
by sharing the exact same RNG bitstream, because upstream NumPy uses
244+
``PCG64`` while EnvPool uses C++ ``mt19937``;
245+
* ``//envpool/minigrid:minigrid_deterministic_test`` for same-seed
246+
determinism;
247+
* ``//envpool:make_test`` for top-level construction coverage through the
248+
public ``envpool.make_*`` entry points.

docs/spelling_wordlist.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ bazel
1414
bazelisk
1515
buildifier
1616
addlicense
17+
BabyAI
18+
bitstream
1719
ruff
1820
envpool
1921
th

envpool/core/dict.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ std::vector<Array> MakeArray(const std::tuple<Spec...>& specs) {
307307
* Dynamic version of MakeArray.
308308
* Takes a vector of `ShapeSpec`.
309309
*/
310-
std::vector<Array> MakeArray(const std::vector<ShapeSpec>& specs) {
310+
inline std::vector<Array> MakeArray(const std::vector<ShapeSpec>& specs) {
311311
return {specs.begin(), specs.end()};
312312
}
313313

envpool/core/env_spec.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,18 @@
2323
#include "envpool/core/array.h"
2424
#include "envpool/core/dict.h"
2525

26-
auto common_config = MakeDict(
26+
inline auto common_config = MakeDict(
2727
"num_envs"_.Bind(1), "batch_size"_.Bind(0), "num_threads"_.Bind(0),
2828
"max_num_players"_.Bind(1), "thread_affinity_offset"_.Bind(-1),
2929
"base_path"_.Bind(std::string("envpool")), "seed"_.Bind(42),
3030
"env_seed"_.Bind(std::vector<int>{}), "gym_reset_return_info"_.Bind(false),
3131
"max_episode_steps"_.Bind(std::numeric_limits<int>::max()));
3232
// Note: this action order is hardcoded in async_envpool Send function
3333
// and env ParseAction function for performance
34-
auto common_action_spec = MakeDict("env_id"_.Bind(Spec<int>({})),
35-
"players.env_id"_.Bind(Spec<int>({-1})));
34+
inline auto common_action_spec = MakeDict(
35+
"env_id"_.Bind(Spec<int>({})), "players.env_id"_.Bind(Spec<int>({-1})));
3636
// Note: this state order is hardcoded in async_envpool Recv function
37-
auto common_state_spec =
37+
inline auto common_state_spec =
3838
MakeDict("info:env_id"_.Bind(Spec<int>({})),
3939
"info:players.env_id"_.Bind(Spec<int>({-1})),
4040
"elapsed_step"_.Bind(Spec<int>({})), "done"_.Bind(Spec<bool>({})),

envpool/core/xla_template.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ struct CustomCall {
6060
if (!handle) {
6161
return xla_ffi::Unexpected(handle.error());
6262
}
63+
// NOLINTNEXTLINE(performance-no-int-to-ptr)
6364
return reinterpret_cast<Class*>(
6465
static_cast<std::uintptr_t>(static_cast<std::int64_t>(*handle)));
6566
}

envpool/make_test.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from absl.testing import absltest
2222

2323
import envpool
24+
import envpool.minigrid.registration # noqa: F401
2425

2526

2627
class _MakeTest(absltest.TestCase):
@@ -120,8 +121,13 @@ def test_make_box2d(self) -> None:
120121
])
121122

122123
def test_make_minigrid(self) -> None:
123-
self.assertIn("MiniGrid-Empty-5x5-v0", envpool.list_all_envs())
124-
self.check_step(["MiniGrid-Empty-5x5-v0"])
124+
task_ids = sorted(
125+
task_id
126+
for task_id in envpool.list_all_envs()
127+
if task_id.startswith("MiniGrid-")
128+
)
129+
self.assertLen(task_ids, 75)
130+
self.check_step(task_ids)
125131

126132
def test_make_mujoco_gym(self) -> None:
127133
self.check_step([

envpool/minigrid/BUILD

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,16 @@ package(default_visibility = ["//visibility:public"])
2222
cc_library(
2323
name = "minigrid_env",
2424
srcs = [
25-
"impl/minigrid_empty_env.cc",
2625
"impl/minigrid_env.cc",
2726
],
2827
hdrs = [
29-
"empty.h",
30-
"impl/minigrid_empty_env.h",
28+
"minigrid.h",
3129
"impl/minigrid_env.h",
3230
"impl/utils.h",
3331
],
3432
deps = [
3533
"//envpool/core:async_envpool",
34+
"//envpool/core:py_envpool",
3635
],
3736
)
3837

@@ -49,7 +48,10 @@ py_library(
4948
name = "minigrid",
5049
srcs = ["__init__.py"],
5150
data = [":minigrid_envpool.so"],
52-
deps = ["//envpool/python:api"],
51+
deps = [
52+
"//envpool/python:api",
53+
requirement("numpy"),
54+
],
5355
)
5456

5557
py_library(

0 commit comments

Comments
 (0)