module ToySolver.SAT.PBO.BC
( solve
) where
import Control.Concurrent.STM
import qualified Data.IntSet as IntSet
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
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
ub <- atomically $ C.getSearchUpperBound cxt
loop (IntSet.fromList [lit | (lit,_) <- sels], IntSet.empty) (0, ub)
where
obj :: SAT.PBLinSum
obj = C.getObjectiveFunction cxt
sels :: [(SAT.Lit, Integer)]
sels = [(lit, w) | (w,lit) <- obj]
weights :: SAT.LitMap Integer
weights = IntMap.fromList sels
loop :: (SAT.LitSet, SAT.LitSet) -> (Integer, Integer) -> IO ()
loop (unrelaxed, relaxed) (lb, ub)
| lb > ub = C.setFinished cxt
| otherwise = do
let mid = (lb + ub) `div` 2
C.logMessage cxt $ printf "BC: %d <= obj <= %d; guessing obj <= %d" lb ub mid
sel <- SAT.newVar solver
SAT.addPBAtMostSoft solver sel [(weights IntMap.! lit, lit) | lit <- IntSet.toList relaxed] mid
ret <- SAT.solveWith solver (sel : IntSet.toList unrelaxed)
if ret then do
m <- SAT.getModel solver
let val = SAT.evalPBLinSum m obj
let ub' = val 1
C.logMessage cxt $ printf "BC: updating upper bound: %d -> %d" ub ub'
C.addSolution cxt m
SAT.addClause solver [sel]
SAT.addPBAtMost solver obj ub'
loop (unrelaxed, relaxed) (lb, ub')
else do
core <- SAT.getFailedAssumptions solver
SAT.addClause solver [sel]
let core2 = IntSet.fromList core `IntSet.intersection` unrelaxed
if IntSet.null core2 then do
C.logMessage cxt $ printf "BC: updating lower bound: %d -> %d" lb (mid+1)
C.addLowerBound cxt (mid+1)
loop (unrelaxed, relaxed) (mid+1, ub)
else do
let unrelaxed' = unrelaxed `IntSet.difference` core2
relaxed' = relaxed `IntSet.union` core2
C.logMessage cxt $ printf "BC: #unrelaxed=%d, #relaxed=%d" (IntSet.size unrelaxed') (IntSet.size relaxed')
loop (unrelaxed', relaxed') (lb, ub)