diff --git a/env_data/tests/test_env_loop.pkl b/env_data/tests/test_env_loop.pkl new file mode 100644 index 0000000000000000000000000000000000000000..dd1df2a1b9982587b45a5bd802168e0820401f79 Binary files /dev/null and b/env_data/tests/test_env_loop.pkl differ diff --git a/flatland/envs/malfunction_generators.py b/flatland/envs/malfunction_generators.py index f8d1bc66b4f9a66c9657902aaa67ae42c9fd8c71..99082ddd764c62e16ad6b71bef7901333732cc4b 100644 --- a/flatland/envs/malfunction_generators.py +++ b/flatland/envs/malfunction_generators.py @@ -6,7 +6,7 @@ import numpy as np from numpy.random.mtrand import RandomState from flatland.envs.agent_utils import EnvAgent, RailAgentStatus -from flatland.envs import persistence +from flatland.envs import persistence Malfunction = NamedTuple('Malfunction', [('num_broken_steps', int)]) MalfunctionParameters = NamedTuple('MalfunctionParameters', @@ -25,7 +25,7 @@ def _malfunction_prob(rate: float) -> float: if rate <= 0: return 0. else: - return 1 - np.exp(- (1 / rate)) + return 1 - np.exp(-rate) def malfunction_from_file(filename: str, load_from_package=None) -> Tuple[MalfunctionGenerator, MalfunctionProcessData]: @@ -42,7 +42,7 @@ def malfunction_from_file(filename: str, load_from_package=None) -> Tuple[Malfun """ # with open(filename, "rb") as file_in: # load_data = file_in.read() - + # if filename.endswith("mpk"): # data = msgpack.unpackb(load_data, use_list=False, encoding='utf-8') # elif filename.endswith("pkl"): @@ -52,7 +52,7 @@ def malfunction_from_file(filename: str, load_from_package=None) -> Tuple[Malfun if "malfunction" in env_dict: env_dict['malfunction'] = oMPD = MalfunctionProcessData._make(env_dict['malfunction']) else: - oMPD=None + oMPD = None if oMPD is not None: # Mean malfunction in number of time steps mean_malfunction_rate = oMPD.malfunction_rate diff --git a/flatland/utils/editor.py b/flatland/utils/editor.py index d0f36a0deefb502017df1704a515ff4fda436a92..ff99ec08a35c26f6fc2b4bd54f9349c3963840ef 100644 --- a/flatland/utils/editor.py +++ b/flatland/utils/editor.py @@ -14,13 +14,13 @@ from flatland.envs.agent_utils import EnvAgent from flatland.envs.observations import TreeObsForRailEnv from flatland.envs.rail_env import RailEnv from flatland.envs.rail_generators import complex_rail_generator, empty_rail_generator, random_rail_generator - +from flatland.envs.persistence import RailEnvPersister class EditorMVC(object): """ EditorMVC - a class to encompass and assemble the Jupyter Editor Model-View-Controller. """ - def __init__(self, env=None, sGL="PIL", env_filename="temp.mpk"): + def __init__(self, env=None, sGL="PIL", env_filename="temp.pkl"): """ Create an Editor MVC assembly around a railenv, or create one if None. """ if env is None: @@ -383,7 +383,7 @@ class Controller(object): class EditorModel(object): - def __init__(self, env, env_filename="temp.mpk"): + def __init__(self, env, env_filename="temp.pkl"): self.view = None self.env = env self.regen_size_width = 10 @@ -624,12 +624,13 @@ class EditorModel(object): def load(self): if os.path.exists(self.env_filename): self.log("load file: ", self.env_filename) - self.env.load(self.env_filename) + #self.env.load(self.env_filename) + RailEnvPersister.load(self.env, self.env_filename) if not self.regen_size_height == self.env.height or not self.regen_size_width == self.env.width: self.regen_size_height = self.env.height self.regen_size_width = self.env.width self.regenerate(None, 0, self.env) - self.env.load(self.env_filename) + RailEnvPersister.load(self.env, self.env_filename) self.env.reset_agents() self.env.reset(False, False) @@ -642,7 +643,8 @@ class EditorModel(object): def save(self): self.log("save to ", self.env_filename, " working dir: ", os.getcwd()) - self.env.save(self.env_filename) + #self.env.save(self.env_filename) + RailEnvPersister.save(self.env, self.env_filename) def save_image(self): self.view.oRT.gl.save_image('frame_{:04d}.bmp'.format(self.save_image_count)) diff --git a/tests/test_flatland_envs_rail_env.py b/tests/test_flatland_envs_rail_env.py index 68f0e089a82934278397b4d637e0ae42a9b61b58..0c865502f94b624ca9712a20cb83af72b0310357 100644 --- a/tests/test_flatland_envs_rail_env.py +++ b/tests/test_flatland_envs_rail_env.py @@ -8,7 +8,7 @@ from flatland.core.transition_map import GridTransitionMap from flatland.envs.agent_utils import EnvAgent from flatland.envs.observations import GlobalObsForRailEnv, TreeObsForRailEnv from flatland.envs.predictions import ShortestPathPredictorForRailEnv -from flatland.envs.rail_env import RailEnv +from flatland.envs.rail_env import RailEnv, RailEnvActions from flatland.envs.rail_generators import complex_rail_generator, rail_from_file from flatland.envs.rail_generators import rail_from_grid_transition_map from flatland.envs.schedule_generators import random_schedule_generator, complex_schedule_generator, schedule_from_file @@ -87,8 +87,8 @@ def test_save_load_mpk(): assert(agent1.target == agent2.target) -@pytest.mark.skip(reason="Some unfortunate behaviour here - agent gets stuck at corners.") -def test_rail_environment_single_agent(): +#@pytest.mark.skip(reason="Some unfortunate behaviour here - agent gets stuck at corners.") +def test_rail_environment_single_agent(show=False): # We instantiate the following map on a 3x3 grid # _ _ # / \/ \ @@ -96,34 +96,50 @@ def test_rail_environment_single_agent(): # \_/\_/ transitions = RailEnvTransitions() - cells = transitions.transition_list - vertical_line = cells[1] - south_symmetrical_switch = cells[6] - north_symmetrical_switch = transitions.rotate_transition(south_symmetrical_switch, 180) - south_east_turn = int('0100000000000010', 2) - south_west_turn = transitions.rotate_transition(south_east_turn, 90) - north_east_turn = transitions.rotate_transition(south_east_turn, 270) - north_west_turn = transitions.rotate_transition(south_east_turn, 180) - - rail_map = np.array([[south_east_turn, south_symmetrical_switch, - south_west_turn], - [vertical_line, vertical_line, vertical_line], - [north_east_turn, north_symmetrical_switch, - north_west_turn]], - dtype=np.uint16) - - rail = GridTransitionMap(width=3, height=3, transitions=transitions) - rail.grid = rail_map - rail_env = RailEnv(width=3, height=3, rail_generator=rail_from_grid_transition_map(rail), - schedule_generator=random_schedule_generator(), number_of_agents=1, - obs_builder_object=GlobalObsForRailEnv()) + + + + if False: + # This env creation doesn't quite work right. + cells = transitions.transition_list + vertical_line = cells[1] + south_symmetrical_switch = cells[6] + north_symmetrical_switch = transitions.rotate_transition(south_symmetrical_switch, 180) + south_east_turn = int('0100000000000010', 2) + south_west_turn = transitions.rotate_transition(south_east_turn, 90) + north_east_turn = transitions.rotate_transition(south_east_turn, 270) + north_west_turn = transitions.rotate_transition(south_east_turn, 180) + + rail_map = np.array([[south_east_turn, south_symmetrical_switch, + south_west_turn], + [vertical_line, vertical_line, vertical_line], + [north_east_turn, north_symmetrical_switch, + north_west_turn]], + dtype=np.uint16) + + rail = GridTransitionMap(width=3, height=3, transitions=transitions) + rail.grid = rail_map + rail_env = RailEnv(width=3, height=3, rail_generator=rail_from_grid_transition_map(rail), + schedule_generator=random_schedule_generator(), number_of_agents=1, + obs_builder_object=GlobalObsForRailEnv()) + else: + rail_env, env_dict = RailEnvPersister.load_new("test_env_loop.pkl", "env_data.tests") + rail_map = rail_env.rail.grid + + rail_env._max_episode_steps = 1000 + + _ = rail_env.reset(False, False, True) + + liActions = [int(a) for a in RailEnvActions] env_renderer = RenderTool(rail_env) + + #RailEnvPersister.save(rail_env, "test_env_figure8.pkl") - for _ in range(50): - _ = rail_env.reset(False, False, True) + for _ in range(5): - + #rail_env.agents[0].initial_position = (1,2) + _ = rail_env.reset(False, False, True) # We do not care about target for the moment agent = rail_env.agents[0] @@ -132,57 +148,68 @@ def test_rail_environment_single_agent(): # Check that trains are always initialized at a consistent position # or direction. # They should always be able to go somewhere. - assert (transitions.get_transitions( - rail_map[agent.position], - agent.direction) != (0, 0, 0, 0)) + if show: + print("After reset - agent pos:", agent.position, "dir: ", agent.direction) + print(transitions.get_transitions(rail_map[agent.position], agent.direction)) - # HACK - force it to appear somwhere we know is good. - agent.position = (1,2) - agent.direction = 0 + #assert (transitions.get_transitions( + # rail_map[agent.position], + # agent.direction) != (0, 0, 0, 0)) - agent.initial_position = initial_pos = agent.position + # HACK - force the direction to one we know is good. + #agent.initial_position = agent.position = (2,3) + agent.initial_direction = agent.direction = 0 - valid_active_actions_done = 0 - pos = initial_pos + if show: + print ("handle:", agent.handle) + #agent.initial_position = initial_pos = agent.position + valid_active_actions_done = 0 + pos = agent.position - env_renderer.render_env(show=False) + if show: + env_renderer.render_env(show=show, show_agents=True) + time.sleep(0.01) iStep = 0 while valid_active_actions_done < 6: # We randomly select an action - action = np.random.randint(4) + action = np.random.choice(liActions) + #action = RailEnvActions.MOVE_FORWARD - _, _, _, _ = rail_env.step({0: action}) + _, _, dict_done, _ = rail_env.step({0: action}) prev_pos = pos pos = agent.position # rail_env.agents_position[0] - #print("action:", action, "pos:", pos, "prev:", prev_pos) + print("action:", action, "pos:", agent.position, "prev:", prev_pos, agent.direction) + print(dict_done) if prev_pos != pos: valid_active_actions_done += 1 iStep += 1 - env_renderer.render_env(show=False) - #time.sleep(0.1) + + if show: + env_renderer.render_env(show=show, show_agents=True, step=iStep) + time.sleep(0.01) assert iStep < 100, "valid actions should have been performed by now - hung agent" # After 6 movements on this railway network, the train should be back # to its original height on the map. - assert (initial_pos[0] == agent.position[0]) + #assert (initial_pos[0] == agent.position[0]) # We check that the train always attains its target after some time for _ in range(10): _ = rail_env.reset() - # JW - to avoid problem with random_schedule_generator. - rail_env.agents[0].position = (1,2) + rail_env.agents[0].direction = 0 - done = False + # JW - to avoid problem with random_schedule_generator. + #rail_env.agents[0].position = (1,2) iStep = 0 while iStep < 100: # We randomly select an action - action = np.random.randint(4) + action = np.random.choice(liActions) _, _, dones, _ = rail_env.step({0: action}) done = dones['__all__'] @@ -190,6 +217,7 @@ def test_rail_environment_single_agent(): break iStep +=1 assert iStep < 100, "agent should have finished by now" + env_renderer.render_env(show=show) def test_dead_end(): @@ -336,7 +364,7 @@ def test_rail_env_reset(): def main(): - test_rail_environment_single_agent() + test_rail_environment_single_agent(show=True) if __name__=="__main__": main() \ No newline at end of file diff --git a/tests/test_flatland_malfunction.py b/tests/test_flatland_malfunction.py index 464e7523db805bd1a45441c0666f5d37245439c1..eaa3112708f3f0e5d255b7e454078d9a59e7ca22 100644 --- a/tests/test_flatland_malfunction.py +++ b/tests/test_flatland_malfunction.py @@ -119,9 +119,9 @@ def test_malfunction_process(): def test_malfunction_process_statistically(): - """Tests hat malfunctions are produced by stochastic_data!""" + """Tests that malfunctions are produced by stochastic_data!""" # Set fixed malfunction duration for this test - stochastic_data = MalfunctionParameters(malfunction_rate=5, # Rate of malfunction occurence + stochastic_data = MalfunctionParameters(malfunction_rate=1/5, # Rate of malfunction occurence min_duration=5, # Minimal duration of malfunction max_duration=5 # Max duration of malfunction ) @@ -168,7 +168,7 @@ def test_malfunction_process_statistically(): def test_malfunction_before_entry(): """Tests that malfunctions are working properly for agents before entering the environment!""" # Set fixed malfunction duration for this test - stochastic_data = MalfunctionParameters(malfunction_rate=2, # Rate of malfunction occurence + stochastic_data = MalfunctionParameters(malfunction_rate=1/2, # Rate of malfunction occurrence min_duration=10, # Minimal duration of malfunction max_duration=10 # Max duration of malfunction ) @@ -215,7 +215,7 @@ def test_malfunction_values_and_behavior(): rail, rail_map = make_simple_rail2() action_dict: Dict[int, RailEnvActions] = {} - stochastic_data = MalfunctionParameters(malfunction_rate=0.001, # Rate of malfunction occurence + stochastic_data = MalfunctionParameters(malfunction_rate=1/0.001, # Rate of malfunction occurence min_duration=10, # Minimal duration of malfunction max_duration=10 # Max duration of malfunction ) @@ -241,7 +241,7 @@ def test_malfunction_values_and_behavior(): def test_initial_malfunction(): - stochastic_data = MalfunctionParameters(malfunction_rate=1000, # Rate of malfunction occurence + stochastic_data = MalfunctionParameters(malfunction_rate=1/1000, # Rate of malfunction occurence min_duration=2, # Minimal duration of malfunction max_duration=5 # Max duration of malfunction ) @@ -390,7 +390,7 @@ def test_initial_malfunction_stop_moving(): def test_initial_malfunction_do_nothing(): - stochastic_data = MalfunctionParameters(malfunction_rate=70, # Rate of malfunction occurence + stochastic_data = MalfunctionParameters(malfunction_rate=1/70, # Rate of malfunction occurence min_duration=2, # Minimal duration of malfunction max_duration=5 # Max duration of malfunction )