feat(proof): add drat/rup proof logging and checking
This commit is contained in:
1 parent
8fea34a107
commit
cf47589cf6
1 file changed
+166
@@ -0,0 +1,166 @@
|
|||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
module Sift.Proof.Drat
|
||||||
|
( ProofResult(..)
|
||||||
|
, solveProof
|
||||||
|
, verifyProof
|
||||||
|
, isRup
|
||||||
|
, renderProof
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Control.Monad (forM_)
|
||||||
|
import Control.Monad.ST (ST, runST)
|
||||||
|
import Data.STRef
|
||||||
|
import Data.Array.ST (readArray)
|
||||||
|
import Data.List (nub)
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
import Sift.Types
|
||||||
|
import qualified Sift.Cdcl.State as St
|
||||||
|
import Sift.Cdcl.Search
|
||||||
|
( propagate, analyze, pickBranchVar, maybeReduce, installLearnt, luby )
|
||||||
|
|
||||||
|
data ProofResult
|
||||||
|
= ProofSat Assignment
|
||||||
|
| ProofUnsat [Clause]
|
||||||
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
solveProof :: CNF -> ProofResult
|
||||||
|
solveProof (CNF cs) = runST $ do
|
||||||
|
let nv = maximum (0 : map varId (concatMap varsOfClause cs))
|
||||||
|
s <- St.newSolver nv
|
||||||
|
proofRef <- newSTRef []
|
||||||
|
forM_ cs (St.addClause s . map litToInt)
|
||||||
|
ok0 <- readSTRef (St.okFlag s)
|
||||||
|
if not ok0
|
||||||
|
then pure (ProofUnsat [[]])
|
||||||
|
else do
|
||||||
|
confl0 <- propagate s
|
||||||
|
if confl0 >= 0
|
||||||
|
then pure (ProofUnsat [[]])
|
||||||
|
else do
|
||||||
|
verdict <- runRestarts s proofRef 0
|
||||||
|
if verdict
|
||||||
|
then do
|
||||||
|
model <- extractAssignment s
|
||||||
|
pure (ProofSat model)
|
||||||
|
else do
|
||||||
|
recorded <- reverse <$> readSTRef proofRef
|
||||||
|
pure (ProofUnsat (map toClause recorded ++ [[]]))
|
||||||
|
|
||||||
|
toClause :: [Int] -> Clause
|
||||||
|
toClause = map (litFromInt . St.dimacsOfLit)
|
||||||
|
|
||||||
|
runRestarts :: St.Solver s -> STRef s [[Int]] -> Int -> ST s Bool
|
||||||
|
runRestarts s proofRef restartNo = do
|
||||||
|
let budget = luby restartNo * 100
|
||||||
|
outcome <- proofSearch s proofRef budget
|
||||||
|
case outcome of
|
||||||
|
Just verdict -> pure verdict
|
||||||
|
Nothing -> do
|
||||||
|
modifySTRef' (St.statRest s) (+ 1)
|
||||||
|
runRestarts s proofRef (restartNo + 1)
|
||||||
|
|
||||||
|
proofSearch :: St.Solver s -> STRef s [[Int]] -> Int -> ST s (Maybe Bool)
|
||||||
|
proofSearch s proofRef confBudget = loop 0
|
||||||
|
where
|
||||||
|
loop confSoFar = do
|
||||||
|
confl <- propagate s
|
||||||
|
if confl >= 0
|
||||||
|
then do
|
||||||
|
modifySTRef' (St.statConf s) (+ 1)
|
||||||
|
lvl <- St.currentLevel s
|
||||||
|
if lvl == 0
|
||||||
|
then pure (Just False)
|
||||||
|
else do
|
||||||
|
(learnt, btLevel, lbd) <- analyze s confl
|
||||||
|
modifySTRef' proofRef (learnt :)
|
||||||
|
St.cancelUntil s btLevel
|
||||||
|
installLearnt s learnt lbd
|
||||||
|
loop (confSoFar + 1)
|
||||||
|
else
|
||||||
|
if confSoFar >= confBudget
|
||||||
|
then do St.cancelUntil s 0; pure Nothing
|
||||||
|
else do
|
||||||
|
maybeReduce s
|
||||||
|
v <- pickBranchVar s
|
||||||
|
if v < 0
|
||||||
|
then pure (Just True)
|
||||||
|
else do
|
||||||
|
modifySTRef' (St.statDec s) (+ 1)
|
||||||
|
pol <- readArray (St.polarity s) v
|
||||||
|
let l = if pol then St.posLit v else St.negLit v
|
||||||
|
St.newDecisionLevel s
|
||||||
|
_ <- St.enqueue s l (-1)
|
||||||
|
loop confSoFar
|
||||||
|
|
||||||
|
extractAssignment :: St.Solver s -> ST s Assignment
|
||||||
|
extractAssignment s = do
|
||||||
|
pairs <- mapM (\v -> do
|
||||||
|
vv <- St.varValue s v
|
||||||
|
pure (Var (v + 1), vv /= -1)) [0 .. St.numVars s - 1]
|
||||||
|
pure (Map.fromList pairs)
|
||||||
|
|
||||||
|
verifyProof :: CNF -> [Clause] -> Bool
|
||||||
|
verifyProof (CNF orig) = go orig
|
||||||
|
where
|
||||||
|
go _ [] = False
|
||||||
|
go formula (c : rest)
|
||||||
|
| not (isRup formula c) = False
|
||||||
|
| null c = True
|
||||||
|
| otherwise = go (c : formula) rest
|
||||||
|
|
||||||
|
isRup :: [Clause] -> Clause -> Bool
|
||||||
|
isRup formula lemma =
|
||||||
|
propagatesToConflict formula (map neg lemma)
|
||||||
|
|
||||||
|
propagatesToConflict :: [Clause] -> [Lit] -> Bool
|
||||||
|
propagatesToConflict clauses0 assumed =
|
||||||
|
case assignAll Map.empty assumed of
|
||||||
|
Nothing -> True
|
||||||
|
Just a0 -> loop a0
|
||||||
|
where
|
||||||
|
clauses = normalizeClauses clauses0
|
||||||
|
assignAll a [] = Just a
|
||||||
|
assignAll a (l : ls) = case extend a l of
|
||||||
|
Nothing -> Nothing
|
||||||
|
Just a' -> assignAll a' ls
|
||||||
|
extend a l = case Map.lookup (litVar l) a of
|
||||||
|
Just b
|
||||||
|
| b == litSign l -> Just a
|
||||||
|
| otherwise -> Nothing
|
||||||
|
Nothing -> Just (Map.insert (litVar l) (litSign l) a)
|
||||||
|
loop a
|
||||||
|
| any (falsifiedBy a) clauses = True
|
||||||
|
| otherwise =
|
||||||
|
case pickUnit a clauses of
|
||||||
|
Nothing -> False
|
||||||
|
Just l -> case extend a l of
|
||||||
|
Nothing -> True
|
||||||
|
Just a' -> loop a'
|
||||||
|
|
||||||
|
normalizeClauses :: [Clause] -> [Clause]
|
||||||
|
normalizeClauses = concatMap norm
|
||||||
|
where
|
||||||
|
norm c =
|
||||||
|
let deduped = nub c
|
||||||
|
in if any (\l -> neg l `elem` deduped) deduped then [] else [deduped]
|
||||||
|
|
||||||
|
falsifiedBy :: Assignment -> Clause -> Bool
|
||||||
|
falsifiedBy a c = all (\l -> litValue a l == Just False) c
|
||||||
|
|
||||||
|
pickUnit :: Assignment -> [Clause] -> Maybe Lit
|
||||||
|
pickUnit a = firstJust . map (unitLiteral a)
|
||||||
|
where
|
||||||
|
firstJust [] = Nothing
|
||||||
|
firstJust (Just l : _) = Just l
|
||||||
|
firstJust (Nothing : xs) = firstJust xs
|
||||||
|
|
||||||
|
unitLiteral :: Assignment -> Clause -> Maybe Lit
|
||||||
|
unitLiteral a c =
|
||||||
|
case [ l | l <- c, litValue a l == Nothing ] of
|
||||||
|
[l] | not (any (\k -> litValue a k == Just True) c) -> Just l
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
renderProof :: [Clause] -> String
|
||||||
|
renderProof = unlines . map renderClause
|
||||||
|
where
|
||||||
|
renderClause c = unwords (map (show . litToInt) c ++ ["0"])
|
||||||
Reference in new issue
Block a user