module ToySolver.SAT.PBO.MSU4
( solve
) where
import Control.Concurrent.STM
import Control.Monad
import qualified Data.IntSet as IS
import qualified Data.IntMap as IM
import qualified ToySolver.SAT as SAT
import qualified ToySolver.SAT.Types as SAT
import qualified ToySolver.SAT.PBO.Context as C
import Text.Printf
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
loop (IM.keysSet weights, IS.empty) 0
where
obj :: SAT.PBLinSum
obj = C.getObjectiveFunction cxt
sels :: [(SAT.Lit, Integer)]
sels = [(lit, w) | (w,lit) <- obj]
weights :: SAT.LitMap Integer
weights = IM.fromList sels
loop :: (SAT.LitSet, SAT.LitSet) -> Integer -> IO ()
loop (unrelaxed, relaxed) lb = do
ret <- SAT.solveWith solver (IS.toList unrelaxed)
if ret then do
currModel <- SAT.getModel solver
C.addSolution cxt currModel
let violated = [weights IM.! l | l <- IS.toList relaxed, SAT.evalLit currModel l == False]
currVal = sum violated
SAT.addPBAtMost solver [(c,l) | (l,c) <- sels] (currVal 1)
cont (unrelaxed, relaxed) lb
else do
core <- SAT.getFailedAssumptions solver
let ls = IS.fromList core `IS.intersection` unrelaxed
if IS.null ls then do
C.setFinished cxt
else do
SAT.addClause solver [l | l <- core]
let min_weight = minimum [weights IM.! l | l <- IS.toList ls]
lb' = lb + min_weight
C.logMessage cxt $ printf "MSU4: found a core: size = %d, minimal weight = %d" (length core) min_weight
C.addLowerBound cxt lb'
cont (unrelaxed `IS.difference` ls, relaxed `IS.union` ls) lb'
cont :: (SAT.LitSet, SAT.LitSet) -> Integer -> IO ()
cont (unrelaxed, relaxed) lb = do
join $ atomically $ do
b <- C.isFinished cxt
return $ if b then return () else loop (unrelaxed, relaxed) lb