packages feed

hgraph-1.2.0.1: src/HGraph/Directed/Connectivity/Flow.hs

module HGraph.Directed.Connectivity.Flow
       ( maxFlow
       , maxDisjointPaths
       , minCut
       , minCutI
       )
where

import Data.List
import HGraph.Directed
import qualified Data.Map as M
import qualified Data.Set as S
import Control.Monad

maxFlow :: (Ord a, Adjacency t, DirectedGraph t) => t a -> a -> a -> M.Map (a, a) Bool
maxFlow d s t = maxFlow' $ foldr (\a -> M.insert a False) M.empty (arcs d)
  where
    maxFlow' flow 
      | null p = flow
      | otherwise = maxFlow' flow'
      where
        p = shortestPathResidual d s t flow
        flow' = foldr (M.adjust not) flow $ zip p (tail p)

shortestPathResidual d s t flow = path (S.singleton s) M.empty
  where
    path active preds
      | t `M.member` preds = reverse $ makePath preds t
      | S.null active = []
      | otherwise = path (S.fromList $ M.keys newPred) (preds `M.union` newPred)
        where
          newPred = M.fromList $ [ (u,v)
                             | v <- S.toList active
                             , u <- outneighbors d v
                             , (not $ flow M.! (v,u)) && (not $ u `M.member` preds)
                             ]
                             ++
                             [ (u,v)
                             | v <- S.toList active
                             , u <- inneighbors d v
                             , flow M.! (u, v) && (not $ u `M.member` preds)
                             ]
    makePath preds v
      | v == s = [v]
      | otherwise = v : makePath preds (preds M.! v)

maxDisjointPaths :: (Mutable t, DirectedGraph t, Adjacency t, Integral a) => t a -> a -> a -> [[a]]
maxDisjointPaths d s t = [s : makePath v | v <- outneighbors d s, (2*v + 1) `M.member` succs]
  where
    d'  = foldr addVertex (empty d) (concat [[2*v, 2*v+1] | v <- vertices d])
    d'' = foldr addArc d' ([(2*v, 2*v + 1) | v <- vertices d] ++ [(2*v+1, 2*u) | (v,u) <- arcs d])
    succs = M.fromList $ M.keys $ M.filter (id) $ maxFlow d'' (2*s+1) (2*t)
    makePath v
      | v == t = [t]
      | otherwise = v : makePath ((succs M.! (2*v + 1)) `div` 2)

minCut :: (Mutable t, DirectedGraph t, Adjacency t, Eq a) => t a -> a -> a -> [a]
minCut d s t = map (iToV M.!) $ minCutI di si ti
  where
    (di, itova) = linearizeVertices d
    iToV = M.fromList itova
    Just si = fmap fst $ find ((==s) . snd) itova
    Just ti = fmap fst $ find ((==t) . snd) itova

minCutI :: (Mutable t, DirectedGraph t, Adjacency t, Integral a) => t a -> a -> a -> [a]
minCutI d s t = [u `div` 2 | v <- S.toList $ reach, u <- outneighbors d'' v, not $ u `S.member` reach]
  where
    d'  = foldr addVertex (empty d) (concat [[2*v, 2*v+1] | v <- vertices d])
    d'' = foldr addArc d' ([(2*v, 2*v + 1) | v <- vertices d] ++ [(2*v+1, 2*u) | (v,u) <- arcs d])
    flow = M.filter (id) $ maxFlow d'' (2*s+1) (2*t)
    reach = bfs (S.singleton (2*s+1)) (S.singleton (2*s+1))
    bfs active reached
      | S.null active = reached
      | otherwise = bfs new (S.union reached new)
        where
          new = S.fromList $ [ u
                           | v <- S.toList active
                           , u <- outneighbors d'' v
                           , (not $ (v,u) `M.member` flow) && (not $ u `S.member` reached)
                           ]
                           ++
                           [ u
                           | v <- S.toList active
                           , u <- inneighbors d'' v
                           , (u,v) `M.member` flow && (not $ u `S.member` reached)
                           ]