{-# OPTIONS_GHC -Wall #-} {-# OPTIONS_HADDOCK show-extensions #-} {-# LANGUAGE TypeFamilies #-} ----------------------------------------------------------------------------- -- | -- Module : ToySolver.Converter.PB2IP -- Copyright : (c) Masahiro Sakai 2011-2015 -- License : BSD-style -- -- Maintainer : masahiro.sakai@gmail.com -- Stability : experimental -- Portability : non-portable -- ----------------------------------------------------------------------------- module ToySolver.Converter.PB2IP ( pb2ip , PB2IPInfo , wbo2ip , WBO2IPInfo , sat2ip , SAT2IPInfo , maxsat2ip , MaxSAT2IPInfo ) where import Data.Array.IArray import Data.Default.Class import Data.Maybe import Data.Map (Map) import qualified Data.Map as Map import qualified Data.PseudoBoolean as PBFile import qualified Numeric.Optimization.MIP as MIP import Numeric.Optimization.MIP ((.==.), (.<=.), (.>=.)) import ToySolver.Converter.Base import ToySolver.Converter.PB import qualified ToySolver.FileFormat.CNF as CNF import qualified ToySolver.SAT.Types as SAT -- ----------------------------------------------------------------------------- newtype PB2IPInfo = PB2IPInfo Int deriving (Eq, Show, Read) instance Transformer PB2IPInfo where type Source PB2IPInfo = SAT.Model type Target PB2IPInfo = Map MIP.Var Rational instance ForwardTransformer PB2IPInfo where transformForward _ m = Map.fromList [(convVar v, if val then 1 else 0) | (v,val) <- assocs m] instance BackwardTransformer PB2IPInfo where transformBackward (PB2IPInfo nv) = mtrans nv pb2ip :: PBFile.Formula -> (MIP.Problem Integer, PB2IPInfo) pb2ip formula = (mip, PB2IPInfo (PBFile.pbNumVars formula)) where mip = def { MIP.objectiveFunction = obj2 , MIP.constraints = cs2 , MIP.varType = Map.fromList [(v, MIP.IntegerVariable) | v <- vs] , MIP.varBounds = Map.fromList [(v, (0,1)) | v <- vs] } vs = [convVar v | v <- [1..PBFile.pbNumVars formula]] obj2 = case PBFile.pbObjectiveFunction formula of Just obj' -> def{ MIP.objDir = MIP.OptMin, MIP.objExpr = convExpr obj' } Nothing -> def{ MIP.objDir = MIP.OptMin, MIP.objExpr = 0 } cs2 = do (lhs,op,rhs) <- PBFile.pbConstraints formula let (lhs2,c) = splitConst $ convExpr lhs rhs2 = rhs - c return $ case op of PBFile.Ge -> def{ MIP.constrExpr = lhs2, MIP.constrLB = MIP.Finite rhs2 } PBFile.Eq -> def{ MIP.constrExpr = lhs2, MIP.constrLB = MIP.Finite rhs2, MIP.constrUB = MIP.Finite rhs2 } convExpr :: PBFile.Sum -> MIP.Expr Integer convExpr s = sum [product (fromIntegral w : map f tm) | (w,tm) <- s] where f :: PBFile.Lit -> MIP.Expr Integer f x | x > 0 = MIP.varExpr (convVar x) | otherwise = 1 - MIP.varExpr (convVar (abs x)) convVar :: PBFile.Var -> MIP.Var convVar x = MIP.toVar ("x" ++ show x) -- ----------------------------------------------------------------------------- data WBO2IPInfo = WBO2IPInfo !Int [(MIP.Var, PBFile.SoftConstraint)] deriving (Eq, Show) instance Transformer WBO2IPInfo where type Source WBO2IPInfo = SAT.Model type Target WBO2IPInfo = Map MIP.Var Rational instance ForwardTransformer WBO2IPInfo where transformForward (WBO2IPInfo _nv relaxVariables) m = Map.union m1 m2 where m1 = Map.fromList $ [(convVar v, if val then 1 else 0) | (v,val) <- assocs m] m2 = Map.fromList $ [(v, if SAT.evalPBConstraint m c then 0 else 1) | (v, (Just _, c)) <- relaxVariables] instance BackwardTransformer WBO2IPInfo where transformBackward (WBO2IPInfo nv _relaxVariables) = mtrans nv wbo2ip :: Bool -> PBFile.SoftFormula -> (MIP.Problem Integer, WBO2IPInfo) wbo2ip useIndicator formula = (mip, WBO2IPInfo (PBFile.wboNumVars formula) relaxVariables) where mip = def { MIP.objectiveFunction = obj2 , MIP.constraints = topConstr ++ map snd cs2 , MIP.varType = Map.fromList [(v, MIP.IntegerVariable) | v <- vs] , MIP.varBounds = Map.fromList [(v, (0,1)) | v <- vs] } vs = [convVar v | v <- [1..PBFile.wboNumVars formula]] ++ [v | (ts, _) <- cs2, (_, v) <- ts] obj2 = def { MIP.objDir = MIP.OptMin , MIP.objExpr = MIP.Expr [MIP.Term w [v] | (ts, _) <- cs2, (w, v) <- ts] } topConstr :: [MIP.Constraint Integer] topConstr = case PBFile.wboTopCost formula of Nothing -> [] Just t -> [ def{ MIP.constrExpr = MIP.objExpr obj2, MIP.constrUB = MIP.Finite (fromInteger t - 1) } ] relaxVariables :: [(MIP.Var, PBFile.SoftConstraint)] relaxVariables = [(MIP.toVar ("r" ++ show n), c) | (n, c) <- zip [(0::Int)..] (PBFile.wboConstraints formula)] cs2 :: [([(Integer, MIP.Var)], MIP.Constraint Integer)] cs2 = do (v, (w, (lhs,op,rhs))) <- relaxVariables let (lhs2,c) = splitConst $ convExpr lhs rhs2 = rhs - c (ts,ind) = case w of Nothing -> ([], Nothing) Just w2 -> ([(w2,v)], Just (v,0)) if isNothing w || useIndicator then do let c = case op of PBFile.Ge -> (lhs2 .>=. MIP.constExpr rhs2) { MIP.constrIndicator = ind } PBFile.Eq -> (lhs2 .==. MIP.constExpr rhs2) { MIP.constrIndicator = ind } return (ts, c) else do let (lhsGE,rhsGE) = relaxGE v (lhs2,rhs2) c1 = lhsGE .>=. MIP.constExpr rhsGE case op of PBFile.Ge -> do return (ts, c1) PBFile.Eq -> do let (lhsLE,rhsLE) = relaxLE v (lhs2,rhs2) c2 = lhsLE .<=. MIP.constExpr rhsLE [ (ts, c1), ([], c2) ] splitConst :: MIP.Expr Integer -> (MIP.Expr Integer, Integer) splitConst e = (e2, c) where e2 = MIP.Expr [t | t@(MIP.Term _ (_:_)) <- MIP.terms e] c = sum [c | MIP.Term c [] <- MIP.terms e] relaxGE :: MIP.Var -> (MIP.Expr Integer, Integer) -> (MIP.Expr Integer, Integer) relaxGE v (lhs, rhs) = (MIP.constExpr (rhs - lhs_lb) * MIP.varExpr v + lhs, rhs) where lhs_lb = sum [min c 0 | MIP.Term c _ <- MIP.terms lhs] relaxLE :: MIP.Var -> (MIP.Expr Integer, Integer) -> (MIP.Expr Integer, Integer) relaxLE v (lhs, rhs) = (MIP.constExpr (rhs - lhs_ub) * MIP.varExpr v + lhs, rhs) where lhs_ub = sum [max c 0 | MIP.Term c _ <- MIP.terms lhs] mtrans :: Int -> Map MIP.Var Rational -> SAT.Model mtrans nvar m = array (1, nvar) [ (i, val) | i <- [1 .. nvar] , let val = case Map.findWithDefault 0 (convVar i) m of 0 -> False 1 -> True v0 -> error (show v0 ++ " is neither 0 nor 1") ] -- ----------------------------------------------------------------------------- type SAT2IPInfo = ComposedTransformer SAT2PBInfo PB2IPInfo sat2ip :: CNF.CNF -> (MIP.Problem Integer, SAT2IPInfo) sat2ip cnf = (ip, ComposedTransformer info1 info2) where (pb,info1) = sat2pb cnf (ip,info2) = pb2ip pb type MaxSAT2IPInfo = ComposedTransformer MaxSAT2WBOInfo WBO2IPInfo maxsat2ip :: Bool -> CNF.WCNF -> (MIP.Problem Integer, MaxSAT2IPInfo) maxsat2ip useIndicator wcnf = (ip, ComposedTransformer info1 info2) where (wbo, info1) = maxsat2wbo wcnf (ip, info2) = wbo2ip useIndicator wbo -- -----------------------------------------------------------------------------