packages feed

hgraph-1.10.0.0: src/HGraph/Directed/Packing/Cycles/Internal.hs

module HGraph.Directed.Packing.Cycles.Internal where

import HGraph.Directed
import HGraph.Directed.Connectivity

import Prelude hiding (maximum)
import qualified Data.Map as M
import qualified Data.Set as S
import Data.Maybe

-- | A packing of pairwise arc-disjoint cycles of maximum size.
arcMaximumI d =
  let (ld, iToA) = lineDigraphI d
      iToA' = M.fromList iToA
      (packing', k) = maximumI ld
  in (map (map fst . map (iToA' M.!)) packing', k)

-- | Computes a packing of pairwise disjoint cycles of maximum size.
maximum :: (DirectedGraph t, Mutable t, Adjacency t) => t a -> ([[a]], Int)
maximum d = 
  let (di, iToL) = linearizeVertices d
      (cs, k) =  maximumI di
      labels = M.fromList iToL
  in (map (map (labels M.!)) cs, k)

-- | Computes a packing of pairwise disjoint cycles of maximum size.
-- Vertices of the input digraph must be labeled with integers from `0` to `n - 1`.
maximumI :: (DirectedGraph t, Mutable t, Adjacency t) => t Int -> ([[Int]], Int)
maximumI d
  | numVertices d == 0 = ([], 0)
  | otherwise = 
      let loops = [v | v <- vertices d, arcExists d (v,v)]
          d' = foldr removeVertex d loops
          components = strongComponents d'
      in foldr
           (\c (cs', k') ->
              let h = inducedSubgraph d $ S.fromList c
                  (cs1, k1) = fromJust $ maximumI' h 1
              in (cs1 ++ cs', k1 + k')
           )
           (map (:[]) loops, length loops)
           (filter (\c -> not $ null $ drop 1 c) components)

maximumI' d kMin 
  | numVertices d <= 1 && kMin <= 0 = Just ([], 0)
  | numVertices d < (2 * kMin) = Nothing
  | numArcs d == 0 = Nothing
  | otherwise = guessArc d kMin $ head (arcs d)

maximumIWeak d kMin = 
  let components = strongComponents d
      ds = map (\c -> inducedSubgraph d $ S.fromList c) $ filter (\c -> not $ null $ drop 1 c) components
      kMaxs = map (\h -> (numVertices h) `div` 2) ds
      kMax = sum kMaxs
      solution = fst $ foldr 
                 (\(h, kMaxH) (solution, kMaxRest) ->
                     case solution of
                       Nothing -> (Nothing, kMaxRest)
                       Just (cs', k') ->
                         case maximumI' h $ max 1 (kMin - kMaxRest - k' - kMaxH) of
                           Nothing -> (Nothing, kMaxRest)
                           Just (csH, kH) -> (Just (csH ++ cs', kH + k'), kMaxRest - kMaxH))
                 ( Just ([], 0)
                 , kMax)
                 (zip ds kMaxs)
  in case solution of
      Nothing -> Nothing
      sol@(Just ([], 0)) ->
        if kMin <= 0 then
          sol
        else
          Nothing
      sol@(Just (cs, k)) ->
        if k >= kMin then
          sol
        else
          Nothing

guessArc d kMin (v,u) = 
  let withArc = packArc d kMin [u,v] v (v,u)
      d' = removeArc (v,u) d
      withoutArc kMin' = maximumIWeak d' kMin'
  in case withArc of
      Nothing -> withoutArc kMin
      Just (cs, k) -> 
        case withoutArc (k + 1) of
          Nothing -> withArc
          Just (cs', k') -> if k' > k then Just (cs', k') else withArc

packArc :: (DirectedGraph t, Mutable t, Adjacency t) 
        => t Int -> Int -> [Int] -> Int -> (Int, Int) -> Maybe ([[Int]], Int)
packArc d kMin cv w (v,u)
  | u == w = 
    let h = foldr removeVertex d $ drop 1 cv
    in case maximumIWeak h (kMin - 1) of
          Nothing -> Nothing
          Just (cs, k) -> Just ((reverse $ drop 1 cv) : cs, k + 1)
  | otherwise = 
      let d1 = foldr removeArc d
                            [(v,x) | x <- outneighbors d v
                            , x /= u]
          d' = foldr removeArc 
                     d1
                     [(x,u) | x <- inneighbors d1 u
                     , x /= v]
          candidates = [ x | x <- 
                              if v == w then
                                outneighbors d' u
                              else
                                filter (/=v) $ outneighbors d' u
                       , reachable d' x w
                       ]
          bestChoice solution _ [] = solution
          bestChoice solution kMin' (x:xs) = 
            case packArc d' kMin' (x : cv) w (u,x) of
              Nothing -> bestChoice solution kMin' xs
              sol@(Just (cs, k')) -> bestChoice sol (k' + 1) xs
      in 
      if arcExists d (u, w) then
        bestChoice Nothing kMin [w]
      else
        bestChoice Nothing kMin candidates