예제 #1
0
def test_get_shortest_paths_max_depth():
    env = load_flatland_environment_from_file('test_002.pkl', 'env_data.tests')
    env.reset()
    actual = get_shortest_paths(env.distance_map, max_depth=2)

    expected = {
        0: [
            WayPoint(position=(1, 1), direction=1),
            WayPoint(position=(1, 2), direction=1)
        ],
        1: [
            WayPoint(position=(3, 18), direction=3),
            WayPoint(position=(3, 17), 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])
예제 #2
0
    def _shortest_path_for_agent(agent):
        if agent.status == RailAgentStatus.READY_TO_DEPART:
            position = agent.initial_position
        elif agent.status == RailAgentStatus.ACTIVE:
            position = agent.position
        elif agent.status == RailAgentStatus.DONE:
            position = agent.target
        else:
            shortest_paths[agent.handle] = None
            return
        direction = agent.direction
        shortest_paths[agent.handle] = []
        distance = math.inf
        depth = 0
        while (position != agent.target
               and (max_depth is None or depth < max_depth)):
            next_actions = get_valid_move_actions_(direction, position,
                                                   distance_map.rail)
            best_next_action = None
            for next_action in next_actions:
                next_action_distance = distance_map.get()[
                    agent.handle, next_action.next_position[0],
                    next_action.next_position[1], next_action.next_direction]
                if next_action_distance < distance:
                    best_next_action = next_action
                    distance = next_action_distance

            shortest_paths[agent.handle].append(WayPoint(position, direction))
            depth += 1

            # if there is no way to continue, the rail must be disconnected!
            # (or distance map is incorrect)
            if best_next_action is None:
                shortest_paths[agent.handle] = None
                return

            position = best_next_action.next_position
            direction = best_next_action.next_direction
        if max_depth is None or depth < max_depth:
            shortest_paths[agent.handle].append(WayPoint(position, direction))
예제 #3
0
    def get_way_point_before_or_at_step(self, agent_id: int,
                                        step: int) -> WayPoint:
        """
        Get the way point point from which the current position can be extracted.

        Parameters
        ----------
        agent_id
        step

        Returns
        -------
        WalkingElement

        """
        train_run = self.train_run_dict[agent_id]
        entry_time_step = train_run[0].scheduled_at
        # the agent has no position before and at choosing to enter the grid (one tick elapses before the agent enters the grid)
        if step <= entry_time_step:
            return WayPoint(
                position=None,
                direction=self.env.agents[agent_id].initial_direction)

        # the agent has no position as soon as the target is reached
        exit_time_step = train_run[-1].scheduled_at
        if step >= exit_time_step:
            # agent loses position as soon as target cell is reached
            return WayPoint(position=None,
                            direction=train_run[-1].way_point.direction)

        way_point = None
        for train_run_way_point in train_run:
            if step < train_run_way_point.scheduled_at:
                return way_point
            if step >= train_run_way_point.scheduled_at:
                way_point = train_run_way_point.way_point
        assert way_point is not None
        return way_point
예제 #4
0
def test_get_k_shortest_paths(rendering=False):
    rail, rail_map = make_simple_rail_with_alternatives()

    env = RailEnv(
        width=rail_map.shape[1],
        height=rail_map.shape[0],
        rail_generator=rail_from_grid_transition_map(rail),
        schedule_generator=random_schedule_generator(),
        number_of_agents=1,
        obs_builder_object=GlobalObsForRailEnv(),
    )
    env.reset()

    initial_position = (3, 1)  # west dead-end
    initial_direction = Grid4TransitionsEnum.WEST  # west
    target_position = (3, 9)  # east

    # set the initial position
    agent = env.agents[0]
    agent.position = initial_position
    agent.initial_position = initial_position
    agent.direction = initial_direction
    agent.target = target_position  # east dead-end
    agent.moving = True

    env.reset(False, False)
    if rendering:
        renderer = RenderTool(env, gl="PILSVG")
        renderer.render_env(show=True, show_observations=False)
        input()

    actual = set(
        get_k_shortest_paths(
            env=env,
            source_position=initial_position,  # west dead-end
            source_direction=int(initial_direction),  # east
            target_position=target_position,
            k=10))

    expected = set([
        (WayPoint(position=(3, 1),
                  direction=3), WayPoint(position=(3, 0), direction=3),
         WayPoint(position=(3, 1),
                  direction=1), WayPoint(position=(3, 2), direction=1),
         WayPoint(position=(3, 3),
                  direction=1), WayPoint(position=(2, 3), direction=0),
         WayPoint(position=(1, 3),
                  direction=0), WayPoint(position=(0, 3), direction=0),
         WayPoint(position=(0, 4),
                  direction=1), WayPoint(position=(0, 5), direction=1),
         WayPoint(position=(0, 6),
                  direction=1), WayPoint(position=(0, 7), direction=1),
         WayPoint(position=(0, 8),
                  direction=1), WayPoint(position=(0, 9), direction=1),
         WayPoint(position=(1, 9),
                  direction=2), WayPoint(position=(2, 9), direction=2),
         WayPoint(position=(3, 9), direction=2)),
        (WayPoint(position=(3, 1),
                  direction=3), WayPoint(position=(3, 0), direction=3),
         WayPoint(position=(3, 1),
                  direction=1), WayPoint(position=(3, 2), direction=1),
         WayPoint(position=(3, 3),
                  direction=1), WayPoint(position=(3, 4), direction=1),
         WayPoint(position=(3, 5),
                  direction=1), WayPoint(position=(3, 6), direction=1),
         WayPoint(position=(4, 6),
                  direction=2), WayPoint(position=(5, 6), direction=2),
         WayPoint(position=(6, 6),
                  direction=2), WayPoint(position=(5, 6), direction=0),
         WayPoint(position=(4, 6),
                  direction=0), WayPoint(position=(4, 7), direction=1),
         WayPoint(position=(4, 8),
                  direction=1), WayPoint(position=(4, 9), direction=1),
         WayPoint(position=(3, 9), direction=0))
    ])

    assert actual == expected, "actual={},expected={}".format(actual, expected)
예제 #5
0
def test_get_shortest_paths_agent_handle():
    env = load_flatland_environment_from_file(
        'Level_distance_map_shortest_path.pkl', 'env_data.tests')
    env.reset()
    actual = get_shortest_paths(env.distance_map, agent_handle=6)

    print(actual, file=sys.stderr)

    expected = {
        6: [
            WayPoint(position=(5, 5), direction=0),
            WayPoint(position=(4, 5), direction=0),
            WayPoint(position=(3, 5), direction=0),
            WayPoint(position=(2, 5), direction=0),
            WayPoint(position=(1, 5), direction=0),
            WayPoint(position=(0, 5), direction=0),
            WayPoint(position=(0, 6), direction=1),
            WayPoint(position=(0, 7), direction=1),
            WayPoint(position=(0, 8), direction=1),
            WayPoint(position=(0, 9), direction=1),
            WayPoint(position=(0, 10), direction=1),
            WayPoint(position=(1, 10), direction=2),
            WayPoint(position=(2, 10), direction=2),
            WayPoint(position=(3, 10), direction=2),
            WayPoint(position=(4, 10), direction=2),
            WayPoint(position=(5, 10), direction=2),
            WayPoint(position=(6, 10), direction=2),
            WayPoint(position=(7, 10), direction=2),
            WayPoint(position=(8, 10), direction=2),
            WayPoint(position=(9, 10), direction=2),
            WayPoint(position=(10, 10), direction=2),
            WayPoint(position=(11, 10), direction=2),
            WayPoint(position=(12, 10), direction=2),
            WayPoint(position=(13, 10), direction=2),
            WayPoint(position=(14, 10), direction=2),
            WayPoint(position=(15, 10), direction=2),
            WayPoint(position=(16, 10), direction=2),
            WayPoint(position=(17, 10), direction=2),
            WayPoint(position=(18, 10), direction=2),
            WayPoint(position=(19, 10), direction=2),
            WayPoint(position=(20, 10), direction=2),
            WayPoint(position=(20, 9), direction=3),
            WayPoint(position=(20, 8), direction=3),
            WayPoint(position=(21, 8), direction=2),
            WayPoint(position=(21, 7), direction=3),
            WayPoint(position=(21, 6), direction=3),
            WayPoint(position=(21, 5), 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])
예제 #6
0
def get_k_shortest_paths(env: RailEnv,
                         source_position: Tuple[int, int],
                         source_direction: int,
                         target_position=Tuple[int, int],
                         k: int = 1,
                         debug=False) -> List[Tuple[WayPoint]]:
    """
    Computes the k shortest paths using modified Dijkstra
    following pseudo-code https://en.wikipedia.org/wiki/K_shortest_path_routing
    In contrast to the pseudo-code in wikipedia, we do not a allow for loopy paths.

    Parameters
    ----------
    env :             RailEnv
    source_position:  Tuple[int,int]
    source_direction: int
    target_position:  Tuple[int,int]
    k :               int
        max number of shortest paths
    debug:            bool
        print debug statements

    Returns
    -------
    List[Tuple[WalkingElement]]
        We use tuples since we need the path elements to be hashable.
        We use a list of paths in order to keep the order of length.
    """

    # P: set of shortest paths from s to t
    # P =empty,
    shortest_paths: List[Tuple[WayPoint]] = []

    # countu: number of shortest paths found to node u
    # countu = 0, for all u in V
    count = {(r, c, d): 0
             for r in range(env.height) for c in range(env.width)
             for d in range(4)}

    # B is a heap data structure containing paths
    heap: Set[Tuple[WayPoint]] = set()

    # insert path Ps = {s} into B with cost 0
    heap.add((WayPoint(source_position, source_direction), ))

    # while B is not empty and countt < K:
    while len(heap) > 0 and len(shortest_paths) < k:
        if debug:
            print("iteration heap={}, shortest_paths={}".format(
                heap, shortest_paths))
        # – let Pu be the shortest cost path in B with cost C
        cost = np.inf
        pu = None
        for path in heap:
            if len(path) < cost:
                pu = path
                cost = len(path)
        u: WayPoint = pu[-1]
        if debug:
            print("  looking at pu={}".format(pu))

        #     – B = B − {Pu }
        heap.remove(pu)
        #     – countu = countu + 1

        urcd = (*u.position, u.direction)
        count[urcd] += 1

        # – if u = t then P = P U {Pu}
        if u.position == target_position:
            if debug:
                print(" found of length {} {}".format(len(pu), pu))
            shortest_paths.append(pu)

        # – if countu ≤ K then
        # CAVEAT: do not allow for loopy paths
        elif count[urcd] <= k:
            possible_transitions = env.rail.get_transitions(*urcd)
            if debug:
                print("  looking at neighbors of u={}, transitions are {}".
                      format(u, possible_transitions))
            #     for each vertex v adjacent to u:
            for new_direction in range(4):
                if debug:
                    print("        looking at new_direction={}".format(
                        new_direction))
                if possible_transitions[new_direction]:
                    new_position = get_new_position(u.position, new_direction)
                    if debug:
                        print("        looking at neighbor v={}".format(
                            (*new_position, new_direction)))

                    v = WayPoint(position=new_position,
                                 direction=new_direction)
                    # CAVEAT: do not allow for loopy paths
                    if v in pu:
                        continue

                    # – let Pv be a new path with cost C + w(u, v) formed by concatenating edge (u, v) to path Pu
                    pv = pu + (v, )
                    #     – insert Pv into B
                    heap.add(pv)

    # return P
    return shortest_paths
def test_action_plan(rendering: bool = False):
    """Tests ActionPlanReplayer: does action plan generation and replay work as expected."""
    rail, rail_map = make_simple_rail()
    env = RailEnv(width=rail_map.shape[1],
                  height=rail_map.shape[0],
                  rail_generator=rail_from_grid_transition_map(rail),
                  schedule_generator=random_schedule_generator(seed=77),
                  number_of_agents=2,
                  obs_builder_object=GlobalObsForRailEnv(),
                  remove_agents_at_target=True)
    env.reset()
    env.agents[0].initial_position = (3, 0)
    env.agents[0].target = (3, 8)
    env.agents[0].initial_direction = Grid4TransitionsEnum.WEST
    env.agents[1].initial_position = (3, 8)
    env.agents[1].initial_direction = Grid4TransitionsEnum.WEST
    env.agents[1].target = (0, 3)
    env.agents[1].speed_data['speed'] = 0.5  # two
    env.reset(False, False, False)
    for handle, agent in enumerate(env.agents):
        print("[{}] {} -> {}".format(handle, agent.initial_position,
                                     agent.target))

    chosen_path_dict = {
        0: [
            TrainRunWayPoint(scheduled_at=0,
                             way_point=WayPoint(position=(3, 0), direction=3)),
            TrainRunWayPoint(scheduled_at=2,
                             way_point=WayPoint(position=(3, 1), direction=1)),
            TrainRunWayPoint(scheduled_at=3,
                             way_point=WayPoint(position=(3, 2), direction=1)),
            TrainRunWayPoint(scheduled_at=14,
                             way_point=WayPoint(position=(3, 3), direction=1)),
            TrainRunWayPoint(scheduled_at=15,
                             way_point=WayPoint(position=(3, 4), direction=1)),
            TrainRunWayPoint(scheduled_at=16,
                             way_point=WayPoint(position=(3, 5), direction=1)),
            TrainRunWayPoint(scheduled_at=17,
                             way_point=WayPoint(position=(3, 6), direction=1)),
            TrainRunWayPoint(scheduled_at=18,
                             way_point=WayPoint(position=(3, 7), direction=1)),
            TrainRunWayPoint(scheduled_at=19,
                             way_point=WayPoint(position=(3, 8), direction=1)),
            TrainRunWayPoint(scheduled_at=20,
                             way_point=WayPoint(position=(3, 8), direction=5))
        ],
        1: [
            TrainRunWayPoint(scheduled_at=0,
                             way_point=WayPoint(position=(3, 8), direction=3)),
            TrainRunWayPoint(scheduled_at=3,
                             way_point=WayPoint(position=(3, 7), direction=3)),
            TrainRunWayPoint(scheduled_at=5,
                             way_point=WayPoint(position=(3, 6), direction=3)),
            TrainRunWayPoint(scheduled_at=7,
                             way_point=WayPoint(position=(3, 5), direction=3)),
            TrainRunWayPoint(scheduled_at=9,
                             way_point=WayPoint(position=(3, 4), direction=3)),
            TrainRunWayPoint(scheduled_at=11,
                             way_point=WayPoint(position=(3, 3), direction=3)),
            TrainRunWayPoint(scheduled_at=13,
                             way_point=WayPoint(position=(2, 3), direction=0)),
            TrainRunWayPoint(scheduled_at=15,
                             way_point=WayPoint(position=(1, 3), direction=0)),
            TrainRunWayPoint(scheduled_at=17,
                             way_point=WayPoint(position=(0, 3), direction=0))
        ]
    }
    expected_action_plan = [
        [
            # take action to enter the grid
            ActionPlanElement(0, RailEnvActions.MOVE_FORWARD),
            # take action to enter the cell properly
            ActionPlanElement(1, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(2, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(3, RailEnvActions.STOP_MOVING),
            ActionPlanElement(13, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(14, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(15, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(16, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(17, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(18, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(19, RailEnvActions.STOP_MOVING)
        ],
        [
            ActionPlanElement(0, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(1, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(3, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(5, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(7, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(9, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(11, RailEnvActions.MOVE_RIGHT),
            ActionPlanElement(13, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(15, RailEnvActions.MOVE_FORWARD),
            ActionPlanElement(17, RailEnvActions.STOP_MOVING),
        ]
    ]

    MAX_EPISODE_STEPS = 50

    deterministic_controller = ControllerFromTrainRuns(env, chosen_path_dict)
    deterministic_controller.print_action_plan()
    ControllerFromTrainRuns.assert_actions_plans_equal(
        expected_action_plan, deterministic_controller.action_plan)
    ControllerFromTrainRunsReplayer.replay_verify(MAX_EPISODE_STEPS,
                                                  deterministic_controller,
                                                  env, rendering)
def test_shortest_path_predictor(rendering=False):
    rail, rail_map = make_simple_rail()
    env = RailEnv(
        width=rail_map.shape[1],
        height=rail_map.shape[0],
        rail_generator=rail_from_grid_transition_map(rail),
        schedule_generator=random_schedule_generator(),
        number_of_agents=1,
        obs_builder_object=TreeObsForRailEnv(
            max_depth=2, predictor=ShortestPathPredictorForRailEnv()),
    )
    env.reset()

    # set the initial position
    agent = env.agents[0]
    agent.initial_position = (5, 6)  # south dead-end
    agent.position = (5, 6)  # south dead-end
    agent.direction = 0  # north
    agent.initial_direction = 0  # north
    agent.target = (3, 9)  # east dead-end
    agent.moving = True
    agent.status = RailAgentStatus.ACTIVE

    env.reset(False, False)

    if rendering:
        renderer = RenderTool(env, gl="PILSVG")
        renderer.render_env(show=True, show_observations=False)
        input("Continue?")

    # compute the observations and predictions
    distance_map = env.distance_map.get()
    assert distance_map[0, agent.initial_position[0], agent.initial_position[1], agent.direction] == 5.0, \
        "found {} instead of {}".format(
            distance_map[agent.handle, agent.initial_position[0], agent.position[1], agent.direction], 5.0)

    paths = get_shortest_paths(env.distance_map)[0]
    assert paths == [
        WayPoint((5, 6), 0),
        WayPoint((4, 6), 0),
        WayPoint((3, 6), 0),
        WayPoint((3, 7), 1),
        WayPoint((3, 8), 1),
        WayPoint((3, 9), 1)
    ]

    # extract the data
    predictions = env.obs_builder.predictions
    positions = np.array(
        list(map(lambda prediction: [*prediction[1:3]], predictions[0])))
    directions = np.array(
        list(map(lambda prediction: [prediction[3]], predictions[0])))
    time_offsets = np.array(
        list(map(lambda prediction: [prediction[0]], predictions[0])))

    # test if data meets expectations
    expected_positions = [
        [5, 6],
        [4, 6],
        [3, 6],
        [3, 7],
        [3, 8],
        [3, 9],
        [3, 9],
        [3, 9],
        [3, 9],
        [3, 9],
        [3, 9],
        [3, 9],
        [3, 9],
        [3, 9],
        [3, 9],
        [3, 9],
        [3, 9],
        [3, 9],
        [3, 9],
        [3, 9],
        [3, 9],
    ]
    expected_directions = [
        [Grid4TransitionsEnum.NORTH],  # next is [5,6] heading north
        [Grid4TransitionsEnum.NORTH],  # next is [4,6] heading north
        [Grid4TransitionsEnum.NORTH],  # next is [3,6] heading north
        [Grid4TransitionsEnum.EAST],  # next is [3,7] heading east
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
        [Grid4TransitionsEnum.EAST],
    ]

    expected_time_offsets = np.array([
        [0.],
        [1.],
        [2.],
        [3.],
        [4.],
        [5.],
        [6.],
        [7.],
        [8.],
        [9.],
        [10.],
        [11.],
        [12.],
        [13.],
        [14.],
        [15.],
        [16.],
        [17.],
        [18.],
        [19.],
        [20.],
    ])

    assert np.array_equal(time_offsets, expected_time_offsets), \
        "time_offsets {}, expected {}".format(time_offsets, expected_time_offsets)

    assert np.array_equal(positions, expected_positions), \
        "positions {}, expected {}".format(positions, expected_positions)
    assert np.array_equal(directions, expected_directions), \
        "directions {}, expected {}".format(directions, expected_directions)