diff --git a/flatland/core/grid/grid_utils.py b/flatland/core/grid/grid_utils.py index 9c2fe2940dfb9a5fc1d7bff7c9ab6b1cb1c880e6..7f920c11f1ed96efd4c46e163bbd2a34638b73bd 100644 --- a/flatland/core/grid/grid_utils.py +++ b/flatland/core/grid/grid_utils.py @@ -2,6 +2,8 @@ from typing import Tuple, Callable, List, Type import numpy as np +from flatland.core.grid.grid4 import Grid4TransitionsEnum + Vector2D: Type = Tuple[float, float] IntVector2D: Type = Tuple[int, int] @@ -296,7 +298,7 @@ def distance_on_rail(pos1, pos2, metric="Euclidean"): return np.abs(pos1[0] - pos2[0]) + np.abs(pos1[1] - pos2[1]) -def direction_to_point(pos1, pos2): +def direction_to_city(pos1: IntVector2D, pos2: IntVector2D) -> Grid4TransitionsEnum: """ Returns the closest direction orientation of position 2 relative to position 1 :param pos1: position we are interested in @@ -308,11 +310,11 @@ def direction_to_point(pos1, pos2): direction = np.sign(diff_vec[axis]) if axis == 0: if direction > 0: - return 0 + return Grid4TransitionsEnum.NORTH else: - return 2 + return Grid4TransitionsEnum.SOUTH else: if direction > 0: - return 3 + return Grid4TransitionsEnum.WEST else: - return 1 + return Grid4TransitionsEnum.EAST diff --git a/flatland/envs/rail_generators.py b/flatland/envs/rail_generators.py index bbbb2c06f85dfa4b3ce36a8fd8ea3765fedd59b1..a25862dce70a32f21057f25875ec6baaecf2206f 100644 --- a/flatland/envs/rail_generators.py +++ b/flatland/envs/rail_generators.py @@ -1,13 +1,14 @@ """Rail generators (infrastructure manager, "Infrastrukturbetreiber").""" import time import warnings -from typing import Callable, Tuple, Optional, Dict, List +from typing import Callable, Tuple, Optional, Dict, List, Any import msgpack import numpy as np from flatland.core.grid.grid4_utils import get_direction, mirror -from flatland.core.grid.grid_utils import distance_on_rail, direction_to_point +from flatland.core.grid.grid_utils import distance_on_rail, direction_to_city, IntVector2DArray, IntVector2D, \ + Vec2dOperations from flatland.core.grid.rail_env_grid import RailEnvTransitions from flatland.core.transition_map import GridTransitionMap from flatland.envs.grid4_generators_utils import connect_rail, connect_cities, connect_straigt_line @@ -545,8 +546,6 @@ def sparse_rail_generator(max_num_cities: int = 5, grid_mode: bool = False, max_ :return: generator """ - DEBUG_PRINT_TIMING = False - def generator(width: int, height: int, num_agents: int, num_resets: int = 0) -> RailGeneratorProduct: np.random.seed(seed + num_resets) @@ -560,7 +559,6 @@ def sparse_rail_generator(max_num_cities: int = 5, grid_mode: bool = False, max_ rails_between_cities = rails_in_city if max_rails_between_cities > rails_in_city else max_rails_between_cities # Evenly distribute cities - city_time_start = time.time() if grid_mode: city_positions, city_cells = _generate_evenly_distr_city_positions(max_num_cities, city_radius, width, height) else: @@ -568,62 +566,40 @@ def sparse_rail_generator(max_num_cities: int = 5, grid_mode: bool = False, max_ # reduce num_cities if less were generated in random mode num_cities = len(city_positions) - if DEBUG_PRINT_TIMING: - print("City position time", time.time() - city_time_start, "Seconds") # Set up connection points for all cities - city_connection_time = time.time() inner_connection_points, outer_connection_points, connection_info, city_orientations = _generate_city_connection_points( city_positions, city_radius, rails_between_cities, rails_in_city) - if DEBUG_PRINT_TIMING: - print("Connection points", time.time() - city_connection_time) # Connect the cities through the connection points - city_connection_time = time.time() inter_city_lines = _connect_cities(city_positions, outer_connection_points, city_cells, rail_trans, grid_map) - if DEBUG_PRINT_TIMING: - print("City connection time", time.time() - city_connection_time) # Build inner cities - city_build_time = time.time() - through_tracks, free_tracks = _build_inner_cities(city_positions, inner_connection_points, - outer_connection_points, - city_radius, - rail_trans, - grid_map) - if DEBUG_PRINT_TIMING: - print("City build time", time.time() - city_build_time) + through_tracks, free_rails = _build_inner_cities(city_positions, inner_connection_points, + outer_connection_points, + rail_trans, + grid_map) # Populate cities - train_station_time = time.time() - train_stations, built_num_trainstation = _set_trainstation_positions(city_positions, city_radius, free_tracks, - grid_map) - if DEBUG_PRINT_TIMING: - print("Trainstation placing time", time.time() - train_station_time) + train_stations, built_num_trainstation = _set_trainstation_positions(city_positions, city_radius, free_rails) # Fix all transition elements - grid_fix_time = time.time() _fix_transitions(city_cells, inter_city_lines, grid_map) - if DEBUG_PRINT_TIMING: - print("Grid fix time", time.time() - grid_fix_time) # Generate start target pairs - schedule_time = time.time() agent_start_targets_cities, num_agents = _generate_start_target_pairs(num_agents, num_cities, train_stations, city_orientations) - if DEBUG_PRINT_TIMING: - print("Schedule time", time.time() - schedule_time) return grid_map, {'agents_hints': { 'num_agents': num_agents, - 'agent_start_targets_cities': agent_start_targets_cities, + 'agent_start_targets_nodes': agent_start_targets_cities, 'train_stations': train_stations, 'city_orientations': city_orientations }} - def _generate_random_city_positions(num_cities: int, city_radius: int, width: int, height: int) -> (List[Tuple[int, int]], List[Tuple[int, int]]): - city_positions: List[Tuple[int, int]] = [] - city_cells: List[Tuple[int, int]] = [] + def _generate_random_city_positions(num_cities: int, city_radius: int, width: int, height: int) -> (IntVector2DArray, IntVector2DArray): + city_positions: IntVector2DArray = [] + city_cells: IntVector2DArray = [] for city_idx in range(num_cities): too_close = True tries = 0 @@ -650,7 +626,7 @@ def sparse_rail_generator(max_num_cities: int = 5, grid_mode: bool = False, max_ break return city_positions, city_cells - def _generate_evenly_distr_city_positions(num_cities: int, city_radius: int, width: int, height: int) -> (List[Tuple[int, int]], List[Tuple[int, int]]): + def _generate_evenly_distr_city_positions(num_cities: int, city_radius: int, width: int, height: int) -> (IntVector2DArray, IntVector2DArray): aspect_ratio = height / width cities_per_row = int(np.ceil(np.sqrt(num_cities * aspect_ratio))) cities_per_col = int(np.ceil(num_cities / cities_per_row)) @@ -665,8 +641,7 @@ def sparse_rail_generator(max_num_cities: int = 5, grid_mode: bool = False, max_ city_cells.extend(_get_cells_in_city(city_positions[-1], city_radius)) return city_positions, city_cells - def _generate_city_connection_points(city_positions: List[Tuple[int, int]], city_radius: int, - rails_between_cities: int, rails_in_city: int = 2): + def _generate_city_connection_points(city_positions: IntVector2DArray, city_radius: int, rails_between_cities: int, rails_in_city: int = 2): inner_connection_points = [] outer_connection_points = [] connection_info = [] @@ -675,8 +650,8 @@ def sparse_rail_generator(max_num_cities: int = 5, grid_mode: bool = False, max_ # Chose the directions where close cities are situated neighb_dist = [] - for neighb_city in city_positions: - neighb_dist.append(distance_on_rail(city_position, neighb_city, metric="Manhattan")) + for neighbour_city in city_positions: + neighb_dist.append(Vec2dOperations.get_manhattan_distance(city_position, neighbour_city)) closest_neighb_idx = argsort(neighb_dist) # Store the directions to these neighbours and orient city to face closest neighbour @@ -685,7 +660,7 @@ def sparse_rail_generator(max_num_cities: int = 5, grid_mode: bool = False, max_ if grid_mode: current_closest_direction = np.random.randint(4) else: - current_closest_direction = direction_to_point(city_position, city_positions[closest_neighb_idx[idx]]) + current_closest_direction = direction_to_city(city_position, city_positions[closest_neighb_idx[idx]]) connection_sides_idx.append(current_closest_direction) connection_sides_idx.append((current_closest_direction + 2) % 4) city_orientations.append(current_closest_direction) @@ -723,7 +698,7 @@ def sparse_rail_generator(max_num_cities: int = 5, grid_mode: bool = False, max_ connection_info.append(connections_per_direction) return inner_connection_points, outer_connection_points, connection_info, city_orientations - def _connect_cities(city_positions: List[Tuple[int, int]], connection_points, city_cells: List[Tuple[int, int]], + def _connect_cities(city_positions: IntVector2DArray, connection_points, city_cells: IntVector2DArray, rail_trans, grid_map): """ Function to connect the different cities through their connection points @@ -750,8 +725,8 @@ def sparse_rail_generator(max_num_cities: int = 5, grid_mode: bool = False, max_ for dir in range(4): current_points = connection_points[neighb_idx][dir] for tmp_in_connection_point in current_points: - tmp_dist = distance_on_rail(tmp_out_connection_point, tmp_in_connection_point, - metric="Manhattan") + tmp_dist = Vec2dOperations.get_manhattan_distance(tmp_out_connection_point, + tmp_in_connection_point) if tmp_dist < min_connection_dist: min_connection_dist = tmp_dist neighb_connection_point = tmp_in_connection_point @@ -763,7 +738,7 @@ def sparse_rail_generator(max_num_cities: int = 5, grid_mode: bool = False, max_ return all_paths - def _build_inner_cities(city_positions, inner_connection_points, outer_connection_points, city_radius, rail_trans, + def _build_inner_cities(city_positions, inner_connection_points, outer_connection_points, rail_trans, grid_map): """ Builds inner city tracks. This current version connects all incoming connections to all outgoing connections @@ -806,29 +781,27 @@ def sparse_rail_generator(max_num_cities: int = 5, grid_mode: bool = False, max_ free_tracks[current_city].append(current_track) return through_path_cells, free_tracks - def _set_trainstation_positions(city_positions, city_radius, free_tracks, grid_map): + def _set_trainstation_positions(city_positions: IntVector2DArray, city_radius: int, free_rails): """ :param city_positions: :param num_trainstations: :return: """ - nb_cities = len(city_positions) - train_stations = [[] for i in range(nb_cities)] - left = 0 - right = 0 + num_cities = len(city_positions) + train_stations = [[] for i in range(num_cities)] built_num_trainstations = 0 for current_city in range(len(city_positions)): - for track_nbr in range(len(free_tracks[current_city])): - possible_location = free_tracks[current_city][track_nbr][city_radius] + for track_nbr in range(len(free_rails[current_city])): + possible_location = free_rails[current_city][track_nbr][city_radius] train_stations[current_city].append((possible_location, track_nbr)) return train_stations, built_num_trainstations - def _generate_start_target_pairs(num_agents, nb_cities, train_stations, city_orientation): + def _generate_start_target_pairs(num_agents, num_cities, train_stations, city_orientation): """ Fill the trainstation positions with targets and goals :param num_agents: - :param nb_cities: + :param num_cities: :param train_stations: :return: """ @@ -839,7 +812,7 @@ def sparse_rail_generator(max_num_cities: int = 5, grid_mode: bool = False, max_ # Slot availability in city city_available_start = [] city_available_target = [] - for city_idx in range(nb_cities): + for city_idx in range(num_cities): city_available_start.append(len(train_stations[city_idx])) city_available_target.append(len(train_stations[city_idx])) @@ -879,35 +852,34 @@ def sparse_rail_generator(max_num_cities: int = 5, grid_mode: bool = False, max_ for cell in range(rails_to_fix_cnt): grid_map.fix_transitions((rails_to_fix[2 * cell], rails_to_fix[2 * cell + 1])) - def _closest_neighbour_in_direction(current_city_idx: int, city_positions: List[Tuple[int, int]]): + def _closest_neighbour_in_direction(current_city_idx: int, city_positions: IntVector2DArray) -> List[int]: """ - Returns indices of closest neighbours in every direction NESW + Returns indices of closest neighbour in every direction NESW :param current_city_idx: Index of city in city_positions list :param city_positions: list of all points being considered - :return: list of index of closest neighbours in all directions + :return: list of index of closest neighbour in all directions """ - city_dist = [] - closest_neighb = [None for i in range(4)] - for av_city in range(len(city_positions)): - city_dist.append( - distance_on_rail(city_positions[current_city_idx], city_positions[av_city], metric="Manhattan")) - sorted_neighbours = np.argsort(city_dist) + city_distances = [] + closest_neighbour: List[int] = [None for i in range(4)] + for city_idx in range(len(city_positions)): + city_distances.append(Vec2dOperations.get_manhattan_distance(city_positions[current_city_idx], city_positions[city_idx])) + sorted_neighbours = np.argsort(city_distances) direction_set = 0 - for neighb in sorted_neighbours[1:]: - direction_to_neighb = direction_to_point(city_positions[current_city_idx], city_positions[neighb]) - if closest_neighb[direction_to_neighb] == None: - closest_neighb[direction_to_neighb] = neighb + for neighbour in sorted_neighbours[1:]: + direction_to_neighbour = direction_to_city(city_positions[current_city_idx], city_positions[neighbour]) + if closest_neighbour[direction_to_neighbour] == None: + closest_neighbour[direction_to_neighbour] = neighbour direction_set += 1 if direction_set == 4: - return closest_neighb - return closest_neighb + return closest_neighbour + return closest_neighbour def argsort(seq): # http://stackoverflow.com/questions/3071415/efficient-method-to-calculate-the-rank-vector-of-a-list-in-python return sorted(range(len(seq)), key=seq.__getitem__) - def _get_cells_in_city(center: Tuple[int, int], radius: int) -> List[Tuple[int, int]]: + def _get_cells_in_city(center: IntVector2D, radius: int) -> IntVector2DArray: """ Parameters