Skip to content

Commit d228035

Browse files
committed
Add gen_grid utility to build GridMDP grids of arbitrary size (#984)
Add gen_grid(n_rows, n_cols, terminals, main_reward, terminal_rewards, block_coords) to mdp.py, which produces a list-of-lists grid in the format GridMDP accepts, so larger grid worlds can be created without writing the grid by hand. Based on the helper proposed and approved in #984, with a modernized signature (tuple defaults instead of mutable list defaults). The default reproduces the canonical 4x3 Figure 17.1 grid. Add a test.
1 parent e38f72c commit d228035

2 files changed

Lines changed: 38 additions & 0 deletions

File tree

mdp.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,24 @@ def to_arrows(self, policy):
188188
return self.to_grid({s: chars[a] for (s, a) in policy.items()})
189189

190190

191+
def gen_grid(n_rows=3, n_cols=4, terminals=((3, 2), (3, 1)), main_reward=-0.04,
192+
terminal_rewards=(1, -1), block_coords=((1, 1),)):
193+
"""Generate a grid (list of lists of rewards) of arbitrary size in the format
194+
accepted by GridMDP, e.g. GridMDP(gen_grid(...), terminals=[...]).
195+
n_rows, n_cols: grid dimensions.
196+
terminals: (x, y) coordinates of the terminal cells.
197+
main_reward: reward for every non-terminal, non-blocked cell.
198+
terminal_rewards: reward for each cell in terminals (paired by position).
199+
block_coords: (x, y) coordinates of obstacles (set to None / unreachable)."""
200+
grid = [[main_reward] * n_cols for _ in range(n_rows)]
201+
for (x, y), reward in zip(terminals, terminal_rewards):
202+
grid[y][x] = reward
203+
for x, y in block_coords:
204+
grid[y][x] = None
205+
grid.reverse() # row 0 at the bottom, matching GridMDP's convention
206+
return grid
207+
208+
191209
# ______________________________________________________________________________
192210

193211

tests/test_mdp.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@
2222
terminals=[(2, 2), (3, 2), (0, 4), (5, 0)])
2323

2424

25+
def test_gen_grid():
26+
# the default reproduces the canonical 4x3 Figure 17.1 grid
27+
assert gen_grid() == [[-0.04, -0.04, -0.04, 1],
28+
[-0.04, None, -0.04, -1],
29+
[-0.04, -0.04, -0.04, -0.04]]
30+
# and feeds GridMDP to the same optimal policy as the shipped environment
31+
generated = GridMDP(gen_grid(), terminals=[(3, 2), (3, 1)])
32+
assert (best_policy(generated, value_iteration(generated, .001)) ==
33+
best_policy(sequential_decision_environment,
34+
value_iteration(sequential_decision_environment, .001)))
35+
# an arbitrary larger world places terminals and obstacles correctly
36+
big = gen_grid(n_rows=5, n_cols=5, terminals=[(4, 3), (4, 2)], main_reward=0.04,
37+
terminal_rewards=[1, -1], block_coords=[(0, 3), (2, 3), (3, 1)])
38+
assert big == [[0.04, 0.04, 0.04, 0.04, 0.04],
39+
[None, 0.04, None, 0.04, 1],
40+
[0.04, 0.04, 0.04, 0.04, -1],
41+
[0.04, 0.04, 0.04, None, 0.04],
42+
[0.04, 0.04, 0.04, 0.04, 0.04]]
43+
44+
2545
def test_value_iteration():
2646
# exact float equality on the value function is brittle across numpy/BLAS
2747
# versions (the values can differ in the last decimal), so compare with a

0 commit comments

Comments
 (0)