toysolver-0.5.0: samples/programs/shortest-path/shortest-path.hs
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Main where
import Control.Exception
import Control.Monad
import qualified Data.ByteString.Lazy.Char8 as BL
import Data.Char
import Data.Foldable (toList)
import qualified Data.HashMap.Strict as HashMap
import Data.Int
import Data.List
import Data.Maybe
import Data.Monoid
import Data.Ord
import qualified Data.Sequence as Seq
import System.Console.GetOpt
import System.Environment
import System.Exit
import System.IO
import qualified ToySolver.Graph.ShortestPath as ShortestPath
import ToySolver.Internal.Util (setEncodingChar8)
data Flag
= Help
| PrintResult
| Method String
deriving Eq
options :: [OptDescr Flag]
options =
[ Option ['h'] ["help"] (NoArg Help) "show help"
, Option [] ["print"] (NoArg PrintResult) "print result"
, Option [] ["method"] (ReqArg Method "STRING") "method: dijkstra, bellman-ford, floyd-warshall"
]
header :: String
header = unlines
[ "Usage:"
, " shortest-path [OPTIONS] INPUTFILE VERTEX.."
, ""
, "Options:"
]
main :: IO ()
main = do
#ifdef FORCE_CHAR8
setEncodingChar8
#endif
args <- getArgs
case getOpt Permute options args of
(o,_,[])
| Help `elem` o -> putStrLn (usageInfo header options)
(o,fname:vs',[]) -> do
let method = last ("dijkstra" : [m | Method m <- o])
vs0 = map read vs'
vs = if null vs0 then [1] else vs0
es <- load fname
let g :: ShortestPath.Graph Int Int64 Int
g = fmap toList $ HashMap.fromListWith (<>) [(s, Seq.singleton (t,fromIntegral w,i)) | (i,(s,t,w)) <- zip [(1::Int)..] es]
case filter (\c -> c /= '-' && c /= '_') (map toLower method) of
"dijkstra" -> do
let ret = ShortestPath.dijkstra ShortestPath.unit g vs
_ <- evaluate ret
when (PrintResult `elem` o) $ do
forM_ (sortBy (comparing fst) (HashMap.toList ret)) $ \(v, (cost,_)) -> do
putStrLn $ show v ++ ": " ++ show cost
"bellmanford" -> do
let ret = ShortestPath.bellmanFord ShortestPath.unit g vs
_ <- evaluate ret
when (PrintResult `elem` o) $ do
forM_ (sortBy (comparing fst) (HashMap.toList ret)) $ \(v, (cost,_)) -> do
putStrLn $ show v ++ ": " ++ show cost
"floydwarshall" -> do
let ret = ShortestPath.floydWarshall ShortestPath.unit g
_ <- evaluate ret
when (PrintResult `elem` o) $ do
forM_ (sortBy (comparing fst) (HashMap.toList ret)) $ \(v, m) -> do
forM_ (sortBy (comparing fst) (HashMap.toList m)) $ \(u, (cost,_)) -> do
putStrLn $ show v ++ "-" ++ show u ++ ": " ++ show cost
_ -> error ("unknown method: " ++ method)
(_,_,errs) -> do
hPutStrLn stderr $ concat errs ++ usageInfo header options
exitFailure
load :: FilePath -> IO [(Int,Int,Int)]
load fname = do
s <- BL.readFile fname
let f l = do
-- 'BL.stripPrefix' is available only on bytestring >=0.10.8.0,
-- But we still want to support bytestring-0.10.4.0 (lts-2.22) and bytestring-0.10.6.0 (lts-3.22).
(c,l2) <- BL.uncons l
guard $ c == 'a'
(v,l3) <- BL.readInt $ BL.dropWhile isSpace l2
(u,l4) <- BL.readInt $ BL.dropWhile isSpace l3
(w,_) <- BL.readInt $ BL.dropWhile isSpace l4
return (v,u,w)
return $ catMaybes [f l | l <- BL.lines s]