The adjacency list graph
The following indicates the simple structure used for our graphs. The following shows a graph with nodes 0,1,2,3,4,5,6 and directed edges: with weight 1, with weight 2, etc.
Visualizing graphs: showGraph
We can visualize our graphs using the networkx module. We need to load a few modules and convert our adjacency list graph to a networkx graph. This is done below in the following code which may be ignored. Things are set up to indicate the DFS ('blue'), the BFS solution ('red'), and the UCS solution ('green') some basic attempt has been made to indicte when the path overlay each other.
Display initial toy graph
Basic Depth First Search and Breath First Search
Here these are implemented using a basic stack (DFS) and queue (BFS). Often the goal is simply to answer "Is there a path between the start node and the goal node?", but sometimes we also wish to get hold of an actual path, for this a back pointer structure is introduced. When we expand the fringe at the current node we indicate for each new element of the fringe where it came from, a dictionary is used for this as well. A path can then be reconstructed backwards starting at the current element and working back to the start node which indicates the history of what nodes were expended to reach the current node. In this way a complete search tree can be reconstructed from the back pointer structure.
The following reconstructs the path from the back pointers.
Run BFS and DFS on toy graph
BFS gives a path of length 3 with cost 11. BFS always returns a minimal length path.
Random graphs
The following make is easy to try out our algorithms on random graphs. There is a probability chance that the i -> j in this graph, where . A weight function can be provided to put weights on edges.
Play around with different weight functions. If you do not assign a weght function, all weights default to 1 and you can verify that BFS and UCS return shortes lenth paths, since now shortest length and minimal cost are the same. Setting weighs to -1, i.e. weights = lambda i,j: -1
is interesting as UCS then wants to find a maximal "length" path. You can set digraph=True
or digraph=False
and see what the difference is.
BFS gives a path of length 2 with cost 14. BFS always returns a minimal length path.
Uniform Cost Search (UCS) and -Search
Here we must switch from regular queue and stack to the priority queue and introduce the cost function. Often the goal is simply to get the least cost of a path, but sometimes we wish to have the path itself so we keep track of back pointers as in the BFS/DFS so we can reconstuct the path. UCS is gauranteed to produce a path of minimal cost.
search is much like UCS, the only difference is that an additional heuristic is used to modify the priority function, so that the cost function and the priority function are no longer the same. For example, in the "project" graphs below, an additional might be used as the priority where is the Manhatten distance from the node to the goal. This can prevent some unecessary exploration in irrelevant directions. We won't implement search here.
BFS gives a path of length 3 with cost 11. BFS always returns a minimal length path.
UCS gives a path of length 5 with cost 8. UCS alway returns a minimal cost path.
BFS gives a path of length 2 with cost 18. BFS always returns a minimal length path.
UCS gives a path of length 5 with cost 14. UCS alway returns a minimal cost path.
Grid Graphs
Here we generate the sort of graphs used in the class project.
Generate an instance
Generate a 10x10 instance of our problem using values between 1 and 15. I have opted to omit any 'inf' nodes in the generation and decided to add them in as a smiley face. You could make a bigger case, say 100 x 100 and design the masking array so you get a "weighted" maze.
Function to show project matrix: showProjectMatrix
Let's look at one representation of our problem.
Function to convert instance into graph: wtsToGraph
There are many ways to convert the matrix above into a graph with one node for each finite element. The nodes could for example be points on a map labeled with elevation, the edges could be labeled with the absolute value of the difference of the two elevations. (For simplicity, keep all edge weights non-negative.) A minimal cost path would correspond to a walk from one location (start) to the another (goal) that has the minimal total change in elevation, that is, minimizes the "up's and down's". This is what we shall use.
Convert the instance into a graph
BFS gives a path of length 18 with cost 57.0. BFS always returns a minimal length path.
UCS gives a path of length 20 with cost 51.0. UCS alway returns a minimal cost path.
Generate your DQ 2 graph
Design your own mask array. We'll use some topo data of Mt Ord in AZ for this.
Now display your array and graph.