def test_update_with_lower_value_for_leaf_node(self): values = [1, 3, 5, 7, 9, 10, 11] names = ['A', 'B', 'C', 'D', 'E', 'F', 'G'] binary_heap = BinaryHeap(self.setup(names, values)) binary_heap.build_heap() binary_heap.update(6, 4) self.assertEqual([x.get_value_attribute() for x in binary_heap.node_list if x is not None], [1, 3, 4, 7, 9, 5, 11])
def test_delete_min(self): names = ['A', 'B', 'C', 'D', 'E', 'F', 'G'] values = [5, 3, 7, 1, 9, 10, 11] binary_heap = BinaryHeap(self.setup(names, values)) binary_heap.build_heap() self.assertEqual([x.get_value_attribute() for x in binary_heap.node_list if x is not None], [1, 3, 7, 5, 9, 10, 11]) self.assertEqual(binary_heap.delete_min().get_value_attribute(), 1)
def test_heap_delete_min_build_heap(benchmark, dsa_, values): nums = deepcopy(values) dsa_obj = BinaryHeap() dsa_obj.build_heap(values) to_del = values[len(values) // 2] benchmark(dsa_obj.delete_min)
def test_correctness(self): for case in cases: bheap = BinaryHeap() bheap.build_heap(case) retrieved = [] while len(bheap) > 0: retrieved.append(bheap.delete_min()) self.assertEqual(retrieved, sorted(case))
def task_1ab(): task_list = deepcopy(TASK_ONE_A) _, bh_obj = create_heap_for_loop_insert(task_list) # for-loop, insert() bh_linear = BinaryHeap() # New bh-obj for linear insertion bh_linear.build_heap(task_list) # Build with linear insertion # HeapList bh_list = ", ".join([str(l) for l in bh_obj.heapList[1::]]) bh_linear_list = ", ".join([str(l) for l in bh_linear.heapList[1::]]) # "For-loop"-obj walks xa, a = travers_tree_inorder(bh_obj) xb, b = travers_tree_postorder(bh_obj) xc, c = travers_tree_preorder(bh_obj) xd, d = level_order(bh_obj) # "Linear"-obj walks ignore, aa = travers_tree_inorder(bh_linear) ignore, bb = travers_tree_postorder(bh_linear) ignore, cc = travers_tree_preorder(bh_linear) ignore, dd = level_order(bh_linear) table = Table("Task", "Array", "Insert Method") table.add_row("1a, algorithm 1", bh_list, "for-loop") table.add_row("1b, algorithm 2", bh_linear_list, "Linear") table.add_row("", "", "") table.add_row("1c, " + xa, ", ".join([str(l) for l in a]), "for-loop") table.add_row("1c, " + xb, ", ".join([str(l) for l in b]), "for-loop") table.add_row("1c, " + xc, ", ".join([str(l) for l in c]), "for-loop") table.add_row("1c, " + xd, ", ".join([str(l) for l in d]), "for-loop") table.add_row("", "", "") table.add_row("1c, " + xa, ", ".join([str(l) for l in aa]), "Linear") table.add_row("1c, " + xb, ", ".join([str(l) for l in bb]), "Linear") table.add_row("1c, " + xc, ", ".join([str(l) for l in cc]), "Linear") table.add_row("1c, " + xd, ", ".join([str(l) for l in dd]), "Linear") console = Console() console.print(table)
def test_build_heap_with_sorted_list(self): values = [1, 3, 5, 7, 9, 10, 11] names = ['A', 'B', 'C', 'D', 'E', 'F', 'G'] binary_heap = BinaryHeap(self.setup(names, values)) binary_heap.build_heap() self.assertEqual([x.get_value_attribute() for x in binary_heap.node_list if x is not None], [1, 3, 5, 7, 9, 10, 11])
def test_heap_build(): bh_bh = BinaryHeap() bh_bh.build_heap(mock_lists[1]) return bh_bh
class AStar(): """ Paramaters: map: Reference to map object start_node_id: Index of start node dest_node_id: Index of destination node """ def __init__(self, map): self.map = map # Hash set to keep track of open intersections. The hash set will contain intersection IDs only # and will be used to find out if an intersection ID is already there is the set self.open = set() # Hash set to keep track of closed intersection ID. The hash set will contain intersection IDs only # and will be used to find out self.closed = set() # Dictionary to keep track of cost. The dictionary is keyed by intersection id # Cost will have three components. # g = true of cost of getting from source node to current node # h = estimated cost of getting from current node to destination node # f = total cost = g + h self.cost = {} # List used to store the actual path from destination path back to source intersection. # Once the shortest path to destination intersection is found, this will be reversed and returned as path from # source to destination self.nodes_in_path = [] # Dictionary to keep track of parent intersection. It is keyed by current intersection id. # Parent intersection ID is the intersection from where the current intersection is reached self.parent = {} # Initialize min binary heap. This will be used to get the intersection with minimum cost self.cost_heap = BinaryHeap() # Private method to get the intersection with minimum total cost def _get_node_with_min_cost(self): min_value_node = self.cost_heap.delete_min() # Remove the intersection with min cost from list of open intersections self.open.remove(min_value_node.id) # Put that intersection into closed intersections self.closed.add(min_value_node.id) return min_value_node # Returns the list of intersections that can be reached from the current intersection def _get_next_nodes(self, current_node_id): return self.map.roads[current_node_id] # Method that performs A-star search def search(self, start_node_id, dest_node_id): # Initialize the cost structure of first intersection self.cost[start_node_id] = { 'g': 0, # True cost of getting from start node to this node. This is calculated in terms of number of hops (edges) 'h': 0, # Estimated cost of getting this node to destination node 'f': 0 # Total cost. It is a computed field f = g + h } # Put the start node as the first open node where the search starts self.open.add(start_node_id) self.cost_heap.insert(HeapNode({'id': start_node_id, 'f': 0, 'g': 0, 'h' : 0}, 'f')) iteration = 1 while len(self.open) > 0: # Among all nodes which are open find the node with minimum total cost # This will be the nest node to explore current_node = self._get_node_with_min_cost() if current_node.id == dest_node_id: end_node = current_node.id while end_node is not None: self.nodes_in_path.append(end_node) end_node = self.parent.get(end_node, None) self.nodes_in_path.reverse() return self.nodes_in_path children = self._get_next_nodes(current_node.id) for child in children: # If the intersection is already in closed set then there is no need to explore it if child in self.closed: continue g = self.cost[current_node.id]['g'] + \ math.sqrt( math.pow(self.map.intersections[current_node.id][0] - self.map.intersections[child][0], 2) + \ math.pow(self.map.intersections[current_node.id][1] - self.map.intersections[child][1], 2)) # Estimate distance to destination intersection. This is pre euclidean distance. # This heuristic will always be less than or equal to the true distance of the road # connecting the two intersections h = math.sqrt( math.pow(self.map.intersections[child][0] - self.map.intersections[dest_node_id][0], 2) + \ math.pow(self.map.intersections[child][1] - self.map.intersections[dest_node_id][1], 2)) # If the child intersection is not in open set then put it in the list to explore # Compute the cost (cost to reach this intersection, estimated cost to reach destination # from here and total cost for this intersection # The child intersection may already be there if there way another intersection leading to this one # Update the cost values if cost of reaching this child intersection is lower than cost value # associated with the intersection if child not in self.open: self.cost[child] = {'g' : g, 'h' : h, 'f' : g + h} self.parent[child] = current_node.id self.open.add(child) self.cost_heap.insert(HeapNode({'id': child, 'f': g + h, 'g': g, 'h' : h}, 'f')) elif self.cost[child]['f'] > g + h: self.cost[child] = {'g' : g, 'h' : h, 'f' : g + h} self.parent[child] = current_node.id self.cost_heap.build_heap() #if iteration >= 1: # sys.exit(0) iteration += 1 # Generates SVG diagram for the graph and the shortest path found using A* search def draw_astar_map(self, path, colors, output_file): graph = pydot.Dot(graph_type='graph', rankdir="LR") nodes = {} edges = set() for k, v in self.map.intersections.items(): n = pydot.Node(k, shape="circle", style="filled", fillcolor="cyan" if k not in path else colors[0], tooltip="(%f,%f)" % (v[0], v[1])) nodes[k] = n graph.add_node(n) for src, dst in enumerate(self.map.roads): for d in dst: if (src,d) not in edges: distance = math.sqrt(math.pow(self.map.intersections[src][0] - self.map.intersections[d][0], 2) + \ math.pow(self.map.intersections[src][1] - self.map.intersections[d][1], 2)) edges.add((src,d)) edges.add((d,src)) if src in path and d in path: color = colors[1] style="bold" else: color = "black" style = "dashed" graph.add_edge(pydot.Edge(nodes[src], nodes[d], style=style, label="%0.2f" % distance, color=color, tooltip="%0.2f" % distance)) graph.write_svg(output_file)