mios-1.5.4: src/SAT/Mios/ClauseManager.hs
-- | (This is a part of MIOS.)
-- A shrinkable vector of 'C.Clause'
{-# LANGUAGE
BangPatterns
, FlexibleInstances
, MultiParamTypeClasses
, RecordWildCards
, ViewPatterns
#-}
{-# LANGUAGE Trustworthy #-}
module SAT.Mios.ClauseManager
(
-- * higher level interface for ClauseVector
ClauseManager (..)
-- * Simple Clause Manager
, ClauseSimpleManager
-- * Manager with an extra Int (used as sort key or blocking literal)
, ClauseExtManager
, pushClauseWithKey
, getKeyVector
, markClause
-- * WatcherList
, WatcherList
, newWatcherList
, getNthWatcher
)
where
import Control.Monad (unless, when)
import qualified Data.IORef as IORef
import qualified Data.Vector as V
import qualified Data.Vector.Mutable as MV
import SAT.Mios.Types
import qualified SAT.Mios.Clause as C
-- | Resizable vector of 'C.Clause'.
class ClauseManager a where
newManager :: Int -> IO a
getClauseVector :: a -> IO C.ClauseVector
-- removeClause :: a -> C.Clause -> IO ()
-- removeNthClause :: a -> Int -> IO ()
--------------------------------------------------------------------------------
-- | Clause + Blocking Literal
data ClauseSimpleManager = ClauseSimpleManager
{
_numActives :: !Int' -- number of active clause
, _clsVector :: IORef.IORef C.ClauseVector -- clause list
}
-- | 'ClauseSimpleManager' is a 'SingleStorage` on the number of clauses in it.
instance SingleStorage ClauseSimpleManager Int where
{-# SPECIALIZE INLINE get' :: ClauseSimpleManager -> IO Int #-}
get' m = get' (_numActives m)
{-# SPECIALIZE INLINE set' :: ClauseSimpleManager -> Int -> IO () #-}
set' m = set' (_numActives m)
-- | 'ClauseSimpleManager' is a 'StackFamily` on clauses.
instance StackFamily ClauseSimpleManager C.Clause where
{-# SPECIALIZE INLINE shrinkBy :: ClauseSimpleManager -> Int -> IO () #-}
shrinkBy m k = modify' (_numActives m) (subtract k)
pushTo ClauseSimpleManager{..} c = do
-- checkConsistency m c
!n <- get' _numActives
!v <- IORef.readIORef _clsVector
if MV.length v - 1 <= n
then do
let len = max 8 $ MV.length v
v' <- MV.unsafeGrow v len
MV.unsafeWrite v' n c
IORef.writeIORef _clsVector v'
else MV.unsafeWrite v n c
modify' _numActives (1 +)
popFrom m = modify' (_numActives m) (subtract 1)
lastOf ClauseSimpleManager{..} = do
n <- get' _numActives
v <- IORef.readIORef _clsVector
MV.unsafeRead v (n - 1)
-- | 'ClauseSimpleManager' is a 'ClauseManager'
instance ClauseManager ClauseSimpleManager where
-- | returns a new instance.
{-# SPECIALIZE INLINE newManager :: Int -> IO ClauseSimpleManager #-}
newManager initialSize = do
i <- new' 0
v <- C.newClauseVector initialSize
ClauseSimpleManager i <$> IORef.newIORef v
-- | returns the internal 'C.ClauseVector'.
{-# SPECIALIZE INLINE getClauseVector :: ClauseSimpleManager -> IO C.ClauseVector #-}
getClauseVector !m = IORef.readIORef (_clsVector m)
--------------------------------------------------------------------------------
-- | Clause + Blocking Literal
data ClauseExtManager = ClauseExtManager
{
_nActives :: !Int' -- number of active clause
, _purged :: !Bool' -- whether it needs gc
, _clauseVector :: IORef.IORef C.ClauseVector -- clause list
, _keyVector :: IORef.IORef (Vec [Int]) -- Int list
}
-- | 'ClauseExtManager' is a 'SingleStorage` on the number of clauses in it.
instance SingleStorage ClauseExtManager Int where
{-# SPECIALIZE INLINE get' :: ClauseExtManager -> IO Int #-}
get' m = get' (_nActives m)
{-# SPECIALIZE INLINE set' :: ClauseExtManager -> Int -> IO () #-}
set' m = set' (_nActives m)
-- | 'ClauseExtManager' is a 'StackFamily` on clauses.
instance StackFamily ClauseExtManager C.Clause where
{-# SPECIALIZE INLINE shrinkBy :: ClauseExtManager -> Int -> IO () #-}
shrinkBy m k = modify' (_nActives m) (subtract k)
pushTo ClauseExtManager{..} c = do
-- checkConsistency m c
!n <- get' _nActives
!v <- IORef.readIORef _clauseVector
!b <- IORef.readIORef _keyVector
if MV.length v - 1 <= n
then do
let len = max 8 $ MV.length v
v' <- MV.unsafeGrow v len
b' <- growBy b len
MV.unsafeWrite v' n c
setNth b' n 0
IORef.writeIORef _clauseVector v'
IORef.writeIORef _keyVector b'
else MV.unsafeWrite v n c >> setNth b n 0
modify' _nActives (1 +)
popFrom m = modify' (_nActives m) (subtract 1)
lastOf ClauseExtManager{..} = do
n <- get' _nActives
v <- IORef.readIORef _clauseVector
MV.unsafeRead v (n - 1)
-- | 'ClauseExtManager' is a 'ClauseManager'
instance ClauseManager ClauseExtManager where
-- | returns a new instance.
{-# SPECIALIZE INLINE newManager :: Int -> IO ClauseExtManager #-}
newManager initialSize = do
i <- new' 0
v <- C.newClauseVector initialSize
b <- newVec (MV.length v) 0
ClauseExtManager i <$> new' False <*> IORef.newIORef v <*> IORef.newIORef b
-- | returns the internal 'C.ClauseVector'.
{-# SPECIALIZE INLINE getClauseVector :: ClauseExtManager -> IO C.ClauseVector #-}
getClauseVector !m = IORef.readIORef (_clauseVector m)
{-
-- | O(1) insertion function
pushClause !ClauseExtManager{..} !c = do
-- checkConsistency m c
!n <- get' _nActives
!v <- IORef.readIORef _clauseVector
!b <- IORef.readIORef _keyVector
if MV.length v - 1 <= n
then do
let len = max 8 $ MV.length v
v' <- MV.unsafeGrow v len
b' <- growBy b len
MV.unsafeWrite v' n c
setNth b' n 0
IORef.writeIORef _clauseVector v'
IORef.writeIORef _keyVector b'
else MV.unsafeWrite v n c >> setNth b n 0
modify' _nActives (1 +)
-}
{-
-- | O(n) but lightweight remove-and-compact function
-- __Pre-conditions:__ the clause manager is empty or the clause is stored in it.
{-# SPECIALIZE INLINE removeClause :: ClauseExtManager -> C.Clause -> IO () #-}
removeClause ClauseExtManager{..} c = do
!n <- subtract 1 <$> get' _nActives
!v <- IORef.readIORef _clauseVector
!b <- IORef.readIORef _keyVector
let
seekIndex :: Int -> IO Int
seekIndex k = do
c' <- MV.unsafeRead v k
if c' == c then return k else seekIndex $ k + 1
unless (n == -1) $ do
!i <- seekIndex 0
MV.unsafeWrite v i =<< MV.unsafeRead v n
setNth b i =<< getNth b n
set' _nActives n
removeNthClause = error "removeNthClause is not implemented on ClauseExtManager"
-}
-- | sets the expire flag to a clause.
{-# INLINABLE markClause #-}
markClause :: ClauseExtManager -> C.Clause -> IO ()
markClause ClauseExtManager{..} c = do
!n <- get' _nActives
!v <- IORef.readIORef _clauseVector
let
seekIndex :: Int -> IO ()
seekIndex k = do
-- assert (k < n)
c' <- MV.unsafeRead v k
if c' == c then MV.unsafeWrite v k C.NullClause else seekIndex $ k + 1
unless (n == 0) $ do
seekIndex 0
set' _purged True
{-# INLINABLE purifyManager #-}
purifyManager :: ClauseExtManager -> IO ()
purifyManager ClauseExtManager{..} = do
diry <- get' _purged
when diry $ do
n <- get' _nActives
vec <- IORef.readIORef _clauseVector
keys <- IORef.readIORef _keyVector
let
loop :: Int -> Int -> IO Int
loop ((< n) -> False) n' = return n'
loop i j = do
c <- getNth vec i
if c /= C.NullClause
then do
unless (i == j) $ do
setNth vec j c
setNth keys j =<< getNth keys i
loop (i + 1) (j + 1)
else loop (i + 1) j
set' _nActives =<< loop 0 0
set' _purged False
-- | returns the associated Int vector, which holds /blocking literals/.
{-# INLINE getKeyVector #-}
getKeyVector :: ClauseExtManager -> IO (Vec [Int])
getKeyVector ClauseExtManager{..} = IORef.readIORef _keyVector
-- | O(1) inserter
{-# INLINABLE pushClauseWithKey #-}
pushClauseWithKey :: ClauseExtManager -> C.Clause -> Lit -> IO ()
pushClauseWithKey ClauseExtManager{..} !c k = do
-- checkConsistency m c
!n <- get' _nActives
!v <- IORef.readIORef _clauseVector
!b <- IORef.readIORef _keyVector
if MV.length v - 1 <= n
then do
let len = max 8 $ MV.length v
v' <- MV.unsafeGrow v len
b' <- growBy b len
MV.unsafeWrite v' n c
setNth b' n k
IORef.writeIORef _clauseVector v'
IORef.writeIORef _keyVector b'
else MV.unsafeWrite v n c >> setNth b n k
modify' _nActives (1 +)
-- | 'ClauseExtManager' is a collection of 'C.Clause'
instance VecFamily ClauseExtManager C.Clause where
getNth = error "no getNth method for ClauseExtManager"
setNth = error "no setNth method for ClauseExtManager"
{-# SPECIALIZE INLINE reset :: ClauseExtManager -> IO () #-}
reset m = set' (_nActives m) 0
{-
dump mes ClauseExtManager{..} = do
n <- get' _nActives
if n == 0
then return $ mes ++ "empty ClauseExtManager"
else do
l <- take n <$> (asList =<< IORef.readIORef _clauseVector)
sts <- mapM (dump ",") (l :: [C.Clause])
return $ mes ++ "[" ++ show n ++ "]" ++ tail (concat sts)
-}
-------------------------------------------------------------------------------- WatcherList
-- | Immutable Vector of 'ClauseExtManager'
type WatcherList = V.Vector ClauseExtManager
-- | /n/ is the number of 'Var', /m/ is default size of each watcher list.
-- | For /n/ vars, we need [0 .. 2 + 2 * n - 1] slots, namely /2 * (n + 1)/-length vector
-- FIXME: sometimes n > 1M
newWatcherList :: Int -> Int -> IO WatcherList
newWatcherList n m = V.replicateM (int2lit (negate n) + 2) (newManager m)
-- | returns the watcher List for "Literal" /l/.
{-# INLINE getNthWatcher #-}
getNthWatcher :: WatcherList -> Lit -> ClauseExtManager
getNthWatcher = V.unsafeIndex
-- | 'WatcherList' is an 'Lit'-indexed collection of 'C.Clause'.
instance VecFamily WatcherList C.Clause where
getNth = error "no getNth method for WatcherList" -- getNthWatcher is a pure function
setNth = error "no setNth method for WatcherList"
{-# SPECIALIZE INLINE reset :: WatcherList -> IO () #-}
reset = V.mapM_ purifyManager
-- dump _ _ = (mes ++) . concat <$> mapM (\i -> dump ("\n" ++ show (lit2int i) ++ "' watchers:") (getNthWatcher wl i)) [1 .. V.length wl - 1]