Example #1
0
def jarnik(weighted_graph):
    """
    Return the minimum spanning tree of the given weighted graph.

    See CCSPiP Listing 4.11
    """
    result = []
    edge_queue = PriorityQueue()
    visited = [False] * weighted_graph.vertex_count

    # Procedure for visiting a vertex at the given index
    def visit(index):
        visited[index] = True
        for edge in weighted_graph.edges_for_index(index):
            if not visited[edge.v]:
                edge_queue.push(edge)

    # Start the problem
    visit(0)
    while not edge_queue.empty:
        edge = edge_queue.pop()
        # Never revisit any vertex
        if visited[edge.v]:
            continue
        # Because we're popping from a priority queue, the edge that is popped
        # must have the lowest weight
        result.append(edge)
        # Visit the next vertex
        visit(edge.v)
    return result
Example #2
0
 def reset(self,
           env: Optional[IEnvironment[OneHotImg, Action, Reward]],
           root_option: Option[Point],
           random_seed: Union[int, RandomState] = None) -> None:
     self.target_path = None
     self.waypoints = PriorityQueue()
     self.history = []
     self.visited = NumPyDict(dtype=np.int8)
     self.current_goal = root_option.value
     self.backstep = 0
     if random_seed is not None:
         self.random = optional_random(random_seed)
Example #3
0
def aStarSP(graph, start, goal):
    '''A* search for single prize. 
    graph is a list of points. (e.g. [[1,3],[4,5],[7,5]]
    a point is a list of two integers (e.g. [1,3])
    start and goal are two points in the maze
    '''
    # convert the lists into tuple, lists are unhashble
    start_t = copy.deepcopy(start)
    start_t = tuple(start_t)
    goal_t = copy.deepcopy(goal)
    goal_t = tuple(goal_t)

    print("start:{0}, start_t {1}".format(type(start), type(start_t)))
    print("goal:{0}, goal_t {1}".format(type(goal), type(goal_t)))
    # initialize an empty PQ
    explore_next = PriorityQueue()
    # Adding the start node to the the PQ. It has a priority of
    # cost being 0??
    explore_next.push(start, 0)
    # NEEDS TUPLE as data type
    cost_atm = {}
    # INSET TUPLE HERE
    cost_atm[start_t] = 0
    # TUPLE as data type
    predecessors = {}
    # INSERT TUPLE
    predecessors[start_t] = None

    while not explore_next.is_empty():
        # get the one with the smallest cost
        current_l = explore_next.pop()  # tuple
        current_t = copy.deepcopy(current_l)
        current_t = tuple(current_t)
        print(current_l, current_t)
        print("current_l:{0}, current_t {1}".format(type(current_l),
                                                    type(current_t)))
        print("BEFORE THE BREAK line")
        print(current_l, goal, type(current_l), type(goal))
        if current_l == goal:
            # go home, got the prize
            print("found the prize! {}".format(cost_atm[current_t]))
            break
        for next in graph.neighbors(current_l):
            next_t = copy.deepcopy(next)
            next_t = tuple(next_t)
            print("Where is the problem?")
            print("next:{0}, next_t {1}".format(type(next), type(next_t)))
            print("{0}{1}{2}".format(cost_atm[current_t], current_l, next))
            new_cost = cost_atm[current_t] + graph.cost(current_l, next)

            if next_t not in cost_atm or new_cost < cost_atm[next_t]:
                cost_atm[next_t] = new_cost
                print(type(new_cost))
                print(manDist(next, goal), type(manDist(next, goal)))
                priority = new_cost + manDist(next, goal)
                explore_next.push(next, priority)
                predecessors[next_t] = current_t
Example #4
0
 def __init__(self):
     self.target_path: Optional[List[DirectedPoint]] = None
     self.waypoints: PriorityQueue[List[DirectedPoint]] = PriorityQueue()
     self.history: List[DirectedPoint] = []
     self.visited: NumPyDict[Point, bool] = NumPyDict(dtype=np.int8)
     self.current_goal: Optional[Point] = None
     self.random: RandomState = optional_random()
     self.backstep: int = 0  # used if we are in the process of backing up
Example #5
0
def best_first_search(problem, f):
    node = Node(problem.initial_state)
    frontier = PriorityQueue(f)
    explored = set()
    frontier.append(node)
    nodes_generated = max_nodes_in_memory = 1
    nodes_expanded = 0
    while frontier:
        node = frontier.pop()
        nodes_expanded += 1
        if problem.goal_test(node.state):
            nodes_info = [nodes_generated, nodes_expanded, max_nodes_in_memory]
            return solution(node), nodes_info
        else:
            for action in problem.actions(node.state):
                nodes_generated += 1
                child = child_node(problem, node, action)
                if repr(child.state) not in explored:
                    explored.add(repr(child.state))
                    frontier.append(child)
        nodes_in_memory = len(frontier) + len(explored)
        if nodes_in_memory > max_nodes_in_memory:
            max_nodes_in_memory = nodes_in_memory
    nodes_info = [nodes_generated, nodes_expanded, max_nodes_in_memory]
    return None, nodes_info  # we couldn't find a solution
Example #6
0
def a_star(grid:np.array,start:tuple,end:tuple) -> Tuple[list,list]:
    """ A function that searches for the shortest path in a grid using the A* algorithm

        This function searches through a grid searching for the shortest path using the A* algorithm. The function first
        sets up a VisitedNodes object (visited) and a PriorityQueue object (priority_queue) to keep track of checked
        nodes. A Node object for the first starting position is created and pushed into the priority queue.
        While there are still objects in the priority_queue, the function will pull the first item from the
        priority_queue and store it in visited. The function will check that the current node's position is not equal
        to the end position; if it does then a visited list and path list is created by calling the appropriate methods
        from visited. Otherwise, the function iterates on the current node's children, and checks if they are already in
        visited or the priority_queue, and that the child is accessible (accessible > 0). If true, then child of the
        current node is added to the priority_queue along with the child's information.

        Parameters
        ----------
            grid : np.array
                a numpy array detailing the grid
            start : tuple
                a tuple detailing the starting node's position
            end : tuple
                a tuple detailing the ending node's position
        Returns
        -------
            Tuple[list,list]
                A list of visited nodes and a list of nodes that are included in the path

    """

    # heuristics used; diagonal_distance is used by default
    def euclidean_distance(child_node, end):
        return math.sqrt((pow(child_node[0]-end[0],2))+(pow(child_node[1]-end[1],2)))

    def manhattan_distance(child_node,end):
        return (abs(child_node[0] - end[0]) + abs(child_node[1]-end[1])) * 10

    def diagonal_distance(child_node,end):
        dx = abs(child_node[0] - end[0])
        dy = abs(child_node[1] - end[1])

        return 10 * (dx+dy) + (14 - 2 * 10) * min(dx,dy)

    if grid[start[0]][start[1]] == 1 or grid[end[0]][end[1]] == 1:
        return [None],[None]

    visited = VisitedNodes()
    priority_queue = PriorityQueue()
    priority_queue.push(Node(grid, start, neighbors="8_wind", cost=0, heuristic=diagonal_distance(start, end)))

    while len(priority_queue) > 0:
        node = priority_queue.pop()
        visited._store_node(node)
        if node.pos == end:
            visited_list,path_list = visited.create_path(node.pos, start)
            return visited_list,path_list
        else:
            for child in node.children:
                if child["node"] not in visited.visited_nodes and child["node"] not in priority_queue.queue_list and child["accessibility"]:
                    priority_queue.push(Node(grid, child["node"], parent=node.pos, neighbors="8_wind", cost=child["cost"],
                                             heuristic=diagonal_distance(child["node"], end)))
    return [None],[None]
 def reset(self,
         env: MazeWorld,
         root_option: Option[OptionData],
         random_seed: Union[int, RandomState] = None)-> None:
     self.env: MazeWorld = env
     self.queue: PriorityQueue[Point] = PriorityQueue()
     self.visited: NumPyDict[Point, bool] = NumPyDict(int)
     self.current_goal: Goal = root_option.value if root_option is not None else None
     self.history: List[State] = [ ]
     self.current_target: Target = None
Example #8
0
    def setUp(self):

        self.grid = np.genfromtxt("data_np.txt", delimiter=",", dtype=np.int)
        self.start = (4, 0)
        self.end = (0, 4)

        self.dfs_correct_returns = {
            "visited_list": [(4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (3, 4),
                             (3, 3), (3, 2), (2, 3), (2, 4), (1, 4), (0, 4)],
            "path_list": [(0, 4), (1, 4), (2, 4), (2, 3), (3, 3), (3, 4),
                          (4, 4), (4, 3), (4, 2), (4, 1), (4, 0)]
        }
        self.bfs_correct_returns = {
            "visited_list": [(4, 0), (3, 0), (4, 1), (4, 2), (3, 2), (4, 3),
                             (3, 3), (4, 4), (2, 3), (3, 4), (2, 4), (1, 4),
                             (0, 4)],
            "path_list": [(0, 4), (1, 4), (2, 4), (2, 3), (3, 3), (3, 2),
                          (4, 2), (4, 1), (4, 0)]
        }

        self.a_star_correct_returns = {
            "visited_list": [(4, 0), (3, 0), (4, 1), (3, 2), (2, 3), (1, 4),
                             (0, 4)],
            "path_list": [(0, 4), (1, 4), (2, 3), (3, 2), (4, 1), (4, 0)]
        }

        self.test_nodes = [
            Node(self.grid, (4, 0), cost=0, heuristic=12),
            Node(self.grid, (3, 0), cost=10, heuristic=10),
            Node(self.grid, (4, 1), cost=10, heuristic=8)
        ]

        self.maze = Maze(self.grid)
        self.priority_queue = PriorityQueue()
        self.stack = Stack()
        self.queue = Queue()
        self.visited = VisitedNodes()
Example #9
0
def aStarSP(graph, start, goal):
    '''A* search for single prize. 
    graph is a list of points. (e.g. [[1,3],[4,5],[7,5]]
    a point is a list of two integers (e.g. [1,3])
    start and goal are two points in the maze
    '''
    # convert the lists into tuple, lists are unhashble
    start_t = copy.deepcopy(start)
    start_t = tuple(start_t)
    goal_t = copy.deepcopy(goal)
    goal_t = tuple(goal_t)

    explore_next = PriorityQueue()
    explore_next.push(start, 0)
    visited_w_cost = {}
    visited_w_cost[start_t] = 0
    predecessors = {}
    predecessors[start_t] = None

    while not explore_next.is_empty():
        # get the one with the smallest cost
        current_l = explore_next.pop()  # tuple
        current_t = copy.deepcopy(current_l)
        current_t = tuple(current_t)
        # print (current_l, goal)
        # print ("{0}".format(explore_next.show_queue()))
        if current_l == goal:
            # go home, got the prize
            print("found the prize! {}".format(visited_w_cost[current_t]))
            break
        for next in graph.neighbors(current_l):
            next_t = copy.deepcopy(next)
            next_t = tuple(next_t)
            new_cost = visited_w_cost[current_t] + graph.cost(current_l, next)

            if next_t not in visited_w_cost or new_cost < visited_w_cost[
                    next_t]:
                visited_w_cost[next_t] = new_cost
                priority = new_cost + manDist(next, goal)

                if next == goal:
                    predecessors[next_t] = current_t
                    return predecessors
                graph.set_node(next, '#')
                explore_next.push(next, priority)
                predecessors[next_t] = current_t
Example #10
0
def a_star(initial, goal_test, successors, cost, heuristic):
    """
    A* search using priority queue.

    Parameters
    ----------
    initial : Generic
        Starting point of the search.
    goal_test : Callable
        Callable returing boolean value indicating search success.
    successors : Callable
        Callable returning list of next possible locations in search space.
    cost : Callable
        Cost function returning the cost of a proposed move between nodes in
        search space.
    heuristic : Callable
        Heuristic to evaluate proposed nodes

    Returns
    -------
    found : Generic
        Node corresponding to successful goal_test.
        Returns None if search fails.
    """
    # Initialize frontier
    frontier = PriorityQueue()
    frontier.push(Node(initial, None, cost=0.0,
                       heuristic=heuristic(initial)))
    # Structure for holding explored nodes (with their costs)
    explored = {initial : 0.0}

    # Continue search as long as their are candidates in the search space
    while not frontier.empty:
        current_node = frontier.pop()
        current_state = current_node.state
        # If current node meets goal, then search completes successfully
        if goal_test(current_state):
            return current_node
        # Populate next step in search
        for child in successors(current_state):
            new_cost = cost(current_node)
            if child not in explored or explored[child] > new_cost: 
                explored[child] = new_cost
                frontier.push(Node(child,
                                   parent_node=current_node,
                                   cost=new_cost,
                                   heuristic=heuristic(child)))
    # Search terminates without finding goal
    return None
Example #11
0
def dijkstra(weighted_graph, root_vertex):
    """
    Dijkstra's algorithm for computing the path with the minimum weight from
    root_vertex to every other vertex in a weighted graph.

    Parameters
    ----------
    weighted_graph : graph.WeightedGraph
        Weighted graph over which search will be conducted.
    root_vertex : Generic
        Vertex in weighted_graph from which paths will originate.

    Returns
    -------
    distances : tuple
        Minimum distances (weights) from root to every other vertex
    path_dict : dict
        Dictionary of weighted edges mapping the shortest edge between each
        node
    """
    # Starting point
    first = weighted_graph.index_of(root_vertex)
    # Initialized distances to all other vertices
    distances = [None] * weighted_graph.vertex_count
    distances[first] = 0
    # Initialize mapping of vertices to their min paths
    path_dict = {}
    # Initialize search queue
    node_queue = PriorityQueue()
    node_queue.push(DijkstraNode(first, 0))

    while not node_queue.empty:
        # Known node and distance
        u = node_queue.pop().vertex
        dist_u = distances[u]
        for we in weighted_graph.edges_for_index(u):
            # Get previous distance to this vertex
            dist_v = distances[we.v]
            # If the vertex hasn't been visited yet, or the new distance is
            # lower than the original, update the distance to the node
            if dist_v is None or dist_v > dist_u + we.weight:
                distances[we.v] = dist_u + we.weight
                # Update edge on shortest path to this vertex
                path_dict[we.v] = we
                # Explore it soon
                node_queue.push(DijkstraNode(we.v, dist_u + we.weight))
    return distances, path_dict
Example #12
0
def a_star(graph, start, goal):
    came_from = dict()
    came_from[start] = None

    cost_dict = dict()
    cost_dict[start] = 0

    # Using a custom Priority Queue class instead of heapq, cleaner
    frontier = PriorityQueue()
    frontier.enqueue(start, 0)
    # frontier = [(0, start)]
    # while len(frontier) > 0:
    while not frontier.is_empty():
        # popped_item = frontier.dequeue()
        # current, priority = popped_item.element, popped_item.priority
        current, priority = frontier.pop_item()
        # current = heapq.heappop(frontier)[1]
        if current == goal:
            break

        for next in graph.roads[current]:
            # we need to calculate the path cost now, which is the total cost through the current point to the next point
            path_cost = calculate_distance(graph.intersections[current], graph.intersections[next])
            new_cost = cost_dict[current] + path_cost

            if next not in cost_dict or new_cost < cost_dict[next]:
                # we need to record the best path
                cost_dict[next] = new_cost

                # calculating the priority from the next road to the goal road
                priority = new_cost + calculate_distance(graph.intersections[next], graph.intersections[goal])

                # add this to the frontier
                frontier.enqueue(next, priority)

                came_from[next] = current
    # print(came_from)
    # print(cost_dict)
    return best_path(came_from, start, goal)
Example #13
0
    def __init__(self,
                 arrivals: List[List[ArrivalEvent]],
                 queries: List[List[QueryEvent]],
                 departures: List[List[int]],
                 initial_station_state: np.ndarray,
                 initial_car_state: np.ndarray,
                 station_info: np.ndarray,
                 car_speed: float,
                 logging: bool = False,
                 **kwargs):
        """

        :param arrivals: List[List[ArrivalEvents]]: [max_t, ]
            list of arrivals at each timestep
        :param queries: List[List[QueryEvent]]: [max_ t, ]
            list of queries at each timestep
        :param departures: List[List[int]]: [max_t, ]
            list of indices of stations being departed from at each
            timestep. Multiple cars may depart from same station at
            one timestep
        :param initial_station_state:  np.ndarray[int8] : [n_stations, 1]
            initial number of occupied slots at stations
        :param initial_car_state: np.ndarray[float32] : [max_cars, 7]
            idx => (used, car_x, car_y, station_idx, station_x, station_y,
                duration)
            initial locations and destinations of cars by rows
            used should be 1 if row has data and 0 if empty
        :param station_info: np.ndarray[float32] : [n_stations, 3]
            idx => (x, y, max_occupancy)
            information about each station, indexed by rows
        :param car_speed: float
            how far each car moves towards destination at each timestep
        :param logging: bool = False
            whether or not to store a summary to generate
        :param kwargs: for compatibility
        """
        assert len(arrivals) == len(queries)
        assert np.all(station_info[:, 2] > 0)  # all stations have spots

        self.car_speed: float = car_speed

        self.arrivals: List[List[ArrivalEvent]] = arrivals
        self.queries: List[List[QueryEvent]] = queries
        self.departures: List[List[int]] = departures
        self.station_state: np.ndarray = initial_station_state[:, np.newaxis]
        self.car_state: np.ndarray = initial_car_state
        self.station_info: np.ndarray = station_info
        self.logging = logging

        self.open_car_indices: PriorityQueue[int] = PriorityQueue()
        for idx in reversed(range(self.car_state.shape[0])):
            if not np.any(self.car_state[idx, :]):  # all 0
                self.open_car_indices.push(idx, idx)

        # these variables should stay static, only for tracking
        # and clarity of code
        self.total_arrivals: int = sum(map(len, arrivals))
        self.total_queries: int = sum(map(len, queries))
        self.max_cars: int = self.car_state.shape[0]
        self.n_stations: int = self.station_state.shape[0]
        self.total_spots: int = np.sum(initial_car_state[:, 2])
        self.max_t: int = len(arrivals)

        if self.max_cars < self.total_queries + self.total_arrivals:
            # warnings.warn("Warning: Fill up of car slots possible")
            pass

        self.t: int = 0
        self._cur_reward: np.ndarray = self._zero_reward_()
        self._summary_ = {
            'distances travelled': [],
            'failed dispatches': 0,
            'timesteps travelled': [],
            'nearest distances': [],
            'organic fails': 0,
            'original queries': list(map(len, self.queries)),
            'actual queries': [0 for _ in range(self.max_t)],
            'n_stations': self.n_stations,
            'recommendation freq': np.zeros(self.n_stations)
        }
Example #14
0
class MinigridBacktrackingAgent(IOptionBasedAgent[OneHotImg, Action, Reward,
                                                  Point]):
    directions: List[np.ndarray] = [
        np.asarray([1, 0], dtype=np.int8),
        np.asarray([-1, 0], dtype=np.int8),
        np.asarray([0, 1], dtype=np.int8),
        np.asarray([0, -1], dtype=np.int8)
    ]

    def __init__(self):
        self.target_path: Optional[List[DirectedPoint]] = None
        self.waypoints: PriorityQueue[List[DirectedPoint]] = PriorityQueue()
        self.history: List[DirectedPoint] = []
        self.visited: NumPyDict[Point, bool] = NumPyDict(dtype=np.int8)
        self.current_goal: Optional[Point] = None
        self.random: RandomState = optional_random()
        self.backstep: int = 0  # used if we are in the process of backing up

    def reset(self,
              env: Optional[IEnvironment[OneHotImg, Action, Reward]],
              root_option: Option[Point],
              random_seed: Union[int, RandomState] = None) -> None:
        self.target_path = None
        self.waypoints = PriorityQueue()
        self.history = []
        self.visited = NumPyDict(dtype=np.int8)
        self.current_goal = root_option.value
        self.backstep = 0
        if random_seed is not None:
            self.random = optional_random(random_seed)

    def view(self, transition: Transition[OneHotImg, Action, Reward]) -> None:
        dpoint: DirectedPoint = onehot2directedpoint(transition.state)
        self._record_(dpoint)

    def act(self, state: OneHotImg, option: Option[Point]) -> Action:
        goal: Point = option.value
        if self.current_goal is None or not np.array_equal(
                goal, self.current_goal):
            self.reset(None, option, None)
        self._record_(onehot2directedpoint(state))
        self._add_potential_targets_(state, goal)
        self._set_target_path_(state, goal)
        if self.backstep != 0:
            # currently undoing forward action
            return self._backup_()
        return self._follow_target_path_(state)

    def optimize(self) -> None:
        pass

    @staticmethod
    def _achieved_goal_(state: OneHotImg, goal: Point) -> bool:
        location: Point = find(state, 'Agent')
        return np.array_equal(location, goal)

    def _add_potential_targets_(self, state: OneHotImg, goal: Point) -> None:
        location: Point = find(state, 'Agent')
        possibilities: Iterable[Point] = map(
            lambda dxdy: location + dxdy, MinigridBacktrackingAgent.directions)
        possibilities = filter(
            lambda point: self._is_valid_point_(state, point), possibilities)
        # ^ doesn't appear to do anything b/c minigrid has walls on the edges
        possibilities = filter(lambda point: tile_type(state, point) != "Wall",
                               possibilities)
        possibilities = filter(lambda point: point not in self.visited,
                               possibilities)
        for point in possibilities:
            path_to: List[DirectedPoint] = self._navigate_to_(
                From=onehot2directedpoint(state), To=point)
            distance: float = self._distance_(point, goal)
            self.waypoints.push(self._join_paths_(self.history, path_to),
                                distance)

    def _backup_(self) -> Action:
        if self.backstep == 2:
            self._increment_backstep_()
            return 2  # forward
        else:
            self._increment_backstep_()
            return 1  # left

    def _distance_(self, point1: Point, point2: Point) -> float:
        return manhattan_distance(point1, point2)

    def _find_last_common_index_(self, series1: List[DirectedPoint],
                                 series2: List[DirectedPoint]) -> int:
        highest_index: int = -1
        for index in range(len(series1)):
            if index >= len(series2) or \
                    not np.array_equal(series1[index], series2[index]):
                return highest_index
            highest_index = index
        return highest_index

    def _follow_target_path_(self, state: OneHotImg) -> Action:
        last_common_index: int = self._find_last_common_index_(
            self.history, self.target_path)
        if last_common_index + 1 < len(self.history):
            #
            # history has things that target path doesn't
            return self._replicate_move_(From=self.history[-1],
                                         To=self.history[-2])
        else:
            return self._replicate_move_(
                From=self.target_path[last_common_index],
                To=self.target_path[last_common_index + 1])

    def _increment_backstep_(self):
        self.backstep += 1
        self.backstep %= 5
        if self.backstep == 0:
            # remove all of the backing up from history
            self.history = self.history[:-5]

    def _is_valid_point_(self, state: OneHotImg, point: Point) -> bool:
        """
        Returns true if point is inbounds for xy values of the image
        :param state: used only for dimensions
        :param point: the point that we're checking, xy coordinates
        :return: if the xy coordinates specify a point on the image
        """
        return np.array_equal(np.clip(point, a_min=0, a_max=state.shape[:2]),
                              point)

    @staticmethod
    def _join_paths_(first: List[DirectedPoint],
                     second: List[DirectedPoint]) -> List[DirectedPoint]:
        result: List[DirectedPoint] = first
        for addition in second:
            if len(result) >= 2 and np.array_equal(addition, result[-2]):
                # we backtracked, so we can just delete the backtrack
                result = result[:-2]
            result = result + [addition]
        return result

    def _navigate_to_(self, From: DirectedPoint,
                      To: Point) -> List[DirectedPoint]:
        from_point: Point = From[:2]
        from_dir: np.ndarary = From[2:]
        #np.ndarray[int8] : [2, ] [dx, dy]
        dxdy = To - from_point
        if np.all(dxdy == 0):  # From = To
            return []  #already there, end trajectory
        assert is_onehot(abs(dxdy))
        # target is one distance from current point
        if np.dot(dxdy, from_dir) == -1:
            # we are facing the opposite direction of what we need
            new_dir = from_dir[::-1]  # arbitrary 90 degree turn
            new_point = from_point
        elif np.array_equal(dxdy, from_dir):
            # already facing correct direction
            new_dir = from_dir
            new_point = from_point + from_dir  #move in direction
        else:  # need to turn 90 degrees to dxdy
            new_dir = dxdy
            new_point = from_point
        next_dir_point: DirectedPoint = np.concatenate(
            (new_point, new_dir)).astype(np.int8)
        return [next_dir_point] + self._navigate_to_(From=next_dir_point,
                                                     To=To)

    def _record_(self, state: DirectedPoint) -> None:
        if len(self.history) == 0 or not np.array_equal(
                state, self.history[-1]):
            self.history = self._join_paths_(self.history, [state])
            self.visited[state[:2]] = True

    def _replicate_move_(self, From: DirectedPoint,
                         To: DirectedPoint) -> Action:
        from_point: Point = From[:-2]
        to_point: Point = To[:-2]
        from_dir: Point = From[2:]
        to_dir: Point = To[2:]
        assert np.array_equal(from_point, to_point) or \
                np.array_equal(from_dir, to_dir)
        # can only turn OR move, not both
        assert np.dot(from_dir,
                      to_dir) != -1  # can't replicate 180 degree turn
        assert is_onehot(abs(to_dir)) and is_onehot(abs(from_dir))
        if np.array_equal(from_point, to_point):
            sine: int = np.cross(from_dir, to_dir)
            if sine == 1:
                return 1  # right
            elif sine == -1:
                return 0  # left
            else:
                raise Exception("shouldn't get here")
        else:
            if np.array_equal((to_point - from_point), from_dir):
                # we are facing in the right direction
                return 2  # move forward
            else:
                # our last move was forward, so we need to rotate 180
                # then move forward,then rotate 180 to undo it
                return self._backup_()

    def _set_target_path_(self, state: OneHotImg, goal: Point) -> None:
        if self.target_path is None:
            self.target_path = self.waypoints.pop()
            return self._set_target_path_(state, goal)
        elif self.target_path[-1][:-2] in self.visited:
            self.target_path = None
            return self._set_target_path_(state, goal)
Example #15
0
 def tearDown(self):
     self.priority_queue = PriorityQueue()
     self.stack = Stack()
     self.queue = Queue()
     self.visited = VisitedNodes()
Example #16
0
class PathfindingTests(unittest.TestCase):

    ############################
    #### setup and teardown ####
    ############################

    def setUp(self):

        self.grid = np.genfromtxt("data_np.txt", delimiter=",", dtype=np.int)
        self.start = (4, 0)
        self.end = (0, 4)

        self.dfs_correct_returns = {
            "visited_list": [(4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (3, 4),
                             (3, 3), (3, 2), (2, 3), (2, 4), (1, 4), (0, 4)],
            "path_list": [(0, 4), (1, 4), (2, 4), (2, 3), (3, 3), (3, 4),
                          (4, 4), (4, 3), (4, 2), (4, 1), (4, 0)]
        }
        self.bfs_correct_returns = {
            "visited_list": [(4, 0), (3, 0), (4, 1), (4, 2), (3, 2), (4, 3),
                             (3, 3), (4, 4), (2, 3), (3, 4), (2, 4), (1, 4),
                             (0, 4)],
            "path_list": [(0, 4), (1, 4), (2, 4), (2, 3), (3, 3), (3, 2),
                          (4, 2), (4, 1), (4, 0)]
        }

        self.a_star_correct_returns = {
            "visited_list": [(4, 0), (3, 0), (4, 1), (3, 2), (2, 3), (1, 4),
                             (0, 4)],
            "path_list": [(0, 4), (1, 4), (2, 3), (3, 2), (4, 1), (4, 0)]
        }

        self.test_nodes = [
            Node(self.grid, (4, 0), cost=0, heuristic=12),
            Node(self.grid, (3, 0), cost=10, heuristic=10),
            Node(self.grid, (4, 1), cost=10, heuristic=8)
        ]

        self.maze = Maze(self.grid)
        self.priority_queue = PriorityQueue()
        self.stack = Stack()
        self.queue = Queue()
        self.visited = VisitedNodes()

    def tearDown(self):
        self.priority_queue = PriorityQueue()
        self.stack = Stack()
        self.queue = Queue()
        self.visited = VisitedNodes()

    ###############
    #### tests ####
    ###############

    #### Algorithm Testing ####

    # settings decorator with verbosity to show inputs and errors in terminal
    #@settings(verbosity=Verbosity.verbose)
    # given decorater to set up the inputs, we use hypo array (imported above) to create a mock numpy array for the grid
    # st.tuples(st.integer(),st.integer()) is creating a tuple with two integers set between 0 to 4
    @given(hypo_array(dtype=np.int, shape=(5, 5), elements=st.integers(0, 1)),
           st.tuples(st.integers(0, 4), st.integers(0, 4)),
           st.tuples(st.integers(0, 4), st.integers(0, 4)))
    # the above will paramaterize the function and for this particular test we assert that the function will return
    # two lists.
    def test_dfs_assert_return_lists(self, grid, start, end):
        visited_list, path_list = dfs(grid, start, end, _stack=Stack())
        assert visited_list
        assert path_list

    def test_dfs_assert_equal_return_lists(self):
        visited_list, path_list = dfs(self.grid,
                                      self.start,
                                      self.end,
                                      _stack=Stack())
        self.assertEqual(
            visited_list, self.dfs_correct_returns["visited_list"],
            "tested visited_list is not equal to correct visited list")
        self.assertEqual(path_list, self.dfs_correct_returns["path_list"],
                         "tested path_list is not equal to correct path list")

    @given(hypo_array(dtype=np.int, shape=(5, 5), elements=st.integers(0, 1)),
           st.tuples(st.integers(0, 4), st.integers(0, 4)),
           st.tuples(st.integers(0, 4), st.integers(0, 4)))
    def test_bfs_assert_return_lists(self, grid, start, end):
        visited_list, path_list = bfs(grid, start, end)
        assert visited_list
        assert path_list

    def test_bfs_assert_equal_return_lists(self):
        visited_list, path_list = bfs(self.grid, self.start, self.end)
        self.assertEqual(
            visited_list, self.bfs_correct_returns["visited_list"],
            "tested visited_list is not equal to correct visited list")
        self.assertEqual(path_list, self.bfs_correct_returns["path_list"],
                         "tested path_list is not equal to correct path list")

    @given(hypo_array(dtype=np.int, shape=(5, 5), elements=st.integers(0, 1)),
           st.tuples(st.integers(0, 4), st.integers(0, 4)),
           st.tuples(st.integers(0, 4), st.integers(0, 4)))
    def test_a_star_assert_return_lists(self, grid, start, end):
        visited_list, path_list = a_star(grid, start, end)
        assert visited_list
        assert path_list

    def test_a_star_assert_equal_return_lists(self):
        visited_list, path_list = a_star(self.grid, self.start, self.end)
        self.assertEqual(
            visited_list, self.a_star_correct_returns["visited_list"],
            "tested visited_list is not equal to correct visited list")
        self.assertEqual(path_list, self.a_star_correct_returns["path_list"],
                         "tested path_list is not equal to correct path list")

    #### Class Testing ####

    def test_stack_push_assert_in(self):
        self.stack.push(self.test_nodes[0])
        self.assertIn(self.test_nodes[0], self.stack.stacked_nodes,
                      "Was not able to push node into stack")

    def test_stack_pop_assert_sequence_equal(self):
        for test_node in self.test_nodes:
            self.stack.push(test_node)
        self.assertEqual(self.stack.pop(), self.test_nodes.pop(-1),
                         "Popped value incorrect.")

    def test_queue_push_assert_in(self):
        self.queue.push(self.test_nodes[0])
        self.assertIn(self.test_nodes[0], self.queue.queued_nodes,
                      "Test node not in queue")

    def test_queue_pop_assert_sequence_equal(self):
        for test_node in self.test_nodes:
            self.queue.push(test_node)
        self.assertEqual(self.queue.pop(), self.test_nodes.pop(0),
                         "Popped value incorrect")

    def test_priority_queue_push(self):
        self.priority_queue.push(self.test_nodes[0])
        self.assertIn(self.test_nodes[0], self.priority_queue.queued_nodes,
                      "Was not able to push Node into priority queue.")

    def test_priority_queue_prioritize(self):
        for node in self.test_nodes[1:]:
            self.priority_queue.push(node)
        self.assertEqual(self.priority_queue.queued_nodes[0],
                         self.test_nodes[2],
                         "prioritize failed with test nodes.")

    def test_priority_queue_pop(self):
        for node in self.test_nodes:
            self.priority_queue.push(node)
        self.priority_queue.pop()
        self.assertSequenceEqual(self.priority_queue.queued_nodes,
                                 [self.test_nodes[1], self.test_nodes[2]],
                                 "pop failed with test nodes.")

    def test_visited_nodes_store_node(self):
        pass

    def test_visited_nodes_create_path(self):
        pass