Milestone 3: Finding Routes ECE 297
Milestone 3 Overview Find shortest travel time routes Between two intersections With right and left turn penalties 15% of final mark 8% algorithm (automarked) Find some path? Find shortest travel time path? Find it with low CPU time? 5% user interface (TA demo) 2% code style and project management Due Date: Tuesday, March 19 @ 7pm.
Milestone 3 UI User Interface: 5% Requirements Can click on two intersections find path Visualize path in UI Print or draw travel directions Have help button or command
Milestone 3 UI Usability matters Travel directions: Try it on a friend or family member! Can he/she enter intersections without lots of pain? Can he/she follow the travel directions and path display? Travel directions: Directions give info you need from start to finish? Take street segment #21 then street segment #10 … Unbelievably Bad! Take Yonge Street Then Yonge Street Then Bloor Street Still bad!
Milestone 3 UI (Cont’d)
Planning Most teams find milestone 3 hardest Make plan to divide work Start early! Make plan to divide work Too big for complete pair/triplet programming Separate pieces for parallel development? UI: input (text & mouse) UI: output (directions & drawing) Hard code path to test before algorithm working Algorithm Path search Can split code & test Or split some helper functions (needs close comm.)
Algorithmic Approaches
Directions: How?
Model as Graph Problem (Node) (Edge) Bathurst dest source Path: sequence of connected nodes from a source to a dest
Now sequence of nodes doesn’t uniquely describe path Model as Graph Problem Bathurst back lane Now sequence of nodes doesn’t uniquely describe path dest source Path: store as sequence of nodes?
Model as Graph Problem Better: sequence of connected edges & nodes Bathurst dest source Better: sequence of connected edges & nodes
Finding Routes Find path from source to dest Any path? Fewest nodes? Is there only one path? Any path? Fewest nodes? Fewest edges? Minimum travel time! Graph texts: minimum weight path or shortest path dest source
Minimum Travel Time Definition Distance / speed limit + turn_penalty per street change Blue path: 200 m / 40 kmh + 300 m / 50 kmh + 1 right turn 18 s + 21.6 s + 15 s = 54.6 s 300 m dest Red path: 100 m / 40 kmh + 200 m / 40 kmh + 200 m / 50 kmh + 1 left and 1 right turns 9 s + 18 s + 14.4 s + 25 + 15 s = 81.4 s 200 m source 100 m Which is better if right_turn_penalty = 15s and left_turn_penalty = 25s?
Minimum Travel Time Definition Left turns usually take longer than right turns. Street change with no turn? Assume right 15 s No penalty Yonge St. Bloor St. West Bloor St. East 15 s penalty Yonge St.
Other Shortest Path Applications Any Ideas?
Internet Routing Nodes: computers and switches Edges: cables source dest Nodes: computers and switches Edges: cables Find a path to connect computers Typical minimum weight path definition: Fewest routers Or least congested
Circuit Board Design Nodes: small square for metal Edges: squares we can connect Find paths to connect chip I/Os
Integrated Circuits Nodes: small grid squares for metal Edges: squares we can connect Find paths to connect gates Huge graph (tens of millions of nodes) need fast algorithms
Facebook Entire social network is stored as > billion-node graph Shortest path: how close to knowing someone? Algorithms built on shortest path: social marketing
Shortest Path Algorithm #1 Depth First Search Shortest Path Algorithm #1
Recursion? source dest int main () { Node *sourceNode = getNodebyID (sourceID); bool found = findPath (sourceNode, destID); . . . } bool findPath (Node* currNode, int destID) { ...
Recursion? bool findPath (Node* currNode, int destID) { if (currNode->id == destID) return (true); for each (outEdge of currNode) { Node *toNode = outEdge.toNode; bool found = findPath (toNode, destID); if (found) } return (false); 1 source dest 2 3 4 3
Recursion? Infinite Loop! bool findPath (Node* currNode, int destID) { if (currNode->id == destID) return (true); for each (outEdge of currNode) { Node *toNode = outEdge.toNode; bool found = findPath (toNode, destID); if (found) } return (false); Infinite Loop! source dest
How to Fix? bool findPath (Node* currNode, int destID) { if (currNode->id == destID) return (true); currNode->visited = true; for each (outEdge of currNode) { Node *toNode = outEdge.toNode; if (!toNode->visited) { bool found = findPath (toNode, destID); if (found) } return (false); toNode visited dest source
Output? Says whether or not a path was found But not what the path is! bool findPath (Node* currNode, int destID) { . . . return (true); } Says whether or not a path was found But not what the path is! Worst directions ever: yes, a path exists! How to fix? dest source
Depth First Seach: Output Fix bool findPath (Node* currNode, int destID, list<Edge> path) { if (currNode->id == destID) return true; currNode->visited = true; for each (outEdge of currNode) { Node *toNode = outEdge.toNode; if (!toNode->visited) { list<Edge> newPath = path; newPath.push_back (outEdge); bool found = findPath (toNode, destID, newPath); if (found) return (true); } return (false); Anything Missing? {a,b} {a,b,c} a b c d {} {a,b,c,d} {a} dest source
Easy Fix Part 2 dest source bool findPath (Node* currNode, int destID, list<Edge> path) { if (currNode->id == destID) print out or save the path, then return (true); currNode->visited = true; for each (outEdge of currNode) { Node *toNode = outEdge.toNode; if (!toNode->visited) { list<Edge> newPath = path; newPath.push_back (outEdge); bool found = findPath (toNode, destID, newPath); if (found) return (true); } return (false); dest source
Depth First Search (DFS) Developed depth first search in a graph Need a visited flag Unlike a tree (can go in circles otherwise) Graph is big (>100,000 nodes, N) Complexity of DFS?
Complexity Analysis bool findPath (Node* currNode, int destID, list<Edge> path) { if (currNode->id == destID) print out or save the path, then return (true); currNode->visited = true; for each (outEdge of currNode) { Node *toNode = outEdge.toNode; if (!toNode->visited) { list<Edge> newPath = path; newPath.push_back (outEdge); bool found = findPath (toNode, destID, newPath); if (found) return (true); } return (false); At most one findPath call per Node Executes once per outgoing edge Average: about 4
Complexity findPath executes at most O(N) times Constant, O(1), work in each call Except copying path path could have O(N) nodes Total worst-case complexity: O(N2) Average path shorter Average case somewhat better, but hard to analyze
Complexity Can we do better? Don’t pass entire path around One way: each Node stores the edge used to reach it e.g. node.reachingEdge Reconstruct path when you reach the dest By following the previous edges / “bread crumbs” Now work per findPath is O(1) Total complexity is O(N) Good for a graph algorithm!
DFS - Demo
Path Quality We’re finding a path, not the shortest path dest source We’re finding a path, not the shortest path Circuitous routes / directions! Low marks! How to fix?