-- | (This is a part of MIOS.) -- Clause, supporting pointer-based equality {-# LANGUAGE FlexibleInstances , MagicHash , MultiParamTypeClasses , RecordWildCards , ViewPatterns #-} {-# LANGUAGE Trustworthy #-} module SAT.Mios.Clause ( Clause (..) , newClauseFromStack -- * Vector of Clause , ClauseVector , newClauseVector ) where import GHC.Prim (tagToEnum#, reallyUnsafePtrEquality#) import qualified Data.Vector as V import qualified Data.Vector.Mutable as MV -- import Data.List (intercalate) import SAT.Mios.Types -- | __Fig. 7.(p.11)__ -- normal, null (and binary) clause. -- This matches both of @Clause@ and @GClause@ in MiniSat. data Clause = Clause { rank :: !Int' -- ^ goodness like LBD; computed in 'Ranking' , activity :: !Double' -- ^ activity of this clause -- , protected :: !Bool' -- ^ protected from reduce , lits :: !Stack -- ^ which this clause consists of } | NullClause -- as null pointer -- | BinaryClause Lit -- binary clause consists of only a propagating literal -- | The equality on 'Clause' is defined with 'reallyUnsafePtrEquality'. instance Eq Clause where {-# SPECIALIZE INLINE (==) :: Clause -> Clause -> Bool #-} (==) x y = x `seq` y `seq` tagToEnum# (reallyUnsafePtrEquality# x y) instance Show Clause where show NullClause = "NullClause" show _ = "a clause" -- | 'Clause' is a 'VecFamily' of 'Lit'. instance VecFamily Clause Lit where {-# SPECIALIZE INLINE getNth :: Clause -> Int -> IO Int #-} getNth Clause{..} n = error "no getNth for Clause" {-# SPECIALIZE INLINE setNth :: Clause -> Int -> Int -> IO () #-} setNth Clause{..} n x = error "no setNth for Clause" -- | returns a vector of literals in it. asList NullClause = return [] asList Clause{..} = take <$> get' lits <*> (tail <$> asList lits) -- dump mes NullClause = return $ mes ++ "Null" -- dump mes Clause{..} = return $ mes ++ "a clause" {- dump mes Clause{..} = do a <- show <$> get' activity n <- get' lits l <- asList lits return $ mes ++ "C" ++ show n ++ "{" ++ intercalate "," [show learnt, a, show (map lit2int l)] ++ "}" -} -- | 'Clause' is a 'SingleStorage' on the number of literals in it. instance SingleStorage Clause Int where -- | returns the number of literals in a clause, even if the given clause is a binary clause {-# SPECIALIZE INLINE get' :: Clause -> IO Int #-} get' = get' . lits -- getSize (BinaryClause _) = return 1 -- | sets the number of literals in a clause, even if the given clause is a binary clause {-# SPECIALIZE INLINE set' :: Clause -> Int -> IO () #-} set' c n = set' (lits c) n -- getSize (BinaryClause _) = return 1 -- | 'Clause' is a 'Stackfamily'on literals since literals in it will be discared if satisifed at level = 0. instance StackFamily Clause Lit where -- | drop the last /N/ literals in a 'Clause' to eliminate unsatisfied literals {-# SPECIALIZE INLINE shrinkBy :: Clause -> Int -> IO () #-} shrinkBy c n = modifyNth (lits c) (subtract n) 0 -- coverts a binary clause to normal clause in order to reuse map-on-literals-in-a-clause codes. -- liftToClause :: Clause -> Clause -- liftToClause (BinaryClause _) = error "So far I use generic function approach instead of lifting" -- | copies /vec/ and return a new 'Clause'. -- Since 1.0.100 DIMACS reader should use a scratch buffer allocated statically. {-# INLINABLE newClauseFromStack #-} newClauseFromStack :: Bool -> Stack -> IO Clause newClauseFromStack l vec = do n <- get' vec v <- newStack n let loop ((<= n) -> False) = return () loop i = (setNth v i =<< getNth vec i) >> loop (i + 1) loop 0 Clause <$> new' (if l then 1 else 0) <*> new' 0.0 {- <*> new' False -} <*> return v -------------------------------------------------------------------------------- Clause Vector -- | Mutable 'Clause' Vector type ClauseVector = MV.IOVector Clause -- | 'ClauseVector' is a vector of 'Clause'. instance VecFamily ClauseVector Clause where {-# SPECIALIZE INLINE getNth :: ClauseVector -> Int -> IO Clause #-} getNth = MV.unsafeRead {-# SPECIALIZE INLINE setNth :: ClauseVector -> Int -> Clause -> IO () #-} setNth = MV.unsafeWrite {-# SPECIALIZE INLINE swapBetween :: ClauseVector -> Int -> Int -> IO () #-} swapBetween = MV.unsafeSwap asList cv = V.toList <$> V.freeze cv -- mapM (asList <=< getNth vec) [0 .. ???] {- dump mes cv = do l <- asList cv sts <- mapM (dump ",") (l :: [Clause]) return $ mes ++ tail (concat sts) -} -- | returns a new 'ClauseVector'. newClauseVector :: Int -> IO ClauseVector newClauseVector n = do v <- MV.new (max 4 n) MV.set v NullClause return v