Last active
May 18, 2020 02:00
-
-
Save harfangk/ef87e47c82630b3e597f4a68afa9d538 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import qualified Data.List as List | |
import qualified Data.Map as Map | |
import qualified Data.IntMap.Strict as IntMap | |
import qualified Data.Sequence as Seq | |
import qualified Data.Array as Array | |
import qualified Data.Maybe as Maybe | |
import qualified Control.Monad.ST as ST | |
import qualified Control.Monad as CM | |
import qualified Data.PQueue.Prio.Min as MinHeap | |
main :: IO () | |
main = do | |
g1File <- readFile "./src/Course4/g3.txt" | |
let g1Data@(g1Vc, _, _) = parseData g1File | |
g1Result = bellmanFord (buildAdjacencyListByHead g1Data) g1Vc 1 | |
print g1Result | |
parseData :: String -> (Int, Int, [(Int, Int, Double)]) | |
parseData s = | |
(vertexCount, edgeCount, edges) | |
where | |
fileLines = lines s | |
(vertexCount, edgeCount) = parseMetaData . head $ fileLines | |
edges = List.map parseEdge . tail $ fileLines | |
parseMetaData :: String -> (Int, Int) | |
parseMetaData line = | |
case List.map read . words $ line of | |
[x,y] -> (x, y) | |
_ -> error "Invalid data format" | |
parseEdge :: String -> (Int, Int, Double) | |
parseEdge line = | |
case words line of | |
(edgeTail:edgeHead:weight:_) -> (read edgeTail, read edgeHead, read weight) | |
_ -> error "Invalid data format" | |
buildAdjacencyListByHead :: (Fractional a, Ord a) => (Int, Int, [(Int, Int, a)]) -> IntMap.IntMap [(Int, a)] | |
buildAdjacencyListByHead (vertexCount, _, edges) = | |
List.foldl' (\acc (t, h, w) -> IntMap.update (\edges' -> Just ((t,w):edges')) h acc) initialMap $ edges | |
where | |
initialMap = IntMap.fromList (List.zip [1..vertexCount] (List.repeat [])) | |
bellmanFord :: IntMap.IntMap [(Int, Double)] -> Int -> Int -> Either String (Array.Array Int Double) | |
bellmanFord g vertexCount s = | |
if hasNegativeCycle then | |
Left "Bellman-Ford algorithm halted: negative cycle found" | |
else | |
Right resultArray | |
where | |
memo = Array.array ((0,1), (vertexCount - 1, vertexCount)) [generator (x,y) | x <- [0..(vertexCount - 1)], y <- [1..vertexCount]] | |
generator pair@(i,v) = | |
if i == 0 then | |
if v == s then | |
(pair, 0) | |
else | |
(pair, 1/0) | |
else | |
(pair, findMin pair) | |
findMin (i,v) = min ({-# SCC accessMemo #-} (Array.!) memo (i-1,v)) ({-# SCC foldl' #-} List.foldl' (\acc (t,w) -> {-# SCC foldStep #-} min acc ((Array.!) memo (i-1,t) + w)) (1/0) ({-# SCC accessGraph #-} (IntMap.!) g v)) | |
resultList = map (\((_,v), d) -> (v,d)) . filter (\((i,_), _) -> i == vertexCount - 1 ) . Array.assocs $ memo | |
resultArray = Array.array (1, vertexCount) resultList | |
hasNegativeCycle = any (\(v, d) -> any (\(t, w) -> d > resultArray Array.! t + w) (g IntMap.! v)) resultList |
Ailrun
commented
May 18, 2020
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment