-- | Maximum Flow algorithm -- -- We are given a flow network @G=(V,E)@ with source @s@ and sink @t@ -- where each edge @(u,v)@ in @E@ has a nonnegative capacity -- @c(u,v)>=0@, and we wish to find a flow of maximum value from @s@ -- to @t@. -- -- A flow in @G=(V,E)@ is a real-valued function @f:VxV->R@ that -- satisfies: -- -- @ -- For all u,v in V, f(u,v)\<=c(u,v) -- For all u,v in V, f(u,v)=-f(v,u) -- For all u in V-{s,t}, Sum{f(u,v):v in V } = 0 -- @ -- -- The value of a flow f is defined as @|f|=Sum {f(s,v)|v in V}@, i.e., -- the total net flow out of the source. -- -- In this module we implement the Edmonds-Karp algorithm, which is -- the Ford-Fulkerson method but using the shortest path from @s@ to -- @t@ as the augmenting path along which the flow is incremented. module Data.Graph.Inductive.Query.MaxFlow( getRevEdges, augmentGraph, updAdjList, updateFlow, mfmg, mf, maxFlowgraph, maxFlow ) where import Data.List import Data.Graph.Inductive.Basic import Data.Graph.Inductive.Graph --import Data.Graph.Inductive.Tree import Data.Graph.Inductive.Query.BFS -- | -- @ -- i 0 -- For each edge a--->b this function returns edge b--->a . -- i -- Edges a\<--->b are ignored -- j -- @ getRevEdges :: (Num b) => [Edge] -> [LEdge b] getRevEdges [] = [] getRevEdges ((u,v):es) | (v,u) `notElem` es = (v,u,0):getRevEdges es | otherwise = getRevEdges (delete (v,u) es) -- | -- @ -- i 0 -- For each edge a--->b insert into graph the edge a\<---b . Then change the -- i (i,0,i) -- label of every edge from a---->b to a------->b -- @ -- -- where label (x,y,z)=(Max Capacity, Current flow, Residual capacity) augmentGraph :: (DynGraph gr, Num b) => gr a b -> gr a (b,b,b) augmentGraph g = emap (\i->(i,0,i)) (insEdges (getRevEdges (edges g)) g) -- | Given a successor or predecessor list for node @u@ and given node @v@, find -- the label corresponding to edge @(u,v)@ and update the flow and -- residual capacity of that edge's label. Then return the updated -- list. updAdjList::(Num b) => Adj (b,b,b) -> Node -> b -> Bool -> Adj (b,b,b) updAdjList s v cf fwd = rs ++ ((x,y+cf',z-cf'),w) : rs' where (rs, ((x,y,z),w):rs') = break ((v==) . snd) s cf' = if fwd then cf else negate cf -- | Update flow and residual capacity along augmenting path from @s@ to @t@ in -- graph @@G. For a path @[u,v,w,...]@ find the node @u@ in @G@ and -- its successor and predecessor list, then update the corresponding -- edges @(u,v)@ and @(v,u)@ on those lists by using the minimum -- residual capacity of the path. updateFlow :: (DynGraph gr, Num b) => Path -> b -> gr a (b,b,b) -> gr a (b,b,b) updateFlow [] _ g = g updateFlow [_] _ g = g updateFlow (u:v:vs) cf g = case match u g of (Nothing,g') -> g' (Just (p,u',l,s),g') -> (p',u',l,s') & g2 where g2 = updateFlow (v:vs) cf g' s' = updAdjList s v cf True p' = updAdjList p v cf False -- | Compute the flow from @s@ to @t@ on a graph whose edges are labeled with -- @(x,y,z)=(max capacity,current flow,residual capacity)@ and all -- edges are of the form @a\<---->b@. First compute the residual -- graph, that is, delete those edges whose residual capacity is -- zero. Then compute the shortest augmenting path from @s@ to @t@, -- and finally update the flow and residual capacity along that path -- by using the minimum capacity of that path. Repeat this process -- until no shortest path from @s@ to @t@ exist. mfmg :: (DynGraph gr, Num b, Ord b) => gr a (b,b,b) -> Node -> Node -> gr a (b,b,b) mfmg g s t | null augPath = g | otherwise = mfmg (updateFlow augPath minC g) s t where minC = minimum (map ((\(_,_,z)->z).snd)(tail augLPath)) augPath = map fst augLPath LP augLPath = lesp s t gf gf = elfilter (\(_,_,z)->z/=0) g -- | Compute the flow from s to t on a graph whose edges are labeled with -- @x@, which is the max capacity and where not all edges need to be -- of the form a\<---->b. Return the flow as a grap whose edges are -- labeled with (x,y,z)=(max capacity,current flow,residual -- capacity) and all edges are of the form a\<---->b mf :: (DynGraph gr, Num b, Ord b) => gr a b -> Node -> Node -> gr a (b,b,b) mf g = mfmg (augmentGraph g) -- | Compute the maximum flow from s to t on a graph whose edges are labeled -- with x, which is the max capacity and where not all edges need to -- be of the form a\<---->b. Return the flow as a graph whose edges -- are labeled with (y,x) = (current flow, max capacity). maxFlowgraph :: (DynGraph gr, Num b, Ord b) => gr a b -> Node -> Node -> gr a (b,b) maxFlowgraph g s t = emap (\(u,v,_)->(v,u)) . elfilter (\(x,_,_) -> x/=0 ) $ mf g s t -- | Compute the value of a maximumflow maxFlow :: (DynGraph gr, Num b, Ord b) => gr a b -> Node -> Node -> b maxFlow g s t = sum (map (fst . edgeLabel) (out (maxFlowgraph g s t) s)) ------------------------------------------------------------------------------ -- Some test cases: clr595 is from the CLR textbook, page 595. The value of -- the maximum flow for s=1 and t=6 (23) coincides with the example but the -- flow itself is slightly different since the textbook does not compute the -- shortest augmenting path from s to t, but just any path. However remember -- that for a given flow graph the maximum flow is not unique. -- (gr595 is defined in GraphData.hs) ------------------------------------------------------------------------------