feat(dpll): add recursive dpll solver with model verification

This commit is contained in:
dualfroz committed 2026-08-23 19:15:00 +02:00
1 parent 34d591cbc3
commit 09cf81b3e0
2 files changed
+95

No files matched your search

+75
View File
@@ -0,0 +1,75 @@
module Sift.Solver
( Result(..)
, solve
, dpll
) where
import Sift.Types
import Sift.Verify (completeModel)
import Data.List (maximumBy, nub)
import Data.Ord (comparing)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
data Result
= Sat Assignment
| Unsat
deriving (Eq, Show)
solve :: CNF -> Result
solve cnf@(CNF cs) =
case dpll cs Map.empty of
Nothing -> Unsat
Just asn -> Sat (completeModel cnf asn)
dpll :: [Clause] -> Assignment -> Maybe Assignment
dpll original asn =
case reduce asn original of
Nothing -> Nothing
Just cs
| null cs -> Just asn
| otherwise ->
case findUnit cs of
Just l -> dpll original (assign l asn)
Nothing ->
case findPure cs of
Just l -> dpll original (assign l asn)
Nothing ->
let l = chooseLit cs
in case dpll original (assign l asn) of
Just m -> Just m
Nothing -> dpll original (assign (neg l) asn)
assign :: Lit -> Assignment -> Assignment
assign l = Map.insert (litVar l) (litSign l)
reduce :: Assignment -> [Clause] -> Maybe [Clause]
reduce asn = fmap reverse . foldl step (Just [])
where
step Nothing _ = Nothing
step (Just acc) c
| any ((== Just True) . litValue asn) c = Just acc
| otherwise =
let remaining = filter ((== Nothing) . litValue asn) c
in if null remaining then Nothing else Just (remaining : acc)
findUnit :: [Clause] -> Maybe Lit
findUnit cs = case [ l | [l] <- cs ] of
(l:_) -> Just l
[] -> Nothing
findPure :: [Clause] -> Maybe Lit
findPure cs =
case [ Lit v s | (v, [s]) <- Map.toList signsByVar ] of
(l:_) -> Just l
[] -> Nothing
where
signsByVar :: Map Var [Bool]
signsByVar =
Map.map nub (Map.fromListWith (++) [ (litVar l, [litSign l]) | l <- concat cs ])
chooseLit :: [Clause] -> Lit
chooseLit cs = fst (maximumBy (comparing snd) (Map.toList counts))
where
counts :: Map Lit Int
counts = Map.fromListWith (+) [ (l, 1) | l <- concat cs ]
+20
View File
@@ -0,0 +1,20 @@
module Sift.Verify
( satisfies
, clauseSatisfied
, completeModel
) where
import Sift.Types
import qualified Data.Map.Strict as Map
clauseSatisfied :: Assignment -> Clause -> Bool
clauseSatisfied asn = any ((== Just True) . litValue asn)
satisfies :: Assignment -> CNF -> Bool
satisfies asn (CNF cs) = all (clauseSatisfied asn) cs
completeModel :: CNF -> Assignment -> Assignment
completeModel cnf asn =
foldr insertDefault asn (allVars cnf)
where
insertDefault v m = if Map.member v m then m else Map.insert v True m