feat(cdcl): add incremental sat solving under assumptions
This commit is contained in:
1 parent
40b43a927f
commit
8fea34a107
1 file changed
+144
@@ -0,0 +1,144 @@
|
|||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
module Sift.Cdcl.Incremental
|
||||||
|
( IncResult(..)
|
||||||
|
, solveAssuming
|
||||||
|
, solveManyAssuming
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Control.Monad (forM, forM_)
|
||||||
|
import Control.Monad.ST (ST, runST)
|
||||||
|
import Data.STRef
|
||||||
|
import Data.Array.ST
|
||||||
|
import Data.List (nub)
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
import Sift.Types (Var(..), Lit, CNF(..), Assignment, litToInt, litFromInt, varsOfClause, varId)
|
||||||
|
import Sift.Cdcl.State
|
||||||
|
import Sift.Cdcl.Search (propagate, analyze, analyzeFinal, pickBranchVar, maybeReduce, installLearnt, luby)
|
||||||
|
|
||||||
|
data IncResult
|
||||||
|
= IncSat Assignment
|
||||||
|
| IncUnsat [Lit]
|
||||||
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
data StepOutcome
|
||||||
|
= StepSat
|
||||||
|
| StepUnsat [Int]
|
||||||
|
| StepRestart
|
||||||
|
|
||||||
|
data AssumeStep
|
||||||
|
= AssumeConflict [Int]
|
||||||
|
| AssumeLit Int
|
||||||
|
| AssumeDone
|
||||||
|
|
||||||
|
solveAssuming :: CNF -> [Lit] -> IncResult
|
||||||
|
solveAssuming cnf assumps =
|
||||||
|
case solveManyAssuming cnf [assumps] of
|
||||||
|
[r] -> r
|
||||||
|
_ -> IncUnsat []
|
||||||
|
|
||||||
|
solveManyAssuming :: CNF -> [[Lit]] -> [IncResult]
|
||||||
|
solveManyAssuming (CNF cs) queries = runST $ do
|
||||||
|
let clauseMax = maximum (0 : map varId (concatMap varsOfClause cs))
|
||||||
|
assumpMax = maximum (0 : [ abs (litToInt l) | q <- queries, l <- q ])
|
||||||
|
nv = max clauseMax assumpMax
|
||||||
|
s <- newSolver nv
|
||||||
|
forM_ cs (addClause s . map litToInt)
|
||||||
|
forM queries $ \assumps -> do
|
||||||
|
outcome <- solveOne s (map (litOfDimacs . litToInt) assumps)
|
||||||
|
case outcome of
|
||||||
|
Right () -> do
|
||||||
|
model <- extractAssignment s
|
||||||
|
pure (IncSat model)
|
||||||
|
Left core ->
|
||||||
|
pure (IncUnsat (nub (map (litFromInt . dimacsOfLit . litNeg) core)))
|
||||||
|
|
||||||
|
solveOne :: Solver s -> [Int] -> ST s (Either [Int] ())
|
||||||
|
solveOne s assumps = do
|
||||||
|
cancelUntil s 0
|
||||||
|
ok <- readSTRef (okFlag s)
|
||||||
|
if not ok
|
||||||
|
then pure (Left [])
|
||||||
|
else do
|
||||||
|
confl0 <- propagate s
|
||||||
|
if confl0 >= 0
|
||||||
|
then do writeSTRef (okFlag s) False; pure (Left [])
|
||||||
|
else runRestarts 0
|
||||||
|
where
|
||||||
|
runRestarts restartNo = do
|
||||||
|
let budget = lubyBudget restartNo
|
||||||
|
outcome <- searchAssuming s assumps budget
|
||||||
|
case outcome of
|
||||||
|
StepSat -> pure (Right ())
|
||||||
|
StepUnsat core -> pure (Left core)
|
||||||
|
StepRestart -> do
|
||||||
|
modifySTRef' (statRest s) (+ 1)
|
||||||
|
runRestarts (restartNo + 1)
|
||||||
|
|
||||||
|
lubyBudget :: Int -> Int
|
||||||
|
lubyBudget restartNo = luby restartNo * 100
|
||||||
|
|
||||||
|
searchAssuming :: Solver s -> [Int] -> Int -> ST s StepOutcome
|
||||||
|
searchAssuming s assumps confBudget = loop 0
|
||||||
|
where
|
||||||
|
loop confSoFar = do
|
||||||
|
confl <- propagate s
|
||||||
|
if confl >= 0
|
||||||
|
then do
|
||||||
|
modifySTRef' (statConf s) (+ 1)
|
||||||
|
lvl <- currentLevel s
|
||||||
|
if lvl == 0
|
||||||
|
then do writeSTRef (okFlag s) False; pure (StepUnsat [])
|
||||||
|
else do
|
||||||
|
(learnt, btLevel, lbd) <- analyze s confl
|
||||||
|
cancelUntil s btLevel
|
||||||
|
installLearnt s learnt lbd
|
||||||
|
loop (confSoFar + 1)
|
||||||
|
else
|
||||||
|
if confSoFar >= confBudget
|
||||||
|
then do cancelUntil s 0; pure StepRestart
|
||||||
|
else do
|
||||||
|
maybeReduce s
|
||||||
|
step <- nextAssumption s assumps
|
||||||
|
case step of
|
||||||
|
AssumeConflict core -> pure (StepUnsat core)
|
||||||
|
AssumeLit next -> do
|
||||||
|
newDecisionLevel s
|
||||||
|
_ <- enqueue s next (-1)
|
||||||
|
loop confSoFar
|
||||||
|
AssumeDone -> do
|
||||||
|
v <- pickBranchVar s
|
||||||
|
if v < 0
|
||||||
|
then pure StepSat
|
||||||
|
else do
|
||||||
|
modifySTRef' (statDec s) (+ 1)
|
||||||
|
pol <- readArray (polarity s) v
|
||||||
|
let l = if pol then posLit v else negLit v
|
||||||
|
newDecisionLevel s
|
||||||
|
_ <- enqueue s l (-1)
|
||||||
|
loop confSoFar
|
||||||
|
|
||||||
|
nextAssumption :: Solver s -> [Int] -> ST s AssumeStep
|
||||||
|
nextAssumption s assumps = go
|
||||||
|
where
|
||||||
|
total = length assumps
|
||||||
|
go = do
|
||||||
|
dl <- currentLevel s
|
||||||
|
if dl >= total
|
||||||
|
then pure AssumeDone
|
||||||
|
else do
|
||||||
|
let p = assumps !! dl
|
||||||
|
v <- litValueInt s p
|
||||||
|
if v == 1
|
||||||
|
then do newDecisionLevel s; go
|
||||||
|
else if v == -1
|
||||||
|
then do
|
||||||
|
core <- analyzeFinal s (litNeg p)
|
||||||
|
pure (AssumeConflict core)
|
||||||
|
else pure (AssumeLit p)
|
||||||
|
|
||||||
|
extractAssignment :: Solver s -> ST s Assignment
|
||||||
|
extractAssignment s = do
|
||||||
|
pairs <- forM [0 .. numVars s - 1] $ \v -> do
|
||||||
|
vv <- varValue s v
|
||||||
|
pure (Var (v + 1), vv /= -1)
|
||||||
|
pure (Map.fromList pairs)
|
||||||
Reference in new issue
Block a user