module ToySolver.HittingSet.SHD
( Options (..)
, Failure (..)
, defaultOptions
, minimalHittingSets
) where
import Control.Exception (Exception, throwIO)
import Control.Monad
import Data.Array.Unboxed
import Data.IntSet (IntSet)
import qualified Data.IntSet as IntSet
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import Data.List
import Data.Typeable
import System.Exit
import System.IO
import System.IO.Temp
import ToySolver.Internal.ProcessUtil (runProcessWithOutputCallback)
type Vertex = Int
type HyperEdge = [Vertex]
type HittingSet = [Vertex]
data Options
= Options
{ optSHDCommand :: FilePath
, optSHDArgs :: [String]
, optOnGetLine :: String -> IO ()
, optOnGetErrorLine :: String -> IO ()
}
defaultOptions :: Options
defaultOptions =
Options
{ optSHDCommand = "shd"
, optSHDArgs = ["0"]
, optOnGetLine = \_ -> return ()
, optOnGetErrorLine = \_ -> return ()
}
data Failure = Failure !Int
deriving (Show, Typeable)
instance Exception Failure
minimalHittingSets :: Options -> [HyperEdge] -> IO [HittingSet]
minimalHittingSets opt es = do
withSystemTempFile "shd-input.dat" $ \fname1 h1 -> do
forM_ es' $ \e -> do
hPutStrLn h1 $ intercalate " " [show (encTable IntMap.! v) | v <- IntSet.toList e]
hClose h1
withSystemTempFile "shd-out.dat" $ \fname2 h2 -> do
hClose h2
execSHD opt fname1 fname2
s <- readFile fname2
return $ map (map ((decTable !) . read) . words) $ lines s
where
es' :: [IntSet]
es' = map IntSet.fromList es
vs :: IntSet
vs = IntSet.unions es'
nv :: Int
nv = IntSet.size vs
encTable :: IntMap Int
encTable = IntMap.fromList (zip (IntSet.toList vs) [0..nv1])
decTable :: UArray Int Int
decTable = array (0,nv1) (zip [0..nv1] (IntSet.toList vs))
execSHD :: Options -> FilePath -> FilePath -> IO ()
execSHD opt inputFile outputFile = do
let args = optSHDArgs opt ++ [inputFile, outputFile]
exitcode <- runProcessWithOutputCallback (optSHDCommand opt) args "" (optOnGetLine opt) (optOnGetErrorLine opt)
case exitcode of
ExitFailure n -> throwIO $ Failure n
ExitSuccess -> return ()