pure-validity / src /SAT /CDCL.hs
SNAPKITTYWEST's picture
push from SNAPKITTYWEST/pure-validity
56de343 verified
Raw
History Blame Contribute Delete
1.98 kB
module SAT.CDCL (cdcl, SATResult(..)) where
import SAT.CNF
import SAT.UnitProp
import qualified Data.Map.Strict as Map
import Data.List (nub)
data SATResult
= SAT (Map.Map Int Bool)
| UNSAT [Clause]
deriving (Show)
data DecisionLevel = DecisionLevel
{ dlVar :: Int
, dlVal :: Bool
, dlLevel :: Int
, dlImplied :: [(Int, Bool)]
} deriving (Show)
cdcl :: CNF -> SATResult
cdcl (CNF clauses numVars) = go Map.empty clauses [] 0
where
go asgn cls trail level =
case unitPropagate asgn cls of
Conflict ->
if level == 0 then UNSAT cls
else
let learned = analyzeConflict trail cls
newLevel = backtrackLevel trail learned
asgn' = backtrack asgn trail newLevel
trail' = take newLevel trail
in go asgn' (learned : cls) trail' newLevel
Propagated asgn' cls' ->
if null cls' then SAT asgn'
else
let var = chooseVar asgn' cls'
level' = level + 1
asgn'' = Map.insert var True asgn'
dl = DecisionLevel var True level' []
in go asgn'' cls' (trail ++ [dl]) level'
analyzeConflict :: [DecisionLevel] -> [Clause] -> Clause
analyzeConflict trail _ =
case trail of
[] -> []
dls -> let lastDl = last dls
in [Neg (dlVar lastDl)]
backtrackLevel :: [DecisionLevel] -> Clause -> Int
backtrackLevel trail _ = max 0 (length trail - 1)
backtrack :: Map.Map Int Bool -> [DecisionLevel] -> Int -> Map.Map Int Bool
backtrack asgn trail level =
let toRemove = drop level trail
vars = map dlVar toRemove
in foldr Map.delete asgn vars
chooseVar :: Map.Map Int Bool -> [Clause] -> Int
chooseVar asgn clauses =
let allVars = nub $ map litVar $ concat clauses
unassigned = filter (\v -> not (Map.member v asgn)) allVars
in case unassigned of
(v:_) -> v
[] -> 0