module SAT.UnitProp (unitPropagate, UnitResult(..)) where import SAT.CNF import qualified Data.Map.Strict as Map import Data.List (nub) data UnitResult = Propagated (Map.Map Int Bool) [Clause] | Conflict deriving (Show) unitPropagate :: Map.Map Int Bool -> [Clause] -> UnitResult unitPropagate assignment clauses = go assignment clauses where go asgn cls = case findUnit cls asgn of Nothing -> let simplified = simplifyClauses asgn cls in if any null simplified then Conflict else Propagated asgn simplified Just (var, val) -> let asgn' = Map.insert var val asgn simplified = simplifyClauses asgn' cls in if any null simplified then Conflict else go asgn' simplified findUnit :: [Clause] -> Map.Map Int Bool -> Maybe (Int, Bool) findUnit clauses asgn = go clauses where go [] = Nothing go (c:cs) = let unresolved = filter (not . resolved asgn) c in case unresolved of [lit] -> Just (litVar lit, isPositive lit) _ -> go cs isPositive (Pos _) = True isPositive (Neg _) = False resolved :: Map.Map Int Bool -> Literal -> Bool resolved asgn (Pos v) = Map.member v asgn resolved asgn (Neg v) = Map.member v asgn simplifyClauses :: Map.Map Int Bool -> [Clause] -> [Clause] simplifyClauses asgn = filter (not . satisfied asgn) . map (removeResolved asgn) satisfied :: Map.Map Int Bool -> Clause -> Bool satisfied asgn = any (satLit asgn) satLit :: Map.Map Int Bool -> Literal -> Bool satLit asgn (Pos v) = Map.lookup v asgn == Just True satLit asgn (Neg v) = Map.lookup v asgn == Just False removeResolved :: Map.Map Int Bool -> Clause -> Clause removeResolved asgn = filter (\lit -> not (falseLit asgn lit)) falseLit :: Map.Map Int Bool -> Literal -> Bool falseLit asgn (Pos v) = Map.lookup v asgn == Just False falseLit asgn (Neg v) = Map.lookup v asgn == Just True