module ToySolver.SAT.PBO.UnsatBased
( solve
) where
import Control.Monad
import qualified Data.IntMap as IntMap
import qualified ToySolver.SAT as SAT
import qualified ToySolver.SAT.Types as SAT
import qualified ToySolver.SAT.PBO.Context as C
solve :: C.Context cxt => cxt -> SAT.Solver -> IO ()
solve cxt solver = solveWBO (C.normalize cxt) solver
solveWBO :: C.Context cxt => cxt -> SAT.Solver -> IO ()
solveWBO cxt solver = do
SAT.setEnableBackwardSubsumptionRemoval solver True
let sels0 = [(v, c) | (c,v) <- C.getObjectiveFunction cxt]
loop 0 (IntMap.fromList sels0)
where
loop :: Integer -> SAT.LitMap Integer -> IO ()
loop !lb sels = do
C.addLowerBound cxt lb
ret <- SAT.solveWith solver (IntMap.keys sels)
if ret then do
m <- SAT.model solver
C.addSolution cxt m
return ()
else do
core <- SAT.failedAssumptions solver
case core of
[] -> C.setFinished cxt
_ -> do
let !min_c = minimum [sels IntMap.! sel | sel <- core]
!lb' = lb + min_c
xs <- forM core $ \sel -> do
r <- SAT.newVar solver
return (sel, r)
SAT.addExactly solver (map snd xs) 1
SAT.addClause solver [l | l <- core]
ys <- liftM IntMap.unions $ forM xs $ \(sel, r) -> do
sel' <- SAT.newVar solver
SAT.addClause solver [sel', r, sel]
let c = sels IntMap.! sel
if c > min_c
then return $ IntMap.fromList [(sel', min_c), (sel, c min_c)]
else return $ IntMap.singleton sel' min_c
let sels' = IntMap.union ys (IntMap.difference sels (IntMap.fromList [(sel, ()) | sel <- core]))
loop lb' sels'