def generate_guided_search_figure(G, positions, src, target): """Generate Guided Search solution .. ultimately omitted from book.""" if plt_error: return None import matplotlib.pyplot as plt (G, positions, _) = tmg_load(highway_map()) plt.clf() plot_gps(positions) plot_highways(positions, G.edges()) def distance_gps(from_cell, to_cell): """These ids are indexed into positions to get GPS coordinates.""" return abs(positions[from_cell][0] - positions[to_cell][0]) + abs(positions[from_cell][1] - positions[to_cell][1]) node_from = guided_search(G, src, target, distance=distance_gps) total = compute_distance(positions, node_from, src, target) plot_node_from(positions, src, target, node_from, color='purple') print( '{0} total steps for Guided Search with distance={1:.1f} miles'.format( len(path_to(node_from, src, target)) - 1, total)) plt.axis('off') output_file = image_file('figure-mass-highway-guided.svg') plt.savefig(output_file, format="svg") print(output_file) plt.clf() return output_file
def generate_bfs_and_dijkstra_figure(src, target): """Generate BFS solution overlaying Massachusetts highway.""" if plt_error: return None import matplotlib.pyplot as plt (G, positions, _) = tmg_load(highway_map()) (dist_to, edge_to) = dijkstra_sp(G, src) print('Dijkstra shortest distance is {} total steps with distance={:.1f}'. format( len(edges_path_to(edge_to, src, target)) - 1, dist_to[target])) path = edges_path_to(edge_to, src, target) plt.clf() plot_gps(positions) plot_highways(positions, G.edges()) plot_path(positions, path) node_from = bfs_search(G, src) total = compute_distance(positions, node_from, src, target) plot_node_from(positions, src, target, node_from, color='purple') print( '{0} total steps for Breadth First Search with distance={1:.1f} miles'. format(len(path_to(node_from, src, target)) - 1, total)) plt.axis('off') output_file = image_file('figure-mass-highway-bfs.svg') plt.savefig(output_file, format="svg") print(output_file) plt.clf() return output_file
def chained_dijkstra(): """Generate Chained Dijkstra results with MA highway data.""" from ch07.tmg_load import tmg_load, highway_map from ch07.dependencies import plt_error from ch07.single_source_sp import dijkstra_sp if not plt_error: (G, positions, _) = tmg_load(highway_map()) start_time = time.time() longest_so_far = 0 start = -1 end = -1 for i in range(G.number_of_nodes()): (dist_to, _) = dijkstra_sp(G, i) for j in range(i + 1, G.number_of_nodes()): if dist_to[j] > longest_so_far: longest_so_far = dist_to[j] start = i end = j end_time = time.time() print( 'start {} to end {} in longest shortest distance {} in time {:.3f} seconds' .format(positions[start], positions[end], longest_so_far, end_time - start_time))
def test_bounding(self): from ch07.tmg_load import tmg_load, highway_map, bounding_ids (_, positions, _) = tmg_load(highway_map()) (NORTH, EAST, SOUTH, WEST) = bounding_ids(positions) self.assertTrue(positions[NORTH][0] > positions[SOUTH][0]) # LAT Is higher for north self.assertTrue( positions[EAST][1] > positions[WEST][1]) # LONG is higher for east
def test_generate_guided_search_figure(self): from ch07.book import generate_guided_search_figure from ch07.tmg_load import tmg_load, highway_map, bounding_ids from ch07.dependencies import plt_error if not plt_error: (G, positions, _) = tmg_load(highway_map()) (_, EAST, _, WEST) = bounding_ids(positions) output_file = generate_guided_search_figure( G, positions, WEST, EAST) self.assertTrue(path.isfile(output_file))
def avoid_interstate_90(): """Find shortest path from westernmost-MA to easternmost-MA that avoids I-90.""" if plt_error: return None import matplotlib.pyplot as plt from ch07.single_source_sp import dijkstra_sp, edges_path_to from ch07.tmg_load import tmg_load, plot_gps, plot_highways, bounding_ids from resources.highway import highway_map from ch07.plot_map import plot_path from algs.output import image_file (G,positions,labels) = tmg_load(highway_map()) # Since graph is undirected, we will visit each edge twice. Make sure to # only remove when u < v to avoid deleting same edge twice edges_to_remove = [] destination = None for u in G.nodes(): if labels[u] == 'I-90@134&I-93@20&MA3@20(93)&US1@I-93(20)': # SPECIAL LABEL in BOSTON destination = u for v in G.adj[u]: if 'I-90' in labels[u] and 'I-90' in labels[v] and u < v: edges_to_remove.append((u,v)) (_,_,_,WEST) = bounding_ids(positions) (dist_to, edge_to) = dijkstra_sp(G, WEST) print('Original Dijkstra shortest distance is {} total steps with distance={:.1f}'.format(len(edges_path_to(edge_to, WEST, destination))-1, dist_to[destination])) print('num edges:', G.number_of_edges()) for e in edges_to_remove: G.remove_edge(e[0], e[1]) print('num edges:', G.number_of_edges()) # create a new graph whose edges are not wholly on I-90 (_,_,_,WEST) = bounding_ids(positions) (dist_to, edge_to) = dijkstra_sp(G, WEST) print('Dijkstra shortest distance avoiding I-90 is {} total steps with distance={:.1f}'.format(len(edges_path_to(edge_to, WEST, destination))-1, dist_to[destination])) path = edges_path_to(edge_to,WEST, destination) plt.clf() plot_gps(positions) plot_highways(positions, G.edges()) plot_path(positions, path) output_file = image_file('figure-mass-no-I-90-dijkstra.svg') plt.savefig(output_file, format="svg") print(output_file) plt.clf() return output_file
def floyd_warshall_highway(): """Generate Floyd-Warshall results with MA highway data.""" from ch07.tmg_load import tmg_load, highway_map from ch07.dependencies import plt_error if not plt_error: (G, positions, _) = tmg_load(highway_map()) from networkx.algorithms.shortest_paths.dense import floyd_warshall print('This might take awhile') start_fw_time = time.time() dist_to = floyd_warshall(G, weight='weight') longest_so_far = 0 start = -1 end = -1 for i in range(G.number_of_nodes()): for j in range(i + 1, G.number_of_nodes()): if dist_to[i][j] > longest_so_far: longest_so_far = dist_to[i][j] start = i end = j end_fw_time = time.time() print( 'start {} to end {} in longest shortest distance {} in time {:.3f} seconds' .format(positions[start], positions[end], longest_so_far, end_fw_time - start_fw_time)) # so much faster since graph is sparse from networkx.algorithms.shortest_paths.weighted import all_pairs_dijkstra_path_length start_time = time.time() dist_to = dict(all_pairs_dijkstra_path_length(G)) longest_so_far = 0 start = -1 end = -1 for i in range(G.number_of_nodes()): for j in range(i + 1, G.number_of_nodes()): if dist_to[i][j] > longest_so_far: longest_so_far = dist_to[i][j] start = i end = j end_time = time.time() print( 'start {} to end {} in longest shortest distance {} in time {:.3f} seconds' .format(positions[start], positions[end], longest_so_far, end_time - start_time))
def generate_dfs_figure(src, target): """Generate DFS solution overlaying Massachusetts highway.""" if plt_error: return None import matplotlib.pyplot as plt (G, positions, _) = tmg_load(highway_map()) plt.clf() plot_gps(positions) plot_highways(positions, G.edges()) node_from = dfs_search_recursive(G, src) total = compute_distance(positions, node_from, src, target) plot_node_from(positions, src, target, node_from, color='purple') print('{0} total steps for Depth First Search with distance={1:.1f} miles'. format(len(path_to(node_from, src, target)) - 1, total)) plt.axis('off') output_file = image_file('figure-mass-highway-dfs.svg') plt.savefig(output_file, format="svg") print(output_file) plt.clf() return output_file
def generate_ch07(): """Generate Tables and Figures for chapter 07.""" chapter = 7 with FigureNum(23) as figure_number: description = 'Initialize dist_to[][] and node_from[][] based on G' label = caption(chapter, figure_number) DG_TABLE = nx.DiGraph() DG_TABLE.add_edge('a', 'b', weight=4) DG_TABLE.add_edge('b', 'a', weight=2) DG_TABLE.add_edge('a', 'c', weight=3) DG_TABLE.add_edge('b', 'd', weight=5) DG_TABLE.add_edge('c', 'b', weight=6) DG_TABLE.add_edge('d', 'b', weight=1) DG_TABLE.add_edge('d', 'c', weight=7) visualize_results_floyd_warshall_just_initialize(DG_TABLE) print('{}. {}'.format(label, description)) print() with FigureNum(24) as figure_number: description = 'Changes to node_from[][] and dist_to[][] after k processes a and b' label = caption(chapter, figure_number) DG_TABLE = nx.DiGraph() DG_TABLE.add_edge('a', 'b', weight=4) DG_TABLE.add_edge('b', 'a', weight=2) DG_TABLE.add_edge('a', 'c', weight=3) DG_TABLE.add_edge('b', 'd', weight=5) DG_TABLE.add_edge('c', 'b', weight=6) DG_TABLE.add_edge('d', 'b', weight=1) DG_TABLE.add_edge('d', 'c', weight=7) visualize_results_floyd_warshall_two_steps(DG_TABLE) print('{}. {}'.format(label, description)) print() with FigureNum(1) as figure_number: description = 'Modeling different problems using graphs' print('by hand') label = caption(chapter, figure_number) print('{}. {}'.format(label, description)) print() with FigureNum(2) as figure_number: description = 'An undirected graph of 12 vertices and 12 edges' make_sample_graph() label = caption(chapter, figure_number) print('{}. {}'.format(label, description)) print() with FigureNum(3) as figure_number: description = 'A graph modeling a rectangular maze' label = caption(chapter, figure_number) from ch07.viewer import Viewer random.seed(15) m = Maze(3, 5) g = to_networkx(m) postscript_output = '{}-graph.ps'.format(label) if tkinter_error: print('unable to generate {}'.format(postscript_output)) else: root = tkinter.Tk() canvas = Viewer(m, 50).view(root) tkinter_register_snapshot(root, canvas, postscript_output) root.mainloop() # For obscure reasons, this must come AFTER root.mainloop() if plt_error: pass else: import matplotlib.pyplot as plt pos = nx.get_node_attributes(g, 'pos') nx.draw(g, pos, with_labels=True, node_color='w', font_size=8) output_file = image_file('{}-graph.svg'.format(label)) plt.savefig(output_file, format="svg") print('created {}'.format(output_file)) print('{}. {}'.format(label, description)) print() with FigureNum(4) as figure_number: description = 'Hitting a dead end while exploring a maze' print('Hand drawn overlay to Figure 7-2.') label = caption(chapter, figure_number) print('{}. {}'.format(label, description)) print() with FigureNum(5) as figure_number: from ch07.search import dfs_search, draw_solution description = 'Depth First Search locates target if reachable from source' label = caption(chapter, figure_number) random.seed(15) m = Maze(3, 5) graph = to_networkx(m) if plt_error: print('unable to draw graph') else: draw_solution(graph, dfs_search(graph, m.start()), m.start(), m.end()) output_file = image_file('{}-graph.svg'.format(label)) plt.savefig(output_file, format="svg") print('created {}'.format(output_file)) print('{}. {}'.format(label, description)) print() with FigureNum(6) as figure_number: description = 'Breadth First Search will locate shortest path to target, if reachable from source' print('Hand drawn overlay to Figure 7-2.') label = caption(chapter, figure_number) print('{}. {}'.format(label, description)) print() with FigureNum(7) as figure_number: description = 'Breadth First Search finds shortest path to each node' label = caption(chapter, figure_number) random.seed(15) m = Maze(3, 5) graph = to_networkx(m) if plt_error: print('unable to draw graph') else: draw_solution(graph, bfs_search(graph, m.start()), m.start(), m.end()) output_file = image_file('{}-graph.svg'.format(label)) plt.savefig(output_file, format="svg") print('created {}'.format(output_file)) print('{}. {}'.format(label, description)) print() with FigureNum(8) as figure_number: description = 'Comparing Depth First Search, Breadth First Search, and Guided Search' label = caption(chapter, figure_number) from ch07.solver_bfs import BreadthFirstSearchSolver from ch07.solver_dfs import DepthFirstSearchSolver from ch07.solver_guided import GuidedSearchSolver random.seed(15) m = Maze(13, 13) if tkinter_error: print('unable to generate {}'.format(postscript_output)) else: root = tkinter.Tk() bfs = BreadthFirstSearchSolver(root, m, 15, refresh_rate=0, stop_end=True) tkinter_register_snapshot(root, bfs.canvas, '{}-BFS.ps'.format(label)) root.mainloop() root = tkinter.Tk() dfs = DepthFirstSearchSolver(root, m, 15, refresh_rate=0, stop_end=True) tkinter_register_snapshot(root, dfs.canvas, '{}-DFS.ps'.format(label)) root.mainloop() root = tkinter.Tk() sfs = GuidedSearchSolver(root, m, 15, refresh_rate=0, stop_end=True) tkinter_register_snapshot(root, sfs.canvas, '{}-Guided.ps'.format(label)) root.mainloop() print( 'Generated BFS, DFS and Guided Postscript files for {}'.format( label)) print('{}. {}'.format(label, description)) print() with FigureNum(9) as figure_number: description = 'Adjacency Matrix vs. Adjacency List representation' label = caption(chapter, figure_number) output_adjacency_matrix() output_adjacency_list() print('{}. {}'.format(label, description)) print() with FigureNum(10) as figure_number: description = 'Sample directed graph with 12 nodes and 14 edges.' label = caption(chapter, figure_number) make_sample_directed_graph() print('{}. {}'.format(label, description)) print() with FigureNum(11) as figure_number: description = 'Sample spreadsheet with underlying directed graph.' label = caption(chapter, figure_number) print('Screen shots from Excel, together with graph from Figure 7-9') print('{}. {}'.format(label, description)) print() with FigureNum(12) as figure_number: description = 'Visualizing execution of Depth First Search for Cycle Detection.' label = caption(chapter, figure_number) print('Done by hand.') print('{}. {}'.format(label, description)) print() # In-text linear ordering print_sample_linear_ordering() print('Linear ordering of spreadsheet cells after Figure 12.') print() with FigureNum(13) as figure_number: description = 'Visualizing execution of Depth First Search for Topological Sort.' label = caption(chapter, figure_number) print('Done by hand.') print('{}. {}'.format(label, description)) print() with FigureNum(14) as figure_number: description = 'Modeling highway infrastructure in Massachusetts.' label = caption(chapter, figure_number) (_, mapPositions, _) = tmg_load(highway_map()) (_, EAST, _, WEST) = bounding_ids(mapPositions) output_file = generate_bfs_and_dijkstra_figure(WEST, EAST) print('Generated {}'.format(output_file)) print('Augmented by hand in SVG') print('{}. {}'.format(label, description)) print() with FigureNum(15) as figure_number: description = 'Modeling highway infrastructure in Massachusetts.' label = caption(chapter, figure_number) (_, mapPositions, _) = tmg_load(highway_map()) (_, EAST, _, WEST) = bounding_ids(mapPositions) output_file = generate_dfs_figure(WEST, EAST) print('Generated {}'.format(output_file)) print('Augmented by hand in SVG') print('{}. {}'.format(label, description)) print() with FigureNum(16) as figure_number: description = 'The shortest path from a to c has accumulated total of 8' label = caption(chapter, figure_number) print('Done by hand.') print('{}. {}'.format(label, description)) print() with FigureNum(17) as figure_number: description = "Executing Dijkstra's algorithm on small graph" label = caption(chapter, figure_number) DG_GOOD = nx.DiGraph() DG_GOOD.add_edge('a', 'b', weight=3) DG_GOOD.add_edge('a', 'c', weight=9) DG_GOOD.add_edge('b', 'c', weight=4) DG_GOOD.add_edge('b', 'd', weight=2) DG_GOOD.add_edge('d', 'c', weight=1) visualize_dijkstra_small_graph(DG_GOOD) print('{}. {}'.format(label, description)) print() with FigureNum(18) as figure_number: description = "A negative edge weight in the wrong place breaks Dijkstra's algorithm" label = caption(chapter, figure_number) DG_GOOD = nx.DiGraph() DG_GOOD.add_edge('a', 'b', weight=3) DG_GOOD.add_edge('a', 'c', weight=1) DG_GOOD.add_edge('b', 'd', weight=-2) # THIS BREAKS IT DG_GOOD.add_edge('c', 'd', weight=1) try: visualize_dijkstra_small_graph(DG_GOOD) print('WARNING: ValueError should have occurred! WARNING WARNING!') except ValueError: print('Unable to relax from final "b" node') print('{}. {}'.format(label, description)) print() with FigureNum(19) as figure_number: description = 'Two graphs with negative edge weights, but only one has a negative cycle' label = caption(chapter, figure_number) DG_GOOD = nx.DiGraph() DG_GOOD.add_edge('a', 'b', weight=1) DG_GOOD.add_edge('b', 'd', weight=-3) DG_GOOD.add_edge('d', 'c', weight=5) DG_GOOD.add_edge('c', 'b', weight=-1) (dist_to, _) = bellman_ford(DG_GOOD, 'a') print('Good Graph: shortest distance from a to b is {}'.format( dist_to['b'])) DG_BAD = nx.DiGraph() DG_BAD.add_edge('a', 'b', weight=1) DG_BAD.add_edge('b', 'd', weight=-3) DG_BAD.add_edge('d', 'c', weight=5) DG_BAD.add_edge('c', 'b', weight=-4) try: (dist_to, _) = bellman_ford(DG_BAD, 'a') print( 'WARNING: RuntimeError should have occurred! WARNING WARNING!') except RuntimeError: print('Bad Graph: Negative cycle exists in the graph.') print('Done by hand.') print('{}. {}'.format(label, description)) print() with FigureNum(20) as figure_number: description = 'Example for all-pairs shortest path problem' label = caption(chapter, figure_number) DG_AP = nx.DiGraph() DG_AP.add_edge('a', 'b', weight=4) DG_AP.add_edge('b', 'a', weight=2) DG_AP.add_edge('a', 'c', weight=3) DG_AP.add_edge('b', 'd', weight=5) DG_AP.add_edge('c', 'b', weight=6) DG_AP.add_edge('d', 'b', weight=1) DG_AP.add_edge('d', 'c', weight=7) print(DG_AP.nodes()) print(DG_AP.edges(data=True)) print('Done by hand.') print('{}. {}'.format(label, description)) print() with FigureNum(21) as figure_number: description = 'Intuition behind the all-pairs shortest path problem' label = caption(chapter, figure_number) print('by hand') print('{}. {}'.format(label, description)) print() with FigureNum(22) as figure_number: description = 'dist_to, node_from, and actual shortest paths for graph in Figure 7-20' label = caption(chapter, figure_number) DG_TABLE = nx.DiGraph() DG_TABLE.add_edge('a', 'b', weight=4) DG_TABLE.add_edge('b', 'a', weight=2) DG_TABLE.add_edge('a', 'c', weight=3) DG_TABLE.add_edge('b', 'd', weight=5) DG_TABLE.add_edge('c', 'b', weight=6) DG_TABLE.add_edge('d', 'b', weight=1) DG_TABLE.add_edge('d', 'c', weight=7) visualize_results_floyd_warshall(DG_TABLE) print('{}. {}'.format(label, description)) print() with FigureNum(23) as figure_number: description = 'Initialize dist_to[][] and node_from[][] based on G' label = caption(chapter, figure_number) DG_TABLE = nx.DiGraph() DG_TABLE.add_edge('a', 'b', weight=4) DG_TABLE.add_edge('b', 'a', weight=2) DG_TABLE.add_edge('a', 'c', weight=3) DG_TABLE.add_edge('b', 'd', weight=5) DG_TABLE.add_edge('c', 'b', weight=6) DG_TABLE.add_edge('d', 'b', weight=1) DG_TABLE.add_edge('d', 'c', weight=7) visualize_results_floyd_warshall_just_initialize(DG_TABLE) print('{}. {}'.format(label, description)) print() with FigureNum(24) as figure_number: description = 'Changes to node_from[][] and dist_to[][] after k processes a and b' label = caption(chapter, figure_number) DG_TABLE = nx.DiGraph() DG_TABLE.add_edge('a', 'b', weight=4) DG_TABLE.add_edge('b', 'a', weight=2) DG_TABLE.add_edge('a', 'c', weight=3) DG_TABLE.add_edge('b', 'd', weight=5) DG_TABLE.add_edge('c', 'b', weight=6) DG_TABLE.add_edge('d', 'b', weight=1) DG_TABLE.add_edge('d', 'c', weight=7) visualize_results_floyd_warshall_two_steps(DG_TABLE) print('{}. {}'.format(label, description)) print() with FigureNum(25) as figure_number: description = 'Sample Maze to defeat Guided Search' label = caption(chapter, figure_number) print('Done by hand.') print('{}. {}'.format(label, description)) print() with FigureNum(26) as figure_number: description = 'Sample directed, acyclic graph for single-source, shortest path optimization' label = caption(chapter, figure_number) print('Done by hand.') print('{}. {}'.format(label, description)) print()