packages feed

hgraph-1.10.0.0: src/HGraph/Directed/EditDistance/Acyclic/ArcDeletion/Internal.hs

module HGraph.Directed.EditDistance.Acyclic.ArcDeletion.Internal where

import Prelude hiding (minimum)

import HGraph.Directed
import HGraph.Directed.Connectivity.Basic
import HGraph.Directed.Connectivity.Flow

import Control.Monad
import Data.Maybe
import qualified Data.Set as S
import qualified Data.Map as M

import qualified Debug.Trace as D (trace)

minimum :: (DirectedGraph t, Adjacency t, Mutable t)
         => t a -> ([(a,a)], Int)
minimum d =
  let (di, iToL) = linearizeVertices d
      iToLM = M.fromList iToL
      (xs, k) = minimumI di
  in ( map (\(v,u) -> (iToLM M.! v, iToLM M.! u)) xs, k)

minimumI :: (DirectedGraph t, Adjacency t, Mutable t)
         => t Int -> ([(Int, Int)], Int)
minimumI d 
  | numArcs d == 0 = ([], 0)
  | otherwise = 
      let loops = [(v,v) | v <- vertices d, arcExists d (v,v)]
          d' = foldr removeArc d loops
      in foldr 
               (\c (x, l) -> 
                  let h = inducedSubgraph d' $ S.fromList c
                      (x', l') = fromJust $ guessArc h (numArcs h - 1) (foldr addVertex (empty d) (vertices d))
                  in (x ++ x', l + l')) (loops, length loops) $
               strongComponents d'

guessArc d kMax fixed  =
  case filter (\e -> not $ arcExists fixed e) $ arcs d of
    [] -> Just ([], 0)
    e@(v,u) : _ ->
      let fixed' = addArc e fixed
          forced = filter (\(x,y) -> reachable fixed' y x) $ arcs d
          dKeep = foldr removeArc d forced
          csKeep = strongComponents dKeep
          kForced = length forced
          dRemove = removeArc e d
          -- csRemove = strongComponents dRemove
      in
      if kMax <= 0 then
        Nothing
      else if kForced > kMax then
        separateVertices' d kMax fixed [] [e]
        -- minimumIComponents dRemove (kMax - 1) csRemove fixed
      else if reachable fixed u v then
        separateVertices' d kMax (addArc (u,v) fixed) [] [e]
      else
        case minimumIComponents dKeep (kMax - kForced) csKeep fixed' of
          Nothing -> separateVertices' d kMax fixed [] [e] -- minimumIComponents dRemove (kMax - 1) csRemove fixed
          keep@(Just (es, kKeep)) ->
            case separateVertices' d (min kMax (kKeep - 1)) fixed [] [e] of
              Nothing -> Just (forced ++ es, kKeep + kForced)
              solution -> solution

separateVertices d kMax fixed [] = 
  let cs = strongComponents d
  in minimumIComponents d kMax cs fixed
separateVertices d kMax fixed ((v,u) : forbidden)
  | arcExists fixed (v,u) = Nothing
  | otherwise = 
    let directArc = arcExists d (v,u)
        d' = if directArc then removeArc (v,u) d else d
        ps = maxArcDisjointPaths d' v u
        cutSize = length ps
        kMax' = if directArc then kMax - 1 else kMax
        addSolution (hs, k) =
          if directArc then
            ((v,u) : hs, k + 1)
          else
            (hs, k)
    in -- D.trace (show (take 10 forbidden, take 10 $ arcs fixed)) $ 
    if cutSize > kMax' then
      Nothing
    else
      case ps of
        [] -> separateVertices d' kMax' fixed forbidden
        ((_ : w : _) : _) ->
          let (w : _) = drop 1 $ head ps
          in
          fmap addSolution $
            if arcExists fixed (v,w) then
              separateVertices' d' kMax' fixed ((v,u) : forbidden) [(w,v), (w,u)]
            else if reachable fixed w v then
              separateVertices' d' kMax' fixed ((v, u) : forbidden) [(v, w)]
            else
              case separateVertices' d' kMax' (addArc (v,w) fixed) ((v,u) : forbidden) [(w,v), (w,u) ]  of
                Nothing -> separateVertices' d' kMax' fixed ((v, u) : forbidden) [(v, w)]
                solution@(Just (hs, k')) -> 
                  (separateVertices' d' (k' - 1) fixed ((v, u) : forbidden)) [(v, w)]
                  `mplus`
                  solution

separateVertices' d kMax fixed forbidden newForbidden = 
  let newRemoved = filter (arcExists d) newForbidden
      kNew = length newRemoved
      d' = foldr removeArc d newRemoved
      kMax' = kMax - kNew
  in 
  if kMax' < 0 then
    Nothing
  else
    fmap (\(hs, k) -> (newRemoved ++ hs, k + kNew)) $
      separateVertices d' kMax' fixed (newForbidden ++ forbidden)

--minimumI' d kMax fixed
--  | numArcs d <= 1 = Just ([], 0)
--  | kMax <= 0 = Nothing
--  | otherwise = 
--      let forced = filter (\(v,u) -> reachable fixed u v) $ arcs d
--          d' = foldr removeArc d forced
--          kForced = length forced
--          candidates = [ (e, d'', cs) | e <- arcs d'
--                       , let d'' = removeArc e d'
--                       , let cs = strongComponents d''
--                       , not $ arcExists fixed e
--                       -- , any (\c -> null $ drop 1 c) cs
--                       ]
--          bestChoice solution _ [] _ = solution
--          bestChoice solution kMax' ((e, d'', cs) : xs) fixed' = 
--            case minimumIComponents d''
--                                    (if isNothing solution then kMax' - 1 else kMax' - 2)
--                                    cs
--                                    fixed
--            of
--              Nothing -> bestChoice solution kMax' xs (addArc e fixed)
--              (Just (es, k)) -> bestChoice (Just (e : es, k + 1)) (k + 1) xs (addArc e fixed)
--      in 
--      if kForced > kMax then
--        Nothing
--      else
--        bestChoice Nothing (kMax - kForced) candidates fixed
        
minimumIComponents d kMax cs fixed
  | length (filter (\c -> not $ null $ drop 1 c) cs) > kMax = Nothing
  | otherwise = minComponents kMax cs
  where
    minComponents kMax' [] = Just ([], 0)
    minComponents kMax' (c':cs') = 
      let h = inducedSubgraph d $ S.fromList c'
      in case guessArc h kMax' fixed of
          Nothing -> Nothing
          Just (xs, k0) -> fmap (\(ys, k') -> (xs ++ ys, k0 + k')) $ minComponents (kMax' - k0) cs'