diff --git a/env_data/tests/Level_distance_map_shortest_path.pkl b/env_data/tests/Level_distance_map_shortest_path.pkl new file mode 100644 index 0000000000000000000000000000000000000000..938adf4660784976299a4be63c9d91667a27c924 Binary files /dev/null and b/env_data/tests/Level_distance_map_shortest_path.pkl differ diff --git a/flatland/__init__.py b/flatland/__init__.py index f6411ca099ebc8f211e3d639e8a873831e43496f..74f8368d8a19dd7eb1ad36a501c81805ef975133 100644 --- a/flatland/__init__.py +++ b/flatland/__init__.py @@ -4,4 +4,4 @@ __author__ = """S.P. Mohanty""" __email__ = 'mohanty@aicrowd.com' -__version__ = '2.1.6' +__version__ = '2.1.7' diff --git a/flatland/envs/distance_map.py b/flatland/envs/distance_map.py index 2bc1a5117794959cca82d2edad821cb629397f78..fe546d1fdd368597f0a6263d61323ecfeb6dc31f 100644 --- a/flatland/envs/distance_map.py +++ b/flatland/envs/distance_map.py @@ -60,8 +60,16 @@ class DistanceMap: self.env_height, self.env_width, 4)) + + computed_targets = [] for i, agent in enumerate(agents): - self._distance_map_walker(rail, agent.target, i) + if agent.target not in computed_targets: + self._distance_map_walker(rail, agent.target, i) + else: + # just copy the distance map form other agent with same target (performance) + self.distance_map[i, :, :, :] = np.copy( + self.distance_map[computed_targets.index(agent.target), :, :, :]) + computed_targets.append(agent.target) def _distance_map_walker(self, rail: GridTransitionMap, position, target_nr: int): """ diff --git a/flatland/envs/rail_env.py b/flatland/envs/rail_env.py index 10908dddbc376f9493d5e00dcda2d48fd0d25163..991de23fe42d19c77d6003c403474609e27b44f9 100644 --- a/flatland/envs/rail_env.py +++ b/flatland/envs/rail_env.py @@ -115,6 +115,7 @@ class RailEnv(Environment): schedule_generator: ScheduleGenerator = random_schedule_generator(), number_of_agents=1, obs_builder_object: ObservationBuilder = GlobalObsForRailEnv(), + max_episode_steps=None, stochastic_data=None, remove_agents_at_target=False, random_seed=1 @@ -147,6 +148,7 @@ class RailEnv(Environment): obs_builder_object: ObservationBuilder object ObservationBuilder-derived object that takes builds observation vectors for each agent. + max_episode_steps : int or None remove_agents_at_target : bool If remove_agents_at_target is set to true then the agents will be removed by placing to RailEnv.DEPOT_POSITION when the agent has reach it's target position. @@ -169,7 +171,7 @@ class RailEnv(Environment): self.obs_builder = obs_builder_object self.obs_builder.set_env(self) - self._max_episode_steps = None + self._max_episode_steps = max_episode_steps self._elapsed_steps = 0 self.dones = dict.fromkeys(list(range(number_of_agents)) + ["__all__"], False) @@ -215,6 +217,9 @@ class RailEnv(Environment): self.max_number_of_steps_broken = malfunction_max_duration # Reset environment + self.reset() + self.num_resets = 0 # yes, set it to zero again! + self.valid_positions = None def _seed(self, seed=None): @@ -265,6 +270,11 @@ class RailEnv(Environment): self.rail = rail self.height, self.width = self.rail.grid.shape + # Do a new set_env call on the obs_builder to ensure + # that obs_builder specific instantiations are made according to the + # specifications of the current environment : like width, height, etc + self.obs_builder.set_env(self) + if optionals and 'distance_map' in optionals: self.distance_map.set(optionals['distance_map']) @@ -275,9 +285,8 @@ class RailEnv(Environment): # TODO https://gitlab.aicrowd.com/flatland/flatland/issues/185 # why do we need static agents? could we it more elegantly? - schedule = self.schedule_generator(self.rail, self.get_num_agents(), agents_hints, self.num_resets) - self.agents_static = EnvAgentStatic.from_lists(schedule) - self._max_episode_steps = schedule.max_episode_steps + self.agents_static = EnvAgentStatic.from_lists( + *self.schedule_generator(self.rail, self.get_num_agents(), agents_hints, self.num_resets)) self.restart_agents() diff --git a/flatland/envs/rail_env_shortest_paths.py b/flatland/envs/rail_env_shortest_paths.py index 7944a49daf388403c8a226dbf866ac810d1286a3..622fb6efd37ab07f59d575fa618cb34676fefcd1 100644 --- a/flatland/envs/rail_env_shortest_paths.py +++ b/flatland/envs/rail_env_shortest_paths.py @@ -72,7 +72,7 @@ def get_valid_move_actions_(agent_direction: Grid4TransitionsEnum, # N.B. get_shortest_paths is not part of distance_map since it refers to RailEnvActions (would lead to circularity!) -def get_shortest_paths(distance_map: DistanceMap, max_depth: Optional[int] = None) \ +def get_shortest_paths(distance_map: DistanceMap, max_depth: Optional[int] = None, agent_handle: Optional[int] = None) \ -> Dict[int, Optional[List[WalkingElement]]]: """ Computes the shortest path for each agent to its target and the action to be taken to do so. @@ -81,9 +81,15 @@ def get_shortest_paths(distance_map: DistanceMap, max_depth: Optional[int] = Non If there is no path (rail disconnected), the path is given as None. The agent state (moving or not) and its speed are not taken into account + example: + agent_fixed_travel_paths = get_shortest_paths(env.distance_map, None, agent.handle) + path = agent_fixed_travel_paths[agent.handle] + Parameters ---------- - distance_map + distance_map : reference to the distance_map + max_depth : max path length, if the shortest path is longer, it will be cutted + agent_handle : if set, the shortest for agent.handle will be returned , otherwise for all agents Returns ------- @@ -133,8 +139,11 @@ def get_shortest_paths(distance_map: DistanceMap, max_depth: Optional[int] = Non WalkingElement(position, direction, RailEnvNextAction(RailEnvActions.STOP_MOVING, position, direction))) - for agent in distance_map.agents: - _shortest_path_for_agent(agent) + if agent_handle is not None: + _shortest_path_for_agent(distance_map.agents[agent_handle]) + else: + for agent in distance_map.agents: + _shortest_path_for_agent(agent) return shortest_paths diff --git a/flatland/evaluators/client.py b/flatland/evaluators/client.py index e6ea1c500336b7592ba45480571ebbb9743d0bfe..9322b6a8530cd3c77c246a2e74e99a8e2bc91ab9 100644 --- a/flatland/evaluators/client.py +++ b/flatland/evaluators/client.py @@ -25,9 +25,9 @@ m.patch() def are_dicts_equal(d1, d2): """ return True if all keys and values are the same """ - return all(k in d2 and d1[k] == d2[k] + return all(k in d2 and np.isclose(d1[k], d2[k]) for k in d1) \ - and all(k in d1 and d1[k] == d2[k] + and all(k in d1 and np.isclose(d1[k], d2[k]) for k in d2) @@ -80,6 +80,7 @@ class FlatlandRemoteClient(object): 'AICROWD_TESTS_FOLDER', '/tmp/flatland_envs' ) + self.current_env_path = None self.verbose = verbose @@ -180,7 +181,9 @@ class FlatlandRemoteClient(object): return observation, info test_env_file_path = _response['payload']['env_file_path'] - print("Received Env : ", test_env_file_path) + if self.verbose: + print("Received Env : ", test_env_file_path) + test_env_file_path = os.path.join( self.test_envs_root, test_env_file_path @@ -192,7 +195,10 @@ class FlatlandRemoteClient(object): "to point to the location of the Tests folder ? \n" "We are currently looking at `{}` for the tests".format(self.test_envs_root) ) - print("Current env path : ", test_env_file_path) + + if self.verbose: + print("Current env path : ", test_env_file_path) + self.current_env_path = test_env_file_path self.env = RailEnv( width=1, height=1, @@ -232,11 +238,13 @@ class FlatlandRemoteClient(object): local_observation, local_reward, local_done, local_info = \ self.env.step(action) - print(local_reward) + if self.verbose: + print(local_reward) if not are_dicts_equal(remote_reward, local_reward): + print("Remote Reward : ", remote_reward, "Local Reward : ", local_reward) raise Exception("local and remote `reward` are diverging") - print(remote_reward, local_reward) if not are_dicts_equal(remote_done, local_done): + print("Remote Done : ", remote_done, "Local Done : ", local_done) raise Exception("local and remote `done` are diverging") # Return local_observation instead of remote_observation diff --git a/setup.cfg b/setup.cfg index 0d5be947cbc3138fa48a9f6fdd4d7f86295dad2b..69077d856c45cf863dc0ff976c6b5ed32bf93330 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 2.1.6 +current_version = 2.1.7 commit = True tag = True diff --git a/setup.py b/setup.py index b7dad95638a1d498016906ebfcd934e3c4a1b8e0..0b6cf7c5f0f04065ecab0d712c74b050f7069385 100644 --- a/setup.py +++ b/setup.py @@ -80,6 +80,6 @@ setup( test_suite='tests', tests_require=test_requirements, url='https://gitlab.aicrowd.com/flatland/flatland', - version='2.1.6', + version='2.1.7', zip_safe=False, ) diff --git a/tests/test_flatland_envs_rail_env_shortest_paths.py b/tests/test_flatland_envs_rail_env_shortest_paths.py index ef18cf72d04a5e6ccfd89ad379bd30df77fc4075..0d863c281840839b2e80aa5e8fe08400c49ad873 100644 --- a/tests/test_flatland_envs_rail_env_shortest_paths.py +++ b/tests/test_flatland_envs_rail_env_shortest_paths.py @@ -1,3 +1,5 @@ +import sys + import numpy as np from flatland.core.grid.grid4 import Grid4TransitionsEnum @@ -196,3 +198,165 @@ def test_get_shortest_paths_max_depth(): for agent_handle in expected: assert np.array_equal(actual[agent_handle], expected[agent_handle]), \ "[{}] actual={},expected={}".format(agent_handle, actual[agent_handle], expected[agent_handle]) + + +def test_get_shortest_paths_agent_handle(): + env = load_flatland_environment_from_file('Level_distance_map_shortest_path.pkl', 'env_data.tests') + actual = get_shortest_paths(env.distance_map, agent_handle=6) + + print(actual, file=sys.stderr) + + expected = {6: + [WalkingElement(position=(5, 5), + direction=0, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(4, 5), next_direction=0)), + WalkingElement(position=(4, 5), + direction=0, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(3, 5), next_direction=0)), + WalkingElement(position=(3, 5), + direction=0, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(2, 5), next_direction=0)), + WalkingElement(position=(2, 5), + direction=0, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(1, 5), next_direction=0)), + WalkingElement(position=(1, 5), + direction=0, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(0, 5), next_direction=0)), + WalkingElement(position=(0, 5), + direction=0, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(0, 6), next_direction=1)), + WalkingElement(position=(0, 6), + direction=1, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(0, 7), next_direction=1)), + WalkingElement(position=(0, 7), + direction=1, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(0, 8), next_direction=1)), + WalkingElement(position=(0, 8), + direction=1, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(0, 9), next_direction=1)), + WalkingElement(position=(0, 9), + direction=1, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(0, 10), next_direction=1)), + WalkingElement(position=(0, 10), + direction=1, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(1, 10), next_direction=2)), + WalkingElement(position=(1, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(2, 10), next_direction=2)), + WalkingElement(position=(2, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(3, 10), next_direction=2)), + WalkingElement(position=(3, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(4, 10), next_direction=2)), + WalkingElement(position=(4, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(5, 10), next_direction=2)), + WalkingElement(position=(5, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(6, 10), next_direction=2)), + WalkingElement(position=(6, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(7, 10), next_direction=2)), + WalkingElement(position=(7, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(8, 10), next_direction=2)), + WalkingElement(position=(8, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(9, 10), next_direction=2)), + WalkingElement(position=(9, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(10, 10), next_direction=2)), + WalkingElement(position=(10, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(11, 10), next_direction=2)), + WalkingElement(position=(11, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(12, 10), next_direction=2)), + WalkingElement(position=(12, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(13, 10), next_direction=2)), + WalkingElement(position=(13, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(14, 10), next_direction=2)), + WalkingElement(position=(14, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(15, 10), next_direction=2)), + WalkingElement(position=(15, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(16, 10), next_direction=2)), + WalkingElement(position=(16, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(17, 10), next_direction=2)), + WalkingElement(position=(17, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(18, 10), next_direction=2)), + WalkingElement(position=(18, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(19, 10), next_direction=2)), + WalkingElement(position=(19, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(20, 10), next_direction=2)), + WalkingElement(position=(20, 10), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(20, 9), next_direction=3)), + WalkingElement(position=(20, 9), + direction=3, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(20, 8), next_direction=3)), + WalkingElement(position=(20, 8), + direction=3, next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_LEFT, + next_position=(21, 8), + next_direction=2)), + WalkingElement(position=(21, 8), + direction=2, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(21, 7), next_direction=3)), + WalkingElement(position=(21, 7), + direction=3, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(21, 6), next_direction=3)), + WalkingElement(position=(21, 6), + direction=3, + next_action_element=RailEnvNextAction(action=RailEnvActions.MOVE_FORWARD, + next_position=(21, 5), next_direction=3)), + WalkingElement(position=(21, 5), + direction=3, + next_action_element=RailEnvNextAction(action=RailEnvActions.STOP_MOVING, + next_position=(21, 5), next_direction=3)) + ]} + + for agent_handle in expected: + assert np.array_equal(actual[agent_handle], expected[agent_handle]), \ + "[{}] actual={},expected={}".format(agent_handle, actual[agent_handle], expected[agent_handle])