Skip to content

Commit 79afaba

Browse files
DeepMind Lab Teamtkoeppe
DeepMind Lab Team
authored andcommitted
[tests] Testing the diversty of generated mazes.
Testing the distribution of random mazes for two different mixer seeds, in the process validating the amount of overlaps remains below a 1% threshold.
1 parent 5cff454 commit 79afaba

File tree

5 files changed

+204
-3
lines changed

5 files changed

+204
-3
lines changed

Diff for: deepmind/engine/BUILD

+2-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ cc_library(
200200

201201
cc_test(
202202
name = "lua_maze_generation_test",
203-
size = "small",
203+
size = "large",
204204
srcs = ["lua_maze_generation_test.cc"],
205205
tags = ["manual"], # Platform specific tests.
206206
deps = [
@@ -210,6 +210,7 @@ cc_test(
210210
"//deepmind/lua:call",
211211
"//deepmind/lua:n_results_or_test_util",
212212
"//deepmind/lua:push_script",
213+
"//deepmind/lua:table_ref",
213214
"//deepmind/lua:vm_test_util",
214215
"@com_google_googletest//:gtest_main",
215216
],

Diff for: deepmind/engine/lua_maze_generation_test.cc

+68-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "deepmind/lua/call.h"
3030
#include "deepmind/lua/n_results_or_test_util.h"
3131
#include "deepmind/lua/push_script.h"
32+
#include "deepmind/lua/table_ref.h"
3233
#include "deepmind/lua/vm_test_util.h"
3334

3435
namespace deepmind {
@@ -45,13 +46,19 @@ class LuaMazeGenerationTest : public lua::testing::TestWithVm {
4546
vm()->AddCModuleToSearchers(
4647
"dmlab.system.maze_generation", &lua::Bind<LuaMazeGeneration::Require>,
4748
{reinterpret_cast<void*>(static_cast<std::uintptr_t>(0))});
49+
vm()->AddCModuleToSearchers(
50+
"dmlab.system.maze_generation1", &lua::Bind<LuaMazeGeneration::Require>,
51+
{reinterpret_cast<void*>(static_cast<std::uintptr_t>(1))});
4852
LuaRandom::Register(L);
4953
vm()->AddCModuleToSearchers(
5054
"dmlab.system.sys_random", &lua::Bind<LuaRandom::Require>,
51-
{&prbg_, reinterpret_cast<void*>(static_cast<std::uintptr_t>(0))});
55+
{&prbg_[0], reinterpret_cast<void*>(static_cast<std::uintptr_t>(0))});
56+
vm()->AddCModuleToSearchers(
57+
"dmlab.system.sys_random1", &lua::Bind<LuaRandom::Require>,
58+
{&prbg_[1], reinterpret_cast<void*>(static_cast<std::uintptr_t>(1))});
5259
}
5360

54-
std::mt19937_64 prbg_;
61+
std::mt19937_64 prbg_[2];
5562
};
5663

5764
constexpr char kCreateMaze[] = R"(
@@ -468,6 +475,65 @@ TEST_F(LuaMazeGenerationTest, CreateRandomMazeNoRandom) {
468475
ASSERT_FALSE(lua::Call(L, 0).ok());
469476
}
470477

478+
constexpr int kRandomMazeSeedCount = 10000;
479+
constexpr char kCreateRandomMazes[] = R"(
480+
local seed, maps, vers = ...
481+
local sys_random = require('dmlab.system.sys_random' .. vers)
482+
local maze_generation = require('dmlab.system.maze_generation' .. vers)
483+
sys_random:seed(seed)
484+
local maze = maze_generation.randomMazeGeneration{
485+
random = sys_random,
486+
width = 17,
487+
height = 17,
488+
extraConnectionProbability = 0.0,
489+
hasDoors = false,
490+
roomCount = 4,
491+
maxRooms = 4,
492+
roomMaxSize = 5,
493+
roomMinSize = 3
494+
}
495+
local key = maze:entityLayer()
496+
local count = maps[key] or 0
497+
maps[key] = count + 1
498+
)";
499+
500+
TEST_F(LuaMazeGenerationTest, CreateRandomMazes) {
501+
auto maps = lua::TableRef::Create(L);
502+
lua::PushScript(L, kCreateRandomMazes, sizeof(kCreateRandomMazes) - 1,
503+
"kCreateRandomMazes");
504+
for (int i = 0; i < kRandomMazeSeedCount; ++i) {
505+
LOG(INFO) << "Phase 1: step " << i + 1 << " out of "
506+
<< kRandomMazeSeedCount;
507+
lua_pushvalue(L, -1);
508+
lua::Push(L, i);
509+
lua::Push(L, maps);
510+
lua::Push(L, "");
511+
ASSERT_THAT(lua::Call(L, 3), IsOkAndHolds(0));
512+
}
513+
const auto mixer_seed_0_maps = maps.KeyCount();
514+
const auto mixer_seed_0_repeat_ratio =
515+
(kRandomMazeSeedCount - mixer_seed_0_maps) /
516+
static_cast<float>(kRandomMazeSeedCount);
517+
ASSERT_GE(mixer_seed_0_repeat_ratio, 0.0);
518+
ASSERT_LE(mixer_seed_0_repeat_ratio, 0.01);
519+
for (int i = 0; i < kRandomMazeSeedCount; ++i) {
520+
LOG(INFO) << "Phase 2: step " << i + 1 << " out of "
521+
<< kRandomMazeSeedCount;
522+
lua_pushvalue(L, -1);
523+
lua::Push(L, i);
524+
lua::Push(L, maps);
525+
lua::Push(L, "1");
526+
ASSERT_THAT(lua::Call(L, 3), IsOkAndHolds(0));
527+
}
528+
const auto mixer_seed_1_maps = maps.KeyCount() - mixer_seed_0_maps;
529+
const auto mixer_seed_1_repeat_ratio =
530+
(kRandomMazeSeedCount - mixer_seed_1_maps) /
531+
static_cast<float>(kRandomMazeSeedCount);
532+
ASSERT_GE(mixer_seed_1_repeat_ratio, 0.0);
533+
ASSERT_LE(mixer_seed_1_repeat_ratio, 0.01);
534+
lua_pop(L, 1);
535+
}
536+
471537
constexpr char kVisitRandomPath[] = R"(
472538
local sys_random = require 'dmlab.system.sys_random'
473539
local maze_generation = require 'dmlab.system.maze_generation'

Diff for: game_scripts/levels/tests/maze_generation_test.lua

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
--[[ Copyright (C) 2018 Google Inc.
2+
3+
This program is free software; you can redistribute it and/or modify
4+
it under the terms of the GNU General Public License as published by
5+
the Free Software Foundation; either version 2 of the License, or
6+
(at your option) any later version.
7+
8+
This program is distributed in the hope that it will be useful,
9+
but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
GNU General Public License for more details.
12+
13+
You should have received a copy of the GNU General Public License along
14+
with this program; if not, write to the Free Software Foundation, Inc.,
15+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16+
]]
17+
18+
local custom_observations = require 'decorators.custom_observations'
19+
local debug_observations = require 'decorators.debug_observations'
20+
local make_map = require 'common.make_map'
21+
local map_maker = require 'dmlab.system.map_maker'
22+
local maze_generation = require 'dmlab.system.maze_generation'
23+
local random = require 'common.random'
24+
25+
local randomMap = random(map_maker:randomGen())
26+
27+
local api = {}
28+
29+
function api:nextMap()
30+
return api._map
31+
end
32+
33+
function api:start(episode, seed)
34+
local mapName = 'maze'
35+
random:seed(seed)
36+
randomMap:seed(seed)
37+
api._maze = maze_generation.randomMazeGeneration{
38+
seed = seed,
39+
width = 17,
40+
height = 17,
41+
maxRooms = 4,
42+
roomMaxSize = 5,
43+
roomMinSize = 3,
44+
extraConnectionProbability = 0.0,
45+
}
46+
api._map = make_map.makeMap{
47+
mapName = mapName,
48+
mapEntityLayer = api._maze:entityLayer(),
49+
mapVariationsLayer = api._maze:variationsLayer(),
50+
useSkybox = true,
51+
}
52+
debug_observations.setMaze(api._maze)
53+
end
54+
55+
custom_observations.decorate(api)
56+
57+
return api

Diff for: python/tests/BUILD

+9
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,12 @@ py_test(
139139
data = ["//:deepmind_lab.so"],
140140
imports = ["python"],
141141
)
142+
143+
py_test(
144+
name = "maze_generation_test",
145+
size = "enormous",
146+
srcs = ["maze_generation_test.py"],
147+
tags = ["manual"],
148+
data = ["//:deepmind_lab.so"],
149+
imports = ["python"],
150+
)

Diff for: python/tests/maze_generation_test.py

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Copyright 2018 Google Inc.
2+
#
3+
# This program is free software; you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License as published by
5+
# the Free Software Foundation; either version 2 of the License, or
6+
# (at your option) any later version.
7+
#
8+
# This program is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU General Public License along
14+
# with this program; if not, write to the Free Software Foundation, Inc.,
15+
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16+
from __future__ import absolute_import
17+
from __future__ import division
18+
from __future__ import print_function
19+
20+
import os
21+
import unittest
22+
import numpy as np
23+
24+
import deepmind_lab
25+
26+
MAZE_LAYOUT_OBSERVATION = 'DEBUG.MAZE.LAYOUT'
27+
MAZE_LAYOUT_TRIALS = 50
28+
29+
30+
class MazeGenerationTest(unittest.TestCase):
31+
32+
def test_maze_layout_spread(self):
33+
layouts = set()
34+
for i in xrange(MAZE_LAYOUT_TRIALS):
35+
print('phase 1: trial {} out of {}'.format(i+1, MAZE_LAYOUT_TRIALS))
36+
env = deepmind_lab.Lab(
37+
'tests/maze_generation_test', [MAZE_LAYOUT_OBSERVATION], config={})
38+
env.reset(seed=i+1)
39+
layouts.add(env.observations()[MAZE_LAYOUT_OBSERVATION])
40+
num_layouts = len(layouts)
41+
self.assertTrue(np.isclose(num_layouts, MAZE_LAYOUT_TRIALS))
42+
for i in xrange(MAZE_LAYOUT_TRIALS):
43+
print('phase 2: trial {} out of {}'.format(i+1, MAZE_LAYOUT_TRIALS))
44+
env = deepmind_lab.Lab(
45+
'tests/maze_generation_test', [MAZE_LAYOUT_OBSERVATION],
46+
config={
47+
'mixerSeed': '0',
48+
})
49+
env.reset(seed=i+1)
50+
layouts.add(env.observations()[MAZE_LAYOUT_OBSERVATION])
51+
self.assertEqual(len(layouts), num_layouts)
52+
for i in xrange(MAZE_LAYOUT_TRIALS):
53+
print('phase 3: trial {} out of {}'.format(i+1, MAZE_LAYOUT_TRIALS))
54+
env = deepmind_lab.Lab(
55+
'tests/maze_generation_test', [MAZE_LAYOUT_OBSERVATION],
56+
config={
57+
'mixerSeed': '1',
58+
})
59+
env.reset(seed=i+1)
60+
layouts.add(env.observations()[MAZE_LAYOUT_OBSERVATION])
61+
self.assertTrue(np.isclose(len(layouts) - num_layouts, MAZE_LAYOUT_TRIALS))
62+
63+
if __name__ == '__main__':
64+
if 'TEST_SRCDIR' in os.environ:
65+
deepmind_lab.set_runfiles_path(
66+
os.path.join(os.environ['TEST_SRCDIR'],
67+
'org_deepmind_lab'))
68+
unittest.main()

0 commit comments

Comments
 (0)