1 module NaiveMinCostFlow (minCostFlow) where
4 import Data.Array.IArray
7 import Control.Monad.ST
8 import Data.Graph.Inductive.Graph
9 import Data.Graph.Inductive.Internal.RootPath
12 data MCFEdge i f c = MCFEdge {
18 data MCFState s gr a b i f c = MCFState {
19 mcfGraph :: gr a (MCFEdge i f c),
22 mcfFlow :: STArray s i f
25 edgeCapLeft :: (Graph gr, Ix i, Real f, Real c) => MCFState s gr a b i f c ->
26 MCFEdge i f c -> ST s f
27 edgeCapLeft state (MCFEdge i cap _ isRev) = do
28 fwdFlow <- readArray (mcfFlow state) i
29 return (if isRev then fwdFlow else cap - fwdFlow)
31 edgePush :: (Graph gr, Ix i, Real f, Real c) => MCFState s gr a b i f c ->
32 MCFEdge i f c -> f -> ST s ()
33 edgePush state (MCFEdge i _ _ isRev) nf = do
34 oldFwdFlow <- readArray (mcfFlow state) i
35 let newFwdFlow = if isRev then oldFwdFlow - nf else oldFwdFlow + nf
36 writeArray (mcfFlow state) i newFwdFlow
38 pathCapLeft :: (Graph gr, Ix i, Real f, Real c) => MCFState s gr a b i f c ->
39 (MCFEdge i f c, BFPath (MCFEdge i f c) c) -> ST s f
40 pathCapLeft state (lastEdge, BFPath _ _ mFrom) = do
41 lastCL <- edgeCapLeft state lastEdge
43 Nothing -> return lastCL
45 fromCL <- pathCapLeft state from
46 return (min lastCL fromCL)
48 augment :: (Graph gr, Ix i, Real f, Real c) => MCFState s gr a b i f c ->
49 f -> BFPath (MCFEdge i f c) c -> ST s ()
50 augment state augAmt (BFPath _ _ mFrom) = case mFrom of
52 Just (lastEdge, path1) -> do
53 edgePush state lastEdge augAmt
54 augment state augAmt path1
56 doFlow :: forall s gr a b i f c. (Graph gr, Ix i, Real f, Real c) => MCFState s gr a b i f c ->
59 filteredEdges <- filterM (\(_, _, l) -> do
60 ecl <- edgeCapLeft state l
62 ) (labEdges (mcfGraph state))
63 let filteredGraph = mkGraph (labNodes (mcfGraph state)) filteredEdges :: gr a (MCFEdge i f c)
64 -- Why won't we get a negative cycle? The original graph from the
65 -- proposal matcher is acyclic (so no negative cycle), and if we
66 -- created a negative cycle, that would contradict the fact that we
67 -- always augment along the lowest-cost path.
68 let mAugPath = bellmanFord edgeCost (mcfSource state) filteredGraph
71 Nothing -> nop -- Done.
72 -- source /= sink, so augPasth is not empty.
73 Just augPath@(BFPath _ _ (Just from)) -> do
74 augAmt <- pathCapLeft state from
75 augment state augAmt augPath
78 minCostFlow :: forall s gr a b i f c. (Graph gr, Ix i, Real f, Real c) =>
79 (i, i) -> -- Range of edge indices
80 (b -> i) -> -- Edge label -> unique edge index
81 (b -> f) -> -- Edge label -> flow capacity
82 (b -> c) -> -- Edge label -> cost per unit of flow
84 (Node, Node) -> -- (source, sink)
85 Array i f -- ! edge index -> flow value
86 minCostFlow idxBounds edgeIdx edgeCap edgeCost theGraph (source, sink) = runSTArray (do
87 let ourFlipF isRev l =
88 MCFEdge (edgeIdx l) (edgeCap l)
89 (if isRev then -(edgeCost l) else edgeCost l)
91 let graph2 = mkGraph (labNodes theGraph) (concatMap
92 (\(n1, n2, l) -> [ -- Capacity of reverse edge is never used.
93 (n1, n2, MCFEdge (edgeIdx l) (edgeCap l) ( edgeCost l ) False),
94 (n2, n1, MCFEdge (edgeIdx l) undefined (-(edgeCost l)) True )
95 ]) $ labEdges theGraph) :: gr a (MCFEdge i f c)
96 flow <- newArray idxBounds 0
97 let state = MCFState graph2 source sink flow
99 return (mcfFlow state)