1 / 49

Case Study: Route Finding

Case Study: Route Finding. Lecture 6, Programmeringsteknik del A. The Problem. 211. Örebro. Stockholm. 285. 205. 335. 294. 71. 89. Göteborg. Borås. Jönköping. Which is the shortest route to Stockholm?. The Program. > route ”Göteborg” ”Stockholm” 71 Borås 160 Jönköping

chelsi
Download Presentation

Case Study: Route Finding

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Case Study: Route Finding Lecture 6, Programmeringsteknik del A.

  2. The Problem 211 Örebro Stockholm 285 205 335 294 71 89 Göteborg Borås Jönköping Which is the shortest route to Stockholm?

  3. The Program > route ”Göteborg” ”Stockholm” 71 Borås 160 Jönköping 324 Norrköping 495 Stockholm

  4. The Map Data Keep the map data in a file, so it is easy to modify. roads Göteborg Borås 71 Borås Jönköping 89 Jönköping Norrköping 164 Norrköping Örebro 105 Norrköping Uppsala 243 Norrköping Västerås 153 Norrköping Stockholm 171 ...

  5. Overall Plan • We begin with a top-down design: • Read the names of the starting point and end point. • Read the roads data. • Find the shortest route. • Display the result.

  6. Main Program main :: IO () main = do (from, to) <- readArguments roads <- readRoads putStr (formatRoute (route roads from to)) What are the types here? readArguments :: IO (Town, Town) readRoads :: IO [Road] route :: [Road] -> Town -> Town -> Route formatRoute :: Route -> String The ”main program” is always a command called main.

  7. Top-Down Design We have broken the problem down into parts, and written the top-level program. We go on to solve each part. When we put the solutions together, we obtain a complete program.

  8. Reading the Arguments Haskell programs communicate with UNIX using a standard library called System. In this library we find getArgs :: IO [String] To use it, we must add import System at the top of our program. A list of the arguments on the command line.

  9. readArguments Let us represent towns by strings: type Town = String readArguments :: IO (Town, Town) readArguments = do [from,to] <- getArgs return (from, to)

  10. The Road Data Göteborg Borås 71 Borås Jönköping 89 Jönköping Norrköping 164 Norrköping Örebro 105 ... The roads file contains: In our program, we represent this information in a form which is convenient to manipulate: [(”Göteborg”, ”Borås”, 71), (”Borås”, ”Jönköping”, 89), …]

  11. The Road Type We make an appropriate type definition: type Road = (Town, Town, Int) Now we must define readRoads :: IO [Road]

  12. Reading the Roads Data Break the problem into simpler stages: Göteborg Borås 71 Borås Jönköping 89 ... Break the input into a list of lines. [”Göteborg Borås 71”, ”Borås Jönköping 89”, …]

  13. Reading the Roads Data Ctd Break the problem into simpler stages: [”Göteborg Borås 71”, ”Borås Jönköping 89”, …] Break each line into a list of ”words”. [[”Göteborg”, ”Borås”, ”71”], [”Borås”, ”Jönköping ”, ”89”], …]

  14. Reading the Roads Data Ctd Break the problem into simpler stages: [[” Göteborg”, ”Borås”, ”71”], [”Borås”, ”Jönköping ”, ”89”], …] Turn each list of words into a road. [(” Göteborg”, ”Borås”, 71), (”Borås”, ”Jönköping ”, 89), …]

  15. Breaking a String into Lines ”a\nb\nc” [”a”, ”b”, ”c”] We must go through the list -- but a list comprehension won’t help. We could try recursion -- but it still isn’t easy. Can we solve a simpler problem?

  16. Taking One Line from a String ”a\nb\nc” ”a” ”” \n a b ... a b \n ... a b takeLine :: String -> String takeLine (’\n’:xs) = ”” takeLine (x : xs) = x : takeLine xs takeLine ”” = ””

  17. Dropping One Line from a String ”a\nb\nc” ”b\nc” \n a b ... a b ... a b \n ... ... dropLine :: String -> String dropLine (’\n’:xs) = xs dropLine (x : xs) = dropLine xs dropLine ”” = ””

  18. Splitting a String into Lines ”ab\ncd\nef” takeLine dropLine ”ab” ”cd\nef” lines [”cd”, ”ef”] : [”ab”, ”cd”, ”ef”]

  19. Defining lines lines :: String -> [String] lines [] = [] lines xs = takeLine xs : lines (dropLine xs) This is actually a standard function…!

  20. Defining readRoads Reminder: type Road = (Town, Town, Int) readRoads :: IO [Road] readRoads = do xs <- readFile ”roads” return [road (words line) | line <- lines xs] road :: [String] -> Road road [from, to, dist] = (from, to, read dist) For each line Convert to a road Split into words (very like lines) Convert a String to e.g. a number.

  21. Reminder: The Main Program main :: IO () main = do (from, to) <- readArguments roads <- readRoads putStr (formatRoute (route roads from to)) What remains to define? route :: [Road] -> Town -> Town -> Route formatRoute :: Route -> String

  22. Representing a Route • What do we need to know about a route? • Where it leads from. • Where it leads to. • How long it is (so we can choose the shorter of two alternatives). • Which towns it leads through (so we can print it out). 71 Borås 160 Jönköping 324 Norrköping 495 Stockholm

  23. Representing a Route: First Try 71 Borås 160 Jönköping 324 Norrköping 495 Stockholm type Route = (Town, Town, Int, [(Town, Int)]) example = (”Göteborg”, ”Stockholm”, 495, [(”Borås”, 71), (”Jönköping”, 160), (”Norrköping”, 324), (”Stockholm”, 495)])

  24. Formatting a Route Once again, solve the problem in stages. formatRoute :: Route -> String formatRoute (from, to, dist, stages) = unlines [formatStage s | s <- stages] Format one stage of the route. Join up the lines with line breaks.

  25. Formatting a Stage formatStage :: (String, Int) -> String First try: formatStage (t, d) = show d ++ ” ” ++ t Output: 71 Borås 160 Jönköping 324 Norrköping 495 Stockholm

  26. Padding with Spaces Second try: formatStage (t, d) = pad 5 (show d) ++ ” ” ++ t pad :: Int -> String -> String pad n s = [’ ’ | i<-[length s+1..n]] ++ s As many spaces as are needed to fill the gap between length s and n.

  27. Joining Up Lines ”ab” ”cd” ”ef” ”cd\nef\n” ”ab\ncd\nef\n” unlines :: [String] -> String unlines (x : xs) = x ++ ”\n” ++ unlines xs unlines [] = [] Another standard function.

  28. Remaining Problem All that remains to do is to define route :: [Road] -> Town -> Town -> Route This is the hard part!

  29. How Can We Get from Göteborg to Stockholm? 211 Örebro Stockholm 285 205 335 294 71 89 Göteborg Borås Jönköping Find the best routes from Örebro and Borås, add the distance from Göteborg, and choose the best.

  30. Choosing the Better of Two Routes • Which choice is better? • A shorter route is better than a longer one. • If two routes have the same length, then the one with more stages is better (because it gives a more detailed route description). • (”Goteborg”, ”Stockholm”, 496, • [(”Orebro”,285), (”Stockholm”,496)]) • is better than • (”Goteborg”, ”Stockholm”, 496, [(”Stockholm”, 496)])

  31. better better :: Route -> Route -> Route better (from,to,dist,stgs) (from',to',dist',stgs') | dist < dist' = (from,to,dist,stgs) | dist > dist' = (from',to',dist',stgs') | length stgs > length stgs' = (from,to,dist,stgs) | length stgs <= length stgs' = (from',to',dist',stgs') best :: [Route] -> Route best [r] = r best (r : rs) = better r (best rs) Choose the best of many routes.

  32. Joining Routes Together • We will need to combine a one-stage route (e.g. Goteborg to Boras) with the route onwards. • How can we join two routes? • The first route must end where the second begins. • We add the distances. • We must adjust the stages in the second route, by adding the length of the first route to their distances.

  33. Example of Joining Routes Joining (”Goteborg”, ”Boras”, 71, [(”Boras”, 71)]) with (”Boras”, ”Jonkoping”, 89, [(”Jonkoping”, 89)]) should give (”Goteborg”, ”Jonkoping”, 160, [(”Boras”, 71), (”Jonkoping”, 160)]) First stage unchanged. Second stage with adjusted distance.

  34. joinRoutes joinRoutes :: Route -> Route -> Route joinRoutes (from,to,dist,stgs) (from',to',dist',stgs') | to==from' = (from,to',dist+dist', stgs++[(c,d+dist) | (c,d)<-stgs']) For each stage in the second route... Adjust the distance.

  35. Making a One Stage Route We will need to convert a road into a one-stage route, so that we can use joinRoute on it. Recall type Road = (Town, Town, Int) roadRoute :: Road -> Route roadRoute (from,to,dist) = (from,to,dist,[(to,dist)]) Example: roadRoute (”Goteborg”, ”Boras”, 71) (”Goteborg”, ”Boras”, 71, [(”Boras”, 71)])

  36. Roads Go Both Ways To keep the route finder simple, for every road in the roads data, we add a road in the opposite direction. bothWays :: [Road] -> [Road] bothWays roads = roads ++ [(to,from,dist) | (from,to,dist) <- roads]

  37. Programming the Route Finder route :: [Road] -> City -> City -> Route route roads from to = best [joinRoutes (roadRoute road) (route roads (endPoint road) to) | road <- bothWays roads, startPoint road == from] startPoint, endPoint :: Road -> Town startPoint (from, to, dist) = from endPoint (from, to, dist) = to Useful auxiliary functions.

  38. The Base Case When we are already in Stockholm, the route there is trivial! Add before the recursive case: route roads from to | from == to = trivialRoute from We must be able to create a trivial route: trivialRoute :: Town -> Route trivialRoute t = (t, t, 0, [])

  39. Testing the Program > runhugs Route.hs Goteborg Stockholm ERROR: Control stack overflow. Every time hugs calls a function, it must record what it was doing beforehand, so as to be able to continue when the function call is complete. Imagine that hugs writes a little note. These notes are piled up on the `control stack’. Now the stack is overfull -- because we have a recursion without end.

  40. Understanding the Recursion 211 Örebro Stockholm 285 205 335 294 71 89 Göteborg Borås Jönköping What is getting smaller? Which are the best routes from Boras to Stockholm?

  41. Avoiding Circles 211 Örebro Stockholm 285 205 335 294 71 89 Göteborg Borås Jönköping Find the best route from Boras to Stockholm avoiding Goteborg. Find the best route from Jonkoping to Stockholm avoiding Goteborg and Boras.

  42. Finding Routes Avoiding Towns Define routeAvoiding :: [Town] -> [Road] -> Town -> Town -> Route Avoiding these towns. Then route roads from to = routeAvoiding [] roads from to

  43. routeAvoiding routeAvoiding avoid roads from to | from == to = trivialRoute from | otherwise = best [joinRoutes (roadRoute road) (routeAvoiding (from : avoid) roads (endPoint road) to) | road <- bothWays roads, startPoint road == from, not (endPoint road `elem` avoid)] Avoid returning to from. Add another condition: do not follow a road to a town to be avoided.

  44. A New Problem > runhugs Route.hs Goteborg Stockholm Program error: {best []} It is possible that every road from a town leads to a town we should avoid! Then no route can be found!

  45. One Solution: Changing the Route Representation We need to be able to represent an invalid route. Redefine type Route = (Bool, … as before …) invalidRoute :: Route invalidRoute = (False, ””, ””, 0, []) True if the route is valid.

  46. Adjust The Functions on Routes formatRoute (False, _, _, _, _) = ”No valid route” formatRoute (True, …) = …as before… better (True, …) (True, …) = …as before… better (False, _, _, _, _) r = r better r (False, _, _, _, _) = r best [] = invalidRoute and so on... Always prefer a valid route.

  47. At Last, It Works! > runhugs Route.hs Goteborg Stockholm 71 Borås 160 Jönköping 324 Norrköping 495 Stockholm

  48. Refinements The program works, but it is slow. As we add more roads, it becomes much much slower. Orebro Stockholm Goteborg Jonkoping It is much better to work out all the shortest routes, between every pair of towns, at the same time!

  49. Lessons • Top-down design enables us to solve difficult problems in many stages. • Lists are a natural way to represent much real world data. • Recursion is a powerful tool for solving difficult problems. • ’Obvious’ solutions can have subtle errors. • Algorithm design is a subtle art: there is a lot to learn!

More Related