feat(cdcl): add solver state with two-watched-literal scheme
This commit is contained in:
1 parent
9795316136
commit
95b52dec31
1 file changed
+333
@@ -0,0 +1,333 @@
|
|||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
module Sift.Cdcl.State
|
||||||
|
( Solver(..)
|
||||||
|
, Clause(..)
|
||||||
|
, Watcher(..)
|
||||||
|
, Cid
|
||||||
|
, litOfDimacs
|
||||||
|
, dimacsOfLit
|
||||||
|
, litVar
|
||||||
|
, litSignPos
|
||||||
|
, litNeg
|
||||||
|
, posLit
|
||||||
|
, negLit
|
||||||
|
, newSolver
|
||||||
|
, litValueInt
|
||||||
|
, varValue
|
||||||
|
, currentLevel
|
||||||
|
, newDecisionLevel
|
||||||
|
, enqueue
|
||||||
|
, cancelUntil
|
||||||
|
, getClause
|
||||||
|
, newClause
|
||||||
|
, attachClause
|
||||||
|
, addClause
|
||||||
|
, varBumpActivity
|
||||||
|
, rescaleActivities
|
||||||
|
, claBumpActivity
|
||||||
|
, claRescale
|
||||||
|
, modifyWatch
|
||||||
|
, varDecayConst
|
||||||
|
, claDecayConst
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Control.Monad (when, forM_, foldM)
|
||||||
|
import Control.Monad.ST (ST)
|
||||||
|
import Data.Bits (xor)
|
||||||
|
import Data.STRef
|
||||||
|
import Data.Array.ST
|
||||||
|
import Data.List (sort)
|
||||||
|
import Sift.Cdcl.Heap
|
||||||
|
|
||||||
|
type Cid = Int
|
||||||
|
|
||||||
|
data Watcher = Watcher !Cid !Int
|
||||||
|
|
||||||
|
data Clause s = Clause
|
||||||
|
{ clsLits :: STUArray s Int Int
|
||||||
|
, clsSize :: !Int
|
||||||
|
, clsLearnt :: !Bool
|
||||||
|
, clsAct :: STRef s Double
|
||||||
|
, clsLbd :: STRef s Int
|
||||||
|
, clsDead :: STRef s Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
data Solver s = Solver
|
||||||
|
{ numVars :: !Int
|
||||||
|
, value :: STUArray s Int Int
|
||||||
|
, varLevel :: STUArray s Int Int
|
||||||
|
, varReason :: STUArray s Int Int
|
||||||
|
, polarity :: STUArray s Int Bool
|
||||||
|
, activity :: STUArray s Int Double
|
||||||
|
, seen :: STUArray s Int Bool
|
||||||
|
, trail :: STUArray s Int Int
|
||||||
|
, trailN :: STRef s Int
|
||||||
|
, qhead :: STRef s Int
|
||||||
|
, trailLim :: STRef s [Int]
|
||||||
|
, watches :: STArray s Int [Watcher]
|
||||||
|
, clauseArr :: STRef s (STArray s Int (Clause s))
|
||||||
|
, clauseN :: STRef s Int
|
||||||
|
, learnts :: STRef s [Cid]
|
||||||
|
, nLearnts :: STRef s Int
|
||||||
|
, heapH :: VarHeap s
|
||||||
|
, varInc :: STRef s Double
|
||||||
|
, claInc :: STRef s Double
|
||||||
|
, okFlag :: STRef s Bool
|
||||||
|
, statDec :: STRef s Int
|
||||||
|
, statConf :: STRef s Int
|
||||||
|
, statProp :: STRef s Int
|
||||||
|
, statRest :: STRef s Int
|
||||||
|
, statLearn :: STRef s Int
|
||||||
|
, statRemove :: STRef s Int
|
||||||
|
}
|
||||||
|
|
||||||
|
varDecayConst :: Double
|
||||||
|
varDecayConst = 0.95
|
||||||
|
|
||||||
|
claDecayConst :: Double
|
||||||
|
claDecayConst = 0.999
|
||||||
|
|
||||||
|
valUndef, valTrue, valFalse :: Int
|
||||||
|
valUndef = 0
|
||||||
|
valTrue = 1
|
||||||
|
valFalse = -1
|
||||||
|
|
||||||
|
litOfDimacs :: Int -> Int
|
||||||
|
litOfDimacs n
|
||||||
|
| n > 0 = 2 * (n - 1)
|
||||||
|
| otherwise = 2 * (negate n - 1) + 1
|
||||||
|
|
||||||
|
dimacsOfLit :: Int -> Int
|
||||||
|
dimacsOfLit l =
|
||||||
|
let v = litVar l + 1
|
||||||
|
in if litSignPos l then v else negate v
|
||||||
|
|
||||||
|
litVar :: Int -> Int
|
||||||
|
litVar l = l `div` 2
|
||||||
|
|
||||||
|
litSignPos :: Int -> Bool
|
||||||
|
litSignPos l = even l
|
||||||
|
|
||||||
|
litNeg :: Int -> Int
|
||||||
|
litNeg l = l `xor` 1
|
||||||
|
|
||||||
|
posLit :: Int -> Int
|
||||||
|
posLit v = 2 * v
|
||||||
|
|
||||||
|
negLit :: Int -> Int
|
||||||
|
negLit v = 2 * v + 1
|
||||||
|
|
||||||
|
newSolver :: Int -> ST s (Solver s)
|
||||||
|
newSolver n = do
|
||||||
|
let nv = max 1 n
|
||||||
|
val <- newArray (0, nv - 1) valUndef
|
||||||
|
lev <- newArray (0, nv - 1) (-1)
|
||||||
|
rsn <- newArray (0, nv - 1) (-1)
|
||||||
|
pol <- newArray (0, nv - 1) False
|
||||||
|
act <- newArray (0, nv - 1) 0
|
||||||
|
sn <- newArray (0, nv - 1) False
|
||||||
|
tr <- newArray (0, nv - 1) 0
|
||||||
|
trN <- newSTRef 0
|
||||||
|
qh <- newSTRef 0
|
||||||
|
tlim <- newSTRef []
|
||||||
|
ws <- newArray (0, 2 * nv - 1) []
|
||||||
|
cap0 <- newArray (0, 15) (error "empty clause slot") :: ST s (STArray s Int (Clause s))
|
||||||
|
carr <- newSTRef cap0
|
||||||
|
cn <- newSTRef 0
|
||||||
|
lrn <- newSTRef []
|
||||||
|
nlrn <- newSTRef 0
|
||||||
|
hp <- newHeap nv act
|
||||||
|
forM_ [0 .. n - 1] $ \v -> heapInsert hp v
|
||||||
|
vinc <- newSTRef 1.0
|
||||||
|
cinc <- newSTRef 1.0
|
||||||
|
ok <- newSTRef True
|
||||||
|
sd <- newSTRef 0
|
||||||
|
sc <- newSTRef 0
|
||||||
|
sp <- newSTRef 0
|
||||||
|
sr <- newSTRef 0
|
||||||
|
sl <- newSTRef 0
|
||||||
|
srm <- newSTRef 0
|
||||||
|
pure Solver
|
||||||
|
{ numVars = n
|
||||||
|
, value = val, varLevel = lev, varReason = rsn, polarity = pol
|
||||||
|
, activity = act, seen = sn, trail = tr, trailN = trN, qhead = qh
|
||||||
|
, trailLim = tlim, watches = ws, clauseArr = carr, clauseN = cn
|
||||||
|
, learnts = lrn, nLearnts = nlrn, heapH = hp, varInc = vinc, claInc = cinc
|
||||||
|
, okFlag = ok, statDec = sd, statConf = sc, statProp = sp, statRest = sr
|
||||||
|
, statLearn = sl, statRemove = srm
|
||||||
|
}
|
||||||
|
|
||||||
|
varValue :: Solver s -> Int -> ST s Int
|
||||||
|
varValue s v = readArray (value s) v
|
||||||
|
|
||||||
|
litValueInt :: Solver s -> Int -> ST s Int
|
||||||
|
litValueInt s l = do
|
||||||
|
vv <- readArray (value s) (litVar l)
|
||||||
|
if vv == valUndef
|
||||||
|
then pure valUndef
|
||||||
|
else pure (if litSignPos l then vv else negate vv)
|
||||||
|
|
||||||
|
currentLevel :: Solver s -> ST s Int
|
||||||
|
currentLevel s = length <$> readSTRef (trailLim s)
|
||||||
|
|
||||||
|
newDecisionLevel :: Solver s -> ST s ()
|
||||||
|
newDecisionLevel s = do
|
||||||
|
n <- readSTRef (trailN s)
|
||||||
|
modifySTRef' (trailLim s) (n :)
|
||||||
|
|
||||||
|
enqueue :: Solver s -> Int -> Cid -> ST s Bool
|
||||||
|
enqueue s l reason = do
|
||||||
|
v <- litValueInt s l
|
||||||
|
if v == valTrue
|
||||||
|
then pure True
|
||||||
|
else if v == valFalse
|
||||||
|
then pure False
|
||||||
|
else do
|
||||||
|
let var = litVar l
|
||||||
|
writeArray (value s) var (if litSignPos l then valTrue else valFalse)
|
||||||
|
lvl <- currentLevel s
|
||||||
|
writeArray (varLevel s) var lvl
|
||||||
|
writeArray (varReason s) var reason
|
||||||
|
writeArray (polarity s) var (litSignPos l)
|
||||||
|
n <- readSTRef (trailN s)
|
||||||
|
writeArray (trail s) n l
|
||||||
|
writeSTRef (trailN s) (n + 1)
|
||||||
|
pure True
|
||||||
|
|
||||||
|
cancelUntil :: Solver s -> Int -> ST s ()
|
||||||
|
cancelUntil s lvl = do
|
||||||
|
lim <- readSTRef (trailLim s)
|
||||||
|
let curLvl = length lim
|
||||||
|
when (curLvl > lvl) $ do
|
||||||
|
n <- readSTRef (trailN s)
|
||||||
|
let boundary = lim !! (curLvl - lvl - 1)
|
||||||
|
forM_ [n - 1, n - 2 .. boundary] $ \i -> do
|
||||||
|
l <- readArray (trail s) i
|
||||||
|
let var = litVar l
|
||||||
|
writeArray (value s) var valUndef
|
||||||
|
heapInsert (heapH s) var
|
||||||
|
writeSTRef (trailN s) boundary
|
||||||
|
writeSTRef (qhead s) boundary
|
||||||
|
writeSTRef (trailLim s) (drop (curLvl - lvl) lim)
|
||||||
|
|
||||||
|
getClause :: Solver s -> Cid -> ST s (Clause s)
|
||||||
|
getClause s cid = do
|
||||||
|
arr <- readSTRef (clauseArr s)
|
||||||
|
readArray arr cid
|
||||||
|
|
||||||
|
pushClauseRef :: Solver s -> Clause s -> ST s Cid
|
||||||
|
pushClauseRef s cl = do
|
||||||
|
arr <- readSTRef (clauseArr s)
|
||||||
|
cnt <- readSTRef (clauseN s)
|
||||||
|
(lo, hi) <- getBounds arr
|
||||||
|
arr' <-
|
||||||
|
if cnt > hi
|
||||||
|
then do
|
||||||
|
bigger <- newArray (lo, 2 * (hi + 1) - 1) (error "empty clause slot")
|
||||||
|
forM_ [lo .. hi] $ \i -> readArray arr i >>= writeArray bigger i
|
||||||
|
writeSTRef (clauseArr s) bigger
|
||||||
|
pure bigger
|
||||||
|
else pure arr
|
||||||
|
writeArray arr' cnt cl
|
||||||
|
writeSTRef (clauseN s) (cnt + 1)
|
||||||
|
pure cnt
|
||||||
|
|
||||||
|
newClause :: Solver s -> [Int] -> Bool -> ST s Cid
|
||||||
|
newClause s lits learnt = do
|
||||||
|
let sz = length lits
|
||||||
|
la <- newListArray (0, sz - 1) lits
|
||||||
|
act <- newSTRef 0
|
||||||
|
lbd <- newSTRef 0
|
||||||
|
dead <- newSTRef False
|
||||||
|
let cl = Clause la sz learnt act lbd dead
|
||||||
|
cid <- pushClauseRef s cl
|
||||||
|
when learnt $ do
|
||||||
|
modifySTRef' (learnts s) (cid :)
|
||||||
|
modifySTRef' (nLearnts s) (+ 1)
|
||||||
|
pure cid
|
||||||
|
|
||||||
|
attachClause :: Solver s -> Cid -> ST s ()
|
||||||
|
attachClause s cid = do
|
||||||
|
cl <- getClause s cid
|
||||||
|
l0 <- readArray (clsLits cl) 0
|
||||||
|
l1 <- readArray (clsLits cl) 1
|
||||||
|
modifyWatch s (litNeg l0) (Watcher cid l1)
|
||||||
|
modifyWatch s (litNeg l1) (Watcher cid l0)
|
||||||
|
|
||||||
|
modifyWatch :: Solver s -> Int -> Watcher -> ST s ()
|
||||||
|
modifyWatch s l w = do
|
||||||
|
old <- readArray (watches s) l
|
||||||
|
writeArray (watches s) l (w : old)
|
||||||
|
|
||||||
|
cleanClause :: [Int] -> Maybe [Int]
|
||||||
|
cleanClause lits = go (sort lits)
|
||||||
|
where
|
||||||
|
go [] = Just []
|
||||||
|
go [x] = Just [x]
|
||||||
|
go (x : y : rest)
|
||||||
|
| x == y = go (y : rest)
|
||||||
|
| x == litNeg y = Nothing
|
||||||
|
| otherwise = (x :) <$> go (y : rest)
|
||||||
|
|
||||||
|
addClause :: Solver s -> [Int] -> ST s ()
|
||||||
|
addClause s dimacsLits = do
|
||||||
|
ok <- readSTRef (okFlag s)
|
||||||
|
when ok $
|
||||||
|
case cleanClause (map litOfDimacs dimacsLits) of
|
||||||
|
Nothing -> pure ()
|
||||||
|
Just ls -> do
|
||||||
|
anyTrue <- foldM (\acc l -> if acc then pure True else (== valTrue) <$> litValueInt s l) False ls
|
||||||
|
if anyTrue
|
||||||
|
then pure ()
|
||||||
|
else do
|
||||||
|
kept <- filterFalse s ls
|
||||||
|
case kept of
|
||||||
|
[] -> writeSTRef (okFlag s) False
|
||||||
|
[u] -> do
|
||||||
|
r <- enqueue s u (-1)
|
||||||
|
when (not r) $ writeSTRef (okFlag s) False
|
||||||
|
_ -> do
|
||||||
|
cid <- newClause s kept False
|
||||||
|
attachClause s cid
|
||||||
|
|
||||||
|
filterFalse :: Solver s -> [Int] -> ST s [Int]
|
||||||
|
filterFalse s = go
|
||||||
|
where
|
||||||
|
go [] = pure []
|
||||||
|
go (l : ls) = do
|
||||||
|
v <- litValueInt s l
|
||||||
|
rest <- go ls
|
||||||
|
pure (if v == valFalse then rest else l : rest)
|
||||||
|
|
||||||
|
varBumpActivity :: Solver s -> Int -> ST s ()
|
||||||
|
varBumpActivity s v = do
|
||||||
|
inc <- readSTRef (varInc s)
|
||||||
|
a <- readArray (activity s) v
|
||||||
|
let a' = a + inc
|
||||||
|
writeArray (activity s) v a'
|
||||||
|
when (a' > 1e100) $ rescaleActivities s
|
||||||
|
heapIncrease (heapH s) v
|
||||||
|
|
||||||
|
rescaleActivities :: Solver s -> ST s ()
|
||||||
|
rescaleActivities s = do
|
||||||
|
forM_ [0 .. numVars s - 1] $ \v -> do
|
||||||
|
a <- readArray (activity s) v
|
||||||
|
writeArray (activity s) v (a * 1e-100)
|
||||||
|
modifySTRef' (varInc s) (* 1e-100)
|
||||||
|
|
||||||
|
claBumpActivity :: Solver s -> Clause s -> ST s ()
|
||||||
|
claBumpActivity s cl = do
|
||||||
|
inc <- readSTRef (claInc s)
|
||||||
|
a <- readSTRef (clsAct cl)
|
||||||
|
let a' = a + inc
|
||||||
|
writeSTRef (clsAct cl) a'
|
||||||
|
when (a' > 1e20) $ claRescale s
|
||||||
|
|
||||||
|
claRescale :: Solver s -> ST s ()
|
||||||
|
claRescale s = do
|
||||||
|
cids <- readSTRef (learnts s)
|
||||||
|
forM_ cids $ \cid -> do
|
||||||
|
cl <- getClause s cid
|
||||||
|
a <- readSTRef (clsAct cl)
|
||||||
|
writeSTRef (clsAct cl) (a * 1e-20)
|
||||||
|
modifySTRef' (claInc s) (* 1e-20)
|
||||||
Reference in new issue
Block a user