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
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 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
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 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
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
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 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
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
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
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)
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) }
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)
def tearDown(self): self.priority_queue = PriorityQueue() self.stack = Stack() self.queue = Queue() self.visited = VisitedNodes()
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