packages feed

mios 1.4.0 → 1.5.4

raw patch · 39 files changed

+4423/−3424 lines, 39 filesdep +miosdep +primitivedep ~basedep ~vectornew-component:exe:cnf-statnew-component:exe:mc-averagecsvnew-component:exe:mc-dump2csvnew-component:exe:mc-numbersnew-component:exe:mc-pickupnew-component:exe:mc-stat2csvnew-component:exe:mc-summarynew-component:exe:mios-1.5.4new-component:exe:mios-mcPVP ok

version bump matches the API change (PVP)

Dependencies added: mios, primitive

Dependency ranges changed: base, vector

API changes (from Hackage documentation)

- SAT.Mios: getModel :: Solver -> IO [Int]
- SAT.Mios.Clause: [learnt] :: Clause -> !Bool
- SAT.Mios.Clause: [protected] :: Clause -> !Bool'
- SAT.Mios.OptionParser: [_confStatProbe] :: MiosProgramOption -> !Bool
- SAT.Mios.OptionParser: [_confTimeProbe] :: MiosProgramOption -> !Bool
- SAT.Mios.Solver: [model] :: Solver -> !(Vec Int)
- SAT.Mios.Solver: addClause :: Solver -> Stack -> IO Bool
- SAT.Mios.Solver: claActivityThreshold :: Double
- SAT.Mios.Solver: claBumpActivity :: Solver -> Clause -> IO ()
- SAT.Mios.Solver: claRescaleActivityAfterRestart :: Solver -> IO ()
- SAT.Mios.Solver: data VarHeap
- SAT.Mios.Solver: getModel :: Solver -> IO [Int]
- SAT.Mios.Solver: instance GHC.Classes.Eq SAT.Mios.Solver.StatIndex
- SAT.Mios.Solver: instance GHC.Classes.Ord SAT.Mios.Solver.StatIndex
- SAT.Mios.Solver: instance GHC.Enum.Bounded SAT.Mios.Solver.StatIndex
- SAT.Mios.Solver: instance GHC.Enum.Enum SAT.Mios.Solver.StatIndex
- SAT.Mios.Solver: instance GHC.Read.Read SAT.Mios.Solver.StatIndex
- SAT.Mios.Solver: instance GHC.Show.Show SAT.Mios.Solver.StatIndex
- SAT.Mios.Solver: varBumpActivity :: Solver -> Var -> IO ()
- SAT.Mios.Solver: varDecayActivity :: Solver -> IO ()
- SAT.Mios.Types: lBottom :: Int
- SAT.Mios.Types: lFalse :: Int
- SAT.Mios.Types: lTrue :: Int
- SAT.Mios.Vec: Vec :: (UVector a) -> Vec a
- SAT.Mios.Vec: asUVector :: (VecFamily v a, a ~ Int) => v -> UVector Int
- SAT.Mios.Vec: instance SAT.Mios.Vec.SingleStorage SAT.Mios.Vec.Double' GHC.Types.Double
- SAT.Mios.Vec: instance SAT.Mios.Vec.SingleStorage SAT.Mios.Vec.Int' GHC.Types.Int
- SAT.Mios.Vec: instance SAT.Mios.Vec.SingleStorage SAT.Mios.Vec.Stack GHC.Types.Int
- SAT.Mios.Vec: instance SAT.Mios.Vec.StackFamily SAT.Mios.Vec.Stack GHC.Types.Int
- SAT.Mios.Vec: instance SAT.Mios.Vec.VecFamily (SAT.Mios.Vec.UVector GHC.Types.Double) GHC.Types.Double
- SAT.Mios.Vec: instance SAT.Mios.Vec.VecFamily (SAT.Mios.Vec.Vec GHC.Types.Double) GHC.Types.Double
- SAT.Mios.Vec: instance SAT.Mios.Vec.VecFamily (SAT.Mios.Vec.Vec GHC.Types.Int) GHC.Types.Int
- SAT.Mios.Vec: newtype Vec a
- SAT.Mios.Vec: type UVector a = IOVector a
+ SAT.Mios: SAT :: [Int] -> Certificate
+ SAT.Mios: UNSAT :: [Int] -> Certificate
+ SAT.Mios: data Certificate
+ SAT.Mios: injectClausesFromCNF :: Solver -> CNFDescription -> ByteString -> IO ()
+ SAT.Mios: parseCNF :: Maybe FilePath -> IO (CNFDescription, ByteString)
+ SAT.Mios: type SolverResult = Either SolverException Certificate
+ SAT.Mios.Clause: [rank] :: Clause -> !Int'
+ SAT.Mios.ClauseManager: data ClauseSimpleManager
+ SAT.Mios.ClauseManager: instance SAT.Mios.ClauseManager.ClauseManager SAT.Mios.ClauseManager.ClauseSimpleManager
+ SAT.Mios.ClauseManager: instance SAT.Mios.Vec.SingleStorage SAT.Mios.ClauseManager.ClauseSimpleManager GHC.Types.Int
+ SAT.Mios.ClauseManager: instance SAT.Mios.Vec.StackFamily SAT.Mios.ClauseManager.ClauseSimpleManager SAT.Mios.Clause.Clause
+ SAT.Mios.ClausePool: makeClauseFromStack :: ClausePool -> Stack -> IO Clause
+ SAT.Mios.ClausePool: newClausePool :: Int -> IO ClausePool
+ SAT.Mios.ClausePool: putBackToPool :: ClausePool -> Clause -> IO ()
+ SAT.Mios.ClausePool: type ClausePool = Vector ClauseSimpleManager
+ SAT.Mios.Criteria: addClause :: Solver -> Stack -> IO Bool
+ SAT.Mios.Criteria: checkRestartCondition :: Solver -> Int -> IO Bool
+ SAT.Mios.Criteria: claBumpActivity :: Solver -> Clause -> IO ()
+ SAT.Mios.Criteria: claDecayActivity :: Solver -> IO ()
+ SAT.Mios.Criteria: lbdOf :: Solver -> Stack -> IO Int
+ SAT.Mios.Criteria: varBumpActivity :: Solver -> Var -> IO ()
+ SAT.Mios.Criteria: varDecayActivity :: Solver -> IO ()
+ SAT.Mios.Main: addClause :: Solver -> Stack -> IO Bool
+ SAT.Mios.Main: data Solver
+ SAT.Mios.Main: dumpSolver :: DumpMode -> Solver -> IO ()
+ SAT.Mios.Main: newSolver :: MiosConfiguration -> CNFDescription -> IO Solver
+ SAT.Mios.Main: setAssign :: Solver -> Int -> LiftedBool -> IO ()
+ SAT.Mios.OptionParser: [_confBenchSeq] :: MiosProgramOption -> !Int
+ SAT.Mios.OptionParser: [_confBenchmark] :: MiosProgramOption -> Integer
+ SAT.Mios.OptionParser: [_confClauseDecayRate] :: MiosProgramOption -> Double
+ SAT.Mios.OptionParser: [_confDumpStat] :: MiosProgramOption -> !Int
+ SAT.Mios.OptionParser: [_confMaxSize] :: MiosProgramOption -> !Int
+ SAT.Mios.OptionParser: [_targets] :: MiosProgramOption -> [String]
+ SAT.Mios.OptionParser: [clauseDecayRate] :: MiosConfiguration -> !Double
+ SAT.Mios.OptionParser: [dumpStat] :: MiosConfiguration -> !Int
+ SAT.Mios.Solver: NumOfAssigned :: StatIndex
+ SAT.Mios.Solver: NumOfBlockRestart :: StatIndex
+ SAT.Mios.Solver: NumOfClause :: StatIndex
+ SAT.Mios.Solver: NumOfGeometricRestart :: StatIndex
+ SAT.Mios.Solver: NumOfLearnt :: StatIndex
+ SAT.Mios.Solver: NumOfPropagation :: StatIndex
+ SAT.Mios.Solver: NumOfReduction :: StatIndex
+ SAT.Mios.Solver: NumOfVariable :: StatIndex
+ SAT.Mios.Solver: [claInc] :: Solver -> !Double'
+ SAT.Mios.Solver: [clsPool] :: Solver -> ClausePool
+ SAT.Mios.Solver: [emaAFast] :: Solver -> !Double'
+ SAT.Mios.Solver: [emaASlow] :: Solver -> !Double'
+ SAT.Mios.Solver: [emaDFast] :: Solver -> !Double'
+ SAT.Mios.Solver: [emaDSlow] :: Solver -> !Double'
+ SAT.Mios.Solver: [lbd'key] :: Solver -> !Int'
+ SAT.Mios.Solver: [lbd'seen] :: Solver -> !(Vec Int)
+ SAT.Mios.Solver: [learntSAdj] :: Solver -> Double'
+ SAT.Mios.Solver: [learntSCnt] :: Solver -> Int'
+ SAT.Mios.Solver: [maxLearnts] :: Solver -> Double'
+ SAT.Mios.Solver: [nextRestart] :: Solver -> !Int'
+ SAT.Mios.Solver: [restartMode] :: Solver -> Int'
+ SAT.Mios.Solver: dumpSolver :: DumpMode -> Solver -> IO ()
+ SAT.Mios.Solver: setAssign :: Solver -> Int -> LiftedBool -> IO ()
+ SAT.Mios.Types: DumpCSV :: DumpMode
+ SAT.Mios.Types: DumpCSVHeader :: DumpMode
+ SAT.Mios.Types: DumpJSON :: DumpMode
+ SAT.Mios.Types: EndOfStatIndex :: StatIndex
+ SAT.Mios.Types: InternalInconsistent :: SolverException
+ SAT.Mios.Types: NoDump :: DumpMode
+ SAT.Mios.Types: NumOfAssigned :: StatIndex
+ SAT.Mios.Types: NumOfBackjump :: StatIndex
+ SAT.Mios.Types: NumOfBlockRestart :: StatIndex
+ SAT.Mios.Types: NumOfClause :: StatIndex
+ SAT.Mios.Types: NumOfGeometricRestart :: StatIndex
+ SAT.Mios.Types: NumOfLearnt :: StatIndex
+ SAT.Mios.Types: NumOfPropagation :: StatIndex
+ SAT.Mios.Types: NumOfReduction :: StatIndex
+ SAT.Mios.Types: NumOfRestart :: StatIndex
+ SAT.Mios.Types: NumOfVariable :: StatIndex
+ SAT.Mios.Types: OutOfMemory :: SolverException
+ SAT.Mios.Types: SAT :: [Int] -> Certificate
+ SAT.Mios.Types: StateSAT :: SolverException
+ SAT.Mios.Types: StateUNSAT :: SolverException
+ SAT.Mios.Types: TimeOut :: SolverException
+ SAT.Mios.Types: UNSAT :: [Int] -> Certificate
+ SAT.Mios.Types: UndescribedError :: SolverException
+ SAT.Mios.Types: [clauseDecayRate] :: MiosConfiguration -> !Double
+ SAT.Mios.Types: [dumpStat] :: MiosConfiguration -> !Int
+ SAT.Mios.Types: data Certificate
+ SAT.Mios.Types: data DumpMode
+ SAT.Mios.Types: data Int :: *
+ SAT.Mios.Types: data SolverException
+ SAT.Mios.Types: data StatIndex
+ SAT.Mios.Types: instance GHC.Classes.Eq SAT.Mios.Types.Certificate
+ SAT.Mios.Types: instance GHC.Classes.Eq SAT.Mios.Types.DumpMode
+ SAT.Mios.Types: instance GHC.Classes.Eq SAT.Mios.Types.DumpTag
+ SAT.Mios.Types: instance GHC.Classes.Eq SAT.Mios.Types.MiosConfiguration
+ SAT.Mios.Types: instance GHC.Classes.Eq SAT.Mios.Types.MiosDump
+ SAT.Mios.Types: instance GHC.Classes.Eq SAT.Mios.Types.MiosStats
+ SAT.Mios.Types: instance GHC.Classes.Eq SAT.Mios.Types.SolverException
+ SAT.Mios.Types: instance GHC.Classes.Eq SAT.Mios.Types.StatIndex
+ SAT.Mios.Types: instance GHC.Classes.Ord SAT.Mios.Types.Certificate
+ SAT.Mios.Types: instance GHC.Classes.Ord SAT.Mios.Types.DumpMode
+ SAT.Mios.Types: instance GHC.Classes.Ord SAT.Mios.Types.DumpTag
+ SAT.Mios.Types: instance GHC.Classes.Ord SAT.Mios.Types.MiosConfiguration
+ SAT.Mios.Types: instance GHC.Classes.Ord SAT.Mios.Types.MiosDump
+ SAT.Mios.Types: instance GHC.Classes.Ord SAT.Mios.Types.MiosStats
+ SAT.Mios.Types: instance GHC.Classes.Ord SAT.Mios.Types.SolverException
+ SAT.Mios.Types: instance GHC.Classes.Ord SAT.Mios.Types.StatIndex
+ SAT.Mios.Types: instance GHC.Enum.Bounded SAT.Mios.Types.DumpMode
+ SAT.Mios.Types: instance GHC.Enum.Bounded SAT.Mios.Types.DumpTag
+ SAT.Mios.Types: instance GHC.Enum.Bounded SAT.Mios.Types.SolverException
+ SAT.Mios.Types: instance GHC.Enum.Bounded SAT.Mios.Types.StatIndex
+ SAT.Mios.Types: instance GHC.Enum.Enum SAT.Mios.Types.DumpMode
+ SAT.Mios.Types: instance GHC.Enum.Enum SAT.Mios.Types.DumpTag
+ SAT.Mios.Types: instance GHC.Enum.Enum SAT.Mios.Types.SolverException
+ SAT.Mios.Types: instance GHC.Enum.Enum SAT.Mios.Types.StatIndex
+ SAT.Mios.Types: instance GHC.Read.Read SAT.Mios.Types.CNFDescription
+ SAT.Mios.Types: instance GHC.Read.Read SAT.Mios.Types.Certificate
+ SAT.Mios.Types: instance GHC.Read.Read SAT.Mios.Types.DumpMode
+ SAT.Mios.Types: instance GHC.Read.Read SAT.Mios.Types.DumpTag
+ SAT.Mios.Types: instance GHC.Read.Read SAT.Mios.Types.MiosConfiguration
+ SAT.Mios.Types: instance GHC.Read.Read SAT.Mios.Types.MiosDump
+ SAT.Mios.Types: instance GHC.Read.Read SAT.Mios.Types.MiosStats
+ SAT.Mios.Types: instance GHC.Read.Read SAT.Mios.Types.StatIndex
+ SAT.Mios.Types: instance GHC.Show.Show SAT.Mios.Types.Certificate
+ SAT.Mios.Types: instance GHC.Show.Show SAT.Mios.Types.DumpMode
+ SAT.Mios.Types: instance GHC.Show.Show SAT.Mios.Types.DumpTag
+ SAT.Mios.Types: instance GHC.Show.Show SAT.Mios.Types.MiosConfiguration
+ SAT.Mios.Types: instance GHC.Show.Show SAT.Mios.Types.MiosDump
+ SAT.Mios.Types: instance GHC.Show.Show SAT.Mios.Types.MiosStats
+ SAT.Mios.Types: instance GHC.Show.Show SAT.Mios.Types.SolverException
+ SAT.Mios.Types: instance GHC.Show.Show SAT.Mios.Types.StatIndex
+ SAT.Mios.Types: lit2lbool :: Lit -> LiftedBool
+ SAT.Mios.Types: type LiftedBool = Int
+ SAT.Mios.Types: type SolverResult = Either SolverException Certificate
+ SAT.Mios.Vec: instance SAT.Mios.Vec.SingleStorage SAT.Mios.Vec.ByteArrayDouble GHC.Types.Double
+ SAT.Mios.Vec: instance SAT.Mios.Vec.SingleStorage SAT.Mios.Vec.ByteArrayInt GHC.Types.Int
+ SAT.Mios.Vec: instance SAT.Mios.Vec.StackFamily SAT.Mios.Vec.ByteArrayInt GHC.Types.Int
+ SAT.Mios.Vec: instance SAT.Mios.Vec.VecFamily (SAT.Mios.Vec.Vec [GHC.Types.Int]) GHC.Types.Int
+ SAT.Mios.Vec: instance SAT.Mios.Vec.VecFamily SAT.Mios.Vec.ByteArrayDouble GHC.Types.Double
+ SAT.Mios.Vec: instance SAT.Mios.Vec.VecFamily SAT.Mios.Vec.ByteArrayInt GHC.Types.Int
+ SAT.Mios.Vec: realLengthOfStack :: Stack -> Int
+ SAT.Mios.Vec: sortStack :: Stack -> IO ()
- SAT.Mios: dumpAssigmentAsCNF :: FilePath -> Bool -> [Int] -> IO ()
+ SAT.Mios: dumpAssigmentAsCNF :: Maybe FilePath -> Certificate -> IO ()
- SAT.Mios: solve :: (Foldable t) => Solver -> t Lit -> IO Bool
+ SAT.Mios: solve :: (Foldable t) => Solver -> t Lit -> IO SolverResult
- SAT.Mios.Clause: Clause :: !Bool -> !Double' -> !Bool' -> !Stack -> Clause
+ SAT.Mios.Clause: Clause :: !Int' -> !Double' -> !Stack -> Clause
- SAT.Mios.ClauseManager: getKeyVector :: ClauseExtManager -> IO (UVector Int)
+ SAT.Mios.ClauseManager: getKeyVector :: ClauseExtManager -> IO (Vec [Int])
- SAT.Mios.Main: solve :: (Foldable t) => Solver -> t Lit -> IO Bool
+ SAT.Mios.Main: solve :: (Foldable t) => Solver -> t Lit -> IO SolverResult
- SAT.Mios.OptionParser: MiosConfiguration :: !Double -> MiosConfiguration
+ SAT.Mios.OptionParser: MiosConfiguration :: !Double -> !Double -> !Int -> MiosConfiguration
- SAT.Mios.OptionParser: MiosProgramOption :: Maybe String -> Maybe String -> !Double -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> MiosProgramOption
+ SAT.Mios.OptionParser: MiosProgramOption :: Maybe String -> [String] -> Maybe String -> !Double -> Double -> !Int -> !Bool -> !Bool -> Integer -> !Int -> !Bool -> !Int -> !Bool -> !Bool -> !Bool -> MiosProgramOption
- SAT.Mios.Solver: Solver :: !(Vec Int) -> !Stack -> !ClauseExtManager -> !ClauseExtManager -> !WatcherList -> !(Vec Int) -> !(Vec Int) -> !Stack -> !Stack -> !Int' -> !ClauseVector -> !(Vec Int) -> !(Vec Double) -> !VarHeap -> !MiosConfiguration -> !Int -> !Double' -> !Int' -> !Bool' -> !(Vec Int) -> !Stack -> !Stack -> !Stack -> !Stack -> !(UVector Int) -> Solver
+ SAT.Mios.Solver: Solver :: !ClauseExtManager -> !ClauseExtManager -> !WatcherList -> !(Vec Int) -> !(Vec Int) -> !Stack -> !Stack -> !Int' -> !ClauseVector -> !(Vec Int) -> !Stack -> !(Vec Double) -> !VarHeap -> !MiosConfiguration -> !Int -> !Double' -> !Double' -> !Int' -> Double' -> Int' -> Double' -> !Int' -> !(Vec Int) -> !Stack -> !Stack -> !Stack -> ClausePool -> !Stack -> !(Vec [Int]) -> !(Vec Int) -> !Int' -> !Double' -> !Double' -> !Double' -> !Double' -> !Int' -> Int' -> Solver
- SAT.Mios.Solver: [ok] :: Solver -> !Bool'
+ SAT.Mios.Solver: [ok] :: Solver -> !Int'
- SAT.Mios.Solver: [stats] :: Solver -> !(UVector Int)
+ SAT.Mios.Solver: [stats] :: Solver -> !(Vec [Int])
- SAT.Mios.Types: MiosConfiguration :: !Double -> MiosConfiguration
+ SAT.Mios.Types: MiosConfiguration :: !Double -> !Double -> !Int -> MiosConfiguration
- SAT.Mios.Types: class VarOrder o where update _ = error "update undefined" undo _ _ = error "undo undefined" select = error "select undefined"
+ SAT.Mios.Types: class VarOrder o
- SAT.Mios.Vec: class SingleStorage s t | s -> t where new' = undefined modify' = undefined
+ SAT.Mios.Vec: class SingleStorage s t | s -> t
- SAT.Mios.Vec: class SingleStorage s Int => StackFamily s t | s -> t where newStack = undefined pushTo = undefined popFrom = undefined lastOf = undefined shrinkBy = undefined
+ SAT.Mios.Vec: class SingleStorage s Int => StackFamily s t | s -> t
- SAT.Mios.Vec: class VecFamily v a | v -> a where reset = error "no default method: reset" asUVector = error "no default method: asUVector" swapBetween = error "no default method: swapBetween" modifyNth = error "no default method: modifyNth" newVec = error "no default method: newVec" setAll = error "no default method: setAll" asList = error "no default method: asList" growBy = error "no default method: growBy"
+ SAT.Mios.Vec: class VecFamily v a | v -> a
- SAT.Mios.Vec: type Double' = IOVector Double
+ SAT.Mios.Vec: type Double' = ByteArrayDouble
- SAT.Mios.Vec: type Int' = IOVector Int
+ SAT.Mios.Vec: type Int' = ByteArrayInt

Files

+ MultiConflict/utils/averagecsv.hs view
@@ -0,0 +1,13 @@+-- | Usage:+-- > mios-averagecsv < a.csv > ave.csv+module Main where++import Data.List (sort)+import SAT.Mios.Util.Stat++main :: IO ()+main = do+  putStrLn $ fst (header :: (String, MergedDump))+  d <- parseBy [(fst (header :: (String, MiosDump)), fromCSV)] <$> getContents+  mapM_ (putStrLn . toCSV) . sort =<< merge d+
+ MultiConflict/utils/dump2csv.hs view
@@ -0,0 +1,10 @@+-- | Usage:+-- > mios --dump ... | mios-dump2csv > a.csv+module Main where++import SAT.Mios.Util.Stat++main :: IO ()+main = do+  putStrLn $ fst (header :: (String, MiosDump))+  mapM_ (putStrLn . toCSV) =<< parseBy [("", fromDump)] <$> getContents
+ MultiConflict/utils/numbers.hs view
@@ -0,0 +1,119 @@+-- | Usage:+-- > mios-summary < average.csv > summary.tbl (for org-mode or github-flavored markdown)+{-# LANGUAGE ViewPatterns #-}+module Main where++import Data.List (intercalate, lookup, minimumBy, nub)+import Data.Maybe (fromMaybe)+import Data.Ord (comparing)+import Numeric (showFFloat)+import System.Console.GetOpt (ArgDescr(..), ArgOrder(..), getOpt, OptDescr(..), usageInfo)+import System.Environment (getArgs)+import SAT.Mios.Types+import SAT.Mios.Util.Stat++data Opt = Opt+  {+    threshold :: Double+  , p1 :: (Double, Double)+  , p2 :: (Double, Double)+  , p3 :: (Int, Int)+  , p4 :: (Int, Int)+  , message :: String+  , help :: Bool+  }++optDefault :: Opt+optDefault = Opt 0 (0, 10) (0, 10) (0, 10) (0, 10) "#-*-mode:org-*-" False++options ::[OptDescr (Opt -> Opt)]+options =+  [+    Option ['t'] ["threshold"]+    (ReqArg (\v c -> c { threshold = read v }) "0.0") "threshold for p1"+  , Option [] ["UF250"]+    (NoArg (\c -> c { threshold = 12109075.01 })) "threshold for UF250; 12109075.01 (7.083)"+  , Option [] ["38bits"]+    (NoArg (\c -> c { threshold = 191761341.00 })) "threshold for 38bits; 191761341.00 (8.283)"+  , Option [] ["44bits"]+    (NoArg (\c -> c { threshold = 5204447789.00 })) "threshold for 44bits; 5204447789.00 (9.716)"+  , Option ['1'] ["p1"]+    (ReqArg (\v c -> c { p1 = read v }) "\"(0,10)\"") "range of p1"+  , Option ['2'] ["p2"]+    (ReqArg (\v c -> c { p2 = read v }) "\"(0,10)\"") "range of p2"+  , Option ['3'] ["p3"]+    (ReqArg (\v c -> c { p3 = read v }) "\"(0,10)\"") "range of p3"+  , Option ['4'] ["p4"]+    (ReqArg (\v c -> c { p4 = read v }) "\"(0,10)\"") "range of p4"+  , Option ['m'] ["message"]+    (ReqArg (\v c -> c { message = undecodeNewline v }) "\"\"") "extra message embeded into output"+  , Option ['h'] ["help"]+    (NoArg (\c -> c { help = True })) "display help message"+  ]++parseOptions :: String -> [String] -> IO Opt+parseOptions mes argv =+    case getOpt Permute options argv of+      (o,  [], []) -> return $ foldl (flip id) optDefault o+      (o,   _, []) -> return $ foldl (flip id) optDefault o+      (_,   _, err) -> ioError (userError (concat err ++ usageInfo mes options))++-- | builds "MiosProgramOption" from a String+parseOptionsFromArgs :: String -> IO Opt+parseOptionsFromArgs mes = parseOptions mes =<< getArgs++undecodeNewline :: String -> String+undecodeNewline [] = []+undecodeNewline [a] = [a]+undecodeNewline ('\\' : 'n' : x) = '\n' : undecodeNewline x+undecodeNewline (a : x) = a : undecodeNewline x++showf :: Double -> String+showf x = showFFloat (Just 2) x ""++main :: IO ()+main = do+  opts <- parseOptionsFromArgs "gp-summary"+  if help opts+    then putStrLn $ usageInfo "" options+    else do putStrLn $ message opts+            putStrLn ""+            putStrLn "| p1   | good | bad |"+            putStrLn "| ---- | ---- | --- |"+            result <- pickup opts . parseBy [(fst (header :: (String, MergedDump)), fromMergedCSV)] <$> getContents+            mapM_ (putStrLn . toString) result+            let ngs = sum $ map (fst . snd) result+                nbs = sum $ map (snd . snd) result+            putStrLn $ intercalate "," [showf (fromIntegral ngs / fromIntegral (ngs + nbs)), show (ngs + nbs) ++ "/" ++ show (ngs, nbs)]++toString :: (Double, (Int, Int))  -> String+toString (p1, (ng, nb)) = "| " ++ intercalate " | " [showf p1, show ng, show nb] ++ " |"++pickup :: Opt -> [MergedDump] -> [(Double, (Int, Int))]+pickup opts l = filter notEmpty $ map gather keys+  where+    notEmpty (_, (0, 0)) = False+    notEmpty _ = True+    thr = threshold opts+    keys = nub $ map (gpParameter1 .  snd. _mergedConf) l+    gather :: Double -> (Double, (Int, Int))+    gather key = (key, (ng, length targets - ng))+      where+        targets' :: [MergedDump]+        targets' = filter ((key ==) . gpParameter1 .  snd. _mergedConf) l+        inBand :: MergedDump -> Bool+        inBand (_mergedConf -> snd -> conf) = c1 && c2 && c3 && c4+          where+            c1 = inPair (p1 opts) (gpParameter1 conf)+            c2 = inPair (p2 opts) (gpParameter2 conf)+            c3 = inPair (p3 opts) (extraParameter3 conf)+            c4 = inPair (p4 opts) (extraParameter4 conf)+            inPair :: (Num a, Ord a) => (a, a) -> a -> Bool+            inPair (b, t) x = b <= x && x <= t+        targets = filter inBand targets'+        ng = length $ filter (< thr) (map value targets)+    value :: MergedDump -> Double+    value m = case lookup PropagationS . (\(MiosStats s) -> s) . _mergedStat $ m of+      Just (Right v) -> fromIntegral v+      Just (Left v)  -> v+      Nothing        -> 10000000
+ MultiConflict/utils/pickup.hs view
@@ -0,0 +1,123 @@+-- | Usage:+-- > mios-summary < average.csv > summary.tbl (for org-mode or github-flavored markdown)+module Main where++import Data.List (intercalate, lookup, maximumBy, minimumBy, nub)+import Data.Maybe (fromMaybe)+import Data.Ord (comparing)+import Numeric (showFFloat)+import System.Console.GetOpt (ArgDescr(..), ArgOrder(..), getOpt, OptDescr(..), usageInfo)+import System.Environment (getArgs)+import SAT.Mios.Types+import SAT.Mios.Util.Stat++data Opt = Opt+  {+    message :: String+  , useLog :: Bool+  , help :: Bool+  }++optDefault :: Opt+optDefault = Opt "#-*-mode:org-*-" False False++options ::[OptDescr (Opt -> Opt)]+options =+  [+    Option ['m'] ["message"]+    (ReqArg (\v c -> c { message = undecodeNewline v }) "\"string\"") "extra message embeded into output"+  , Option ['l'] ["useLog"]+    (NoArg (\c -> c { useLog = True })) "use Logarithmic value for propagation"+  , Option ['h'] ["help"]+    (NoArg (\c -> c { help = True })) "display help message"+  ]++parseOptions :: String -> [String] -> IO Opt+parseOptions mes argv =+    case getOpt Permute options argv of+      (o,  [], []) -> return $ foldl (flip id) optDefault o+      (o,   _, []) -> return $ foldl (flip id) optDefault o+      (_,   _, err) -> ioError (userError (concat err ++ usageInfo mes options))++-- | builds "MiosProgramOption" from a String+parseOptionsFromArgs :: String -> IO Opt+parseOptionsFromArgs mes = parseOptions mes =<< getArgs++undecodeNewline :: String -> String+undecodeNewline [] = []+undecodeNewline [a] = [a]+undecodeNewline ('\\' : 'n' : x) = '\n' : undecodeNewline x+undecodeNewline (a : x) = a : undecodeNewline x++showf :: Double -> String+showf x = showFFloat (Just 2) x ""++showi :: Int -> String+showi x+  | 3 <= length s = s+  | otherwise = reverse . take 3 . (++ "   ") . reverse $ s+  where s = show x++showl :: Either Double Int -> String+showl (Left x) = showf x+showl (Right x) = showf (fromIntegral x)++main :: IO ()+main = do+  opts <- parseOptionsFromArgs "gp-summary"+  if help opts+    then putStrLn $ usageInfo "" options+    else do let parsers = [ (fst (header :: (String, MiosDump)), toMerge <$> fromCSV)+                          , (fst (header :: (String, MergedDump)), fromMergedCSV)]+            putStrLn $ message opts+            putStrLn ""+            if useLog opts+              then do putStrLn "|   n |   p1 |   p2 |  p3 |  p4 | log(P) | conflict |   learnt | backjump | re-st | rate |  extra | pr/bj |"+                      putStrLn "| --- | ---- | ---- | --- | --- | ------ | -------- | -------- | -------- | ----- | ---- |  ----- | ----- |"+              else do putStrLn "|   n |   p1 |   p2 |  p3 |  p4 | propagation | conflict |   learnt | backjump | re-st | rate |  extra | pr/bj |"+                      putStrLn "| --- | ---- | ---- | --- | --- | ----------- | -------- | -------- | -------- | ----- | ---- |  ----- | ----- |"+            d <- parseBy parsers <$> getContents+            mapM_ (putStrLn . toSummary (useLog opts)) $ pickup True d+            putStrLn ""+            mapM_ (putStrLn . toSummary (useLog opts)) $ pickup False d+            putStrLn ""++toSummary :: Bool -> MergedDump -> String+toSummary uLog (MergedDump (_, MiosConfiguration _ _ p1 p2 p3 p4) n (MiosStats l) _) =+  "| " ++ intercalate " | " [show n, m', s', showf pr] ++ " |"+  where+    m' = intercalate " | " [showf p1, showf p2, showi p3, showi p4]+    s' = intercalate " | " $ map (showl . snd) (convert uLog l) -- (tail . init $ l)+    convert :: Bool -> [DumpedValue] -> [DumpedValue]+    convert uL ks+      | uL = logOf PropagationS : map valOf [ConflictS .. ExtraS]+      | otherwise = map valOf [PropagationS .. ExtraS]+      where+        logOf :: DumpTag -> DumpedValue+        logOf key = (key, Left $ logBase 10 (val key))+        valOf key = (key, Left $ val key)+        val :: DumpTag -> Double+        val key+          | Just (Left x) <- lookup key ks = x+          | Just (Right x) <- lookup key ks = fromIntegral x+          | otherwise = 0+    pr = fromMaybe 0 $ div' <$> lookup PropagationS l <*> lookup BackjumpS l+    div' :: Either Double Int -> Either Double Int -> Double+    div' (Right a) (Right b) = fromIntegral a / fromIntegral b+    div' (Right a) (Left b)  = fromIntegral a / b+    div' (Left a) (Right b)  = a / fromIntegral b+    div' (Left a) (Left b)   = a / b++pickup :: Bool -> [MergedDump] -> [MergedDump]+pickup good l = map selectData keys+  where+    keys = nub $ map (gpParameter1 .  snd. _mergedConf) l+    selectData :: Double -> MergedDump+    selectData key+      | good      = minimumBy (comparing value) $ filter ((key ==) . gpParameter1 .  snd. _mergedConf) l+      | otherwise = maximumBy (comparing value) $ filter ((key ==) . gpParameter1 .  snd. _mergedConf) l+    value :: MergedDump -> Double+    value m = case lookup PropagationS . (\(MiosStats s) -> s) . _mergedStat $ m of+      Just (Right v) -> fromIntegral v+      Just (Left v)  -> v+      Nothing        -> 10000000
+ MultiConflict/utils/stat2csv.hs view
@@ -0,0 +1,10 @@+-- | Usage:+-- > mios --stat -X ... | mios-stat2csv > a.csv+module Main where++import SAT.Mios.Util.Stat++main :: IO ()+main = do+  putStrLn $ fst (header :: (String, MiosDump))+  mapM_ (putStrLn . toCSV) =<< parseBy [("", fromStat)] <$> getContents
+ MultiConflict/utils/summary.hs view
@@ -0,0 +1,104 @@+-- | Usage:+-- > mios-summary < average.csv > summary.tbl (for org-mode or github-flavored markdown)+module Main where++import Data.List (intercalate, lookup)+import Data.Maybe (fromMaybe)+import Numeric (showFFloat)+import System.Console.GetOpt (ArgDescr(..), ArgOrder(..), getOpt, OptDescr(..), usageInfo)+import System.Environment (getArgs)+import SAT.Mios.Types+import SAT.Mios.Util.Stat++data Opt = Opt+  {+    message :: String+  , useLog :: Bool+  , help :: Bool+  }++optDefault :: Opt+optDefault = Opt "#-*-mode:org-*-" False False++options ::[OptDescr (Opt -> Opt)]+options =+  [+    Option ['m'] ["message"]+    (ReqArg (\v c -> c { message = undecodeNewline v }) "\"string\"") "extra message embeded into output"+  , Option ['l'] ["useLog"]+    (NoArg (\c -> c { useLog = True })) "use Logarithmic value for propagation"+  , Option ['h'] ["help"]+    (NoArg (\c -> c { help = True })) "display help message"+  ]++parseOptions :: String -> [String] -> IO Opt+parseOptions mes argv =+    case getOpt Permute options argv of+      (o,  [], []) -> return $ foldl (flip id) optDefault o+      (o,   _, []) -> return $ foldl (flip id) optDefault o+      (_,   _, err) -> ioError (userError (concat err ++ usageInfo mes options))++-- | builds "MiosProgramOption" from a String+parseOptionsFromArgs :: String -> IO Opt+parseOptionsFromArgs mes = parseOptions mes =<< getArgs++undecodeNewline :: String -> String+undecodeNewline [] = []+undecodeNewline [a] = [a]+undecodeNewline ('\\' : 'n' : x) = '\n' : undecodeNewline x+undecodeNewline (a : x) = a : undecodeNewline x++showf :: Double -> String+showf x = showFFloat (Just 2) x ""++showi :: Int -> String+showi x+  | 3 <= length s = s+  | otherwise = reverse . take 3 . (++ "   ") . reverse $ s+  where s = show x++showl :: Either Double Int -> String+showl (Left x) = showf x+showl (Right x) = showf (fromIntegral x)++main :: IO ()+main = do+  opts <- parseOptionsFromArgs "gp-summary"+  if help opts+    then putStrLn $ usageInfo "" options+    else do let parsers = [ (fst (header :: (String, MiosDump)), toMerge <$> fromCSV)+                          , (fst (header :: (String, MergedDump)), fromMergedCSV)]+            putStrLn $ message opts+            putStrLn ""+            if useLog opts+              then do putStrLn "|   n |   p1 |   p2 |  p3 |  p4 | log(P) | conflict |   learnt | backjump | re-st | rate | extra | pr/bj |"+                      putStrLn "| --- | ---- | ---- | --- | --- | ------ | -------- | -------- | -------- | ----- | ---- | ----- | ----- |"+              else do putStrLn "|   n |   p1 |   p2 |  p3 |  p4 | propagation | conflict |   learnt | backjump | re-st | rate | extra | pr/bj |"+                      putStrLn "| --- | ---- | ---- | --- | --- | ----------- | -------- | -------- | -------- | ----- | ---- | ----- | ----- |"+            mapM_ (putStrLn . toSummary (useLog opts)) . parseBy parsers =<< getContents++toSummary :: Bool -> MergedDump -> String+toSummary uLog (MergedDump (_, MiosConfiguration _ _ p1 p2 p3 p4) n (MiosStats l) _) =+  "| " ++ intercalate " | " [show n, m', s', showf pr] ++ " |"+  where+    m' = intercalate " | " [showf p1, showf p2, showi p3, showi p4]+    s' = intercalate " | " $ map (showl . snd) (convert uLog l) -- (tail . init $ l)+    convert :: Bool -> [DumpedValue] -> [DumpedValue]+    convert uL ks+      | uL = logOf PropagationS : map valOf [ConflictS .. ExtraS]+      | otherwise = map valOf [PropagationS .. ExtraS]+      where+        logOf :: DumpTag -> DumpedValue+        logOf key = (key, Left $ logBase 10 (val key))+        valOf key = (key, Left $ val key)+        val :: DumpTag -> Double+        val key+          | Just (Left x) <- lookup key ks = x+          | Just (Right x) <- lookup key ks = fromIntegral x+          | otherwise = 0+    pr = fromMaybe 0 $ div' <$> lookup PropagationS l <*> lookup BackjumpS l+    div' :: Either Double Int -> Either Double Int -> Double+    div' (Right a) (Right b) = fromIntegral a / fromIntegral b+    div' (Right a) (Left b)  = fromIntegral a / b+    div' (Left a) (Right b)  = a / fromIntegral b+    div' (Left a) (Left b)   = a / b
− SAT/Mios.hs
@@ -1,293 +0,0 @@-{-# LANGUAGE ViewPatterns #-}-{-# LANGUAGE Safe #-}---- | Minisat-based Implementation and Optimization Study on SAT solver-module SAT.Mios-       (-         -- * Interface to the core of solver-         versionId-       , CNFDescription (..)-       , module SAT.Mios.OptionParser-       , runSolver-       , solveSAT-       , solveSATWithConfiguration-       , solve-       , getModel-         -- * Assignment Validator-       , validateAssignment-       , validate-         -- * For standalone programs-       , executeSolverOn-       , executeSolver-       , executeValidatorOn-       , executeValidator-         -- * File IO-       , dumpAssigmentAsCNF-       )-       where--import Control.Monad ((<=<), unless, void, when)-import Data.Char-import qualified Data.ByteString.Char8 as B-import Data.List-import Numeric (showFFloat)-import System.CPUTime-import System.Exit-import System.IO--import SAT.Mios.Types-import SAT.Mios.Solver-import SAT.Mios.Main-import SAT.Mios.OptionParser-import SAT.Mios.Validator---- | version name-versionId :: String-versionId = "mios 1.4.0 -- https://github.com/shnarazk/mios"--reportElapsedTime :: Bool -> String -> Integer -> IO Integer-reportElapsedTime False _ _ = return 0-reportElapsedTime _ _ 0 = getCPUTime-reportElapsedTime _ mes t = do-  now <- getCPUTime-  let toSecond = 1000000000000 :: Double-  hPutStr stderr mes-  hPutStrLn stderr $ showFFloat (Just 3) ((fromIntegral (now - t)) / toSecond) " sec"-  return now---- | executes a solver on the given CNF file.--- This is the simplest entry to standalone programs; not for Haskell programs.-executeSolverOn :: FilePath -> IO ()-executeSolverOn path = executeSolver (miosDefaultOption { _targetFile = Just path })---- | executes a solver on the given 'arg :: MiosConfiguration'.--- This is another entry point for standalone programs.-executeSolver :: MiosProgramOption -> IO ()-executeSolver opts@(_targetFile -> target@(Just cnfFile)) = do-  t0 <- reportElapsedTime (_confTimeProbe opts) "" 0-  (desc, cls) <- parseHeader target <$> B.readFile cnfFile-  when (_numberOfVariables desc == 0) $ error $ "couldn't load " ++ show cnfFile-  s <- newSolver (toMiosConf opts) desc-  parseClauses s desc cls-  t1 <- reportElapsedTime (_confTimeProbe opts) ("## [" ++ showPath cnfFile ++ "] Parse: ") t0-  when (_confVerbose opts) $ do-    nc <- nClauses s-    hPutStrLn stderr $ cnfFile ++ " was loaded: #v = " ++ show (nVars s, _numberOfVariables desc) ++ " #c = " ++ show (nc, _numberOfClauses desc)-  res <- simplifyDB s-  -- when (_confVerbose opts) $ hPutStrLn stderr $ "`simplifyDB`: " ++ show res-  result <- if res then solve s [] else return False-  case result of-    True  | _confNoAnswer opts -> when (_confVerbose opts) $ hPutStrLn stderr "SATISFIABLE"-    False | _confNoAnswer opts -> when (_confVerbose opts) $ hPutStrLn stderr "UNSATISFIABLE"-    True  -> print =<< getModel s-    False -> do          -- contradiction-      -- FIXMEin future-      when (_confVerbose opts) $ hPutStrLn stderr "UNSAT"-      -- print =<< map lit2int <$> asList (conflict s)-      putStrLn "[]"-  case _outputFile opts of-    Just fname -> dumpAssigmentAsCNF fname result =<< getModel s-    Nothing -> return ()-  t2 <- reportElapsedTime (_confTimeProbe opts) ("## [" ++ showPath cnfFile ++ "] Solve: ") t1-  when (result && _confCheckAnswer opts) $ do-    asg <- getModel s-    s' <- newSolver (toMiosConf opts) desc-    parseClauses s' desc cls-    good <- validate s' asg-    if _confVerbose opts-      then hPutStrLn stderr $ if good then "A vaild answer" else "Internal error: mios returns a wrong answer"-      else unless good $ hPutStrLn stderr "Internal error: mios returns a wrong answer"-    void $ reportElapsedTime (_confTimeProbe opts) ("## [" ++ showPath cnfFile ++ "] Validate: ") t2-  void $ reportElapsedTime (_confTimeProbe opts) ("## [" ++ showPath cnfFile ++ "] Total: ") t0-  when (_confStatProbe opts) $ do-    hPutStr stderr $ "## [" ++ showPath cnfFile ++ "] "-    hPutStrLn stderr . intercalate ", " . map (\(k, v) -> show k ++ ": " ++ show v) =<< getStats s--executeSolver _ = return ()---- | new top-level interface that returns:------ * conflicting literal set :: Left [Int]--- * satisfiable assignment :: Right [Int]----runSolver :: Traversable t => MiosConfiguration -> CNFDescription -> t [Int] -> IO (Either [Int] [Int])-runSolver m d c = do-  s <- newSolver m d-  mapM_ ((s `addClause`) <=< (newStackFromList . map int2lit)) c-  noConf <- simplifyDB s-  if noConf-    then do-        x <- solve s []-        if x-            then Right <$> getModel s-            else Left .  map lit2int <$> asList (conflicts s)-    else return $ Left []---- | The easiest interface for Haskell programs.--- This returns the result @::[[Int]]@ for a given @(CNFDescription, [[Int]])@.--- The first argument @target@ can be build by @Just target <- cnfFromFile targetfile@.--- The second part of the first argument is a list of vector, which 0th element is the number of its real elements.-solveSAT :: Traversable m => CNFDescription -> m [Int] -> IO [Int]-solveSAT = solveSATWithConfiguration defaultConfiguration---- | solves the problem (2rd arg) under the configuration (1st arg).--- and returns an assignment as list of literals :: Int.-solveSATWithConfiguration :: Traversable m => MiosConfiguration -> CNFDescription -> m [Int] -> IO [Int]-solveSATWithConfiguration conf desc cls = do-  s <- newSolver conf desc-  -- mapM_ (const (newVar s)) [0 .. _numberOfVariables desc - 1]-  mapM_ ((s `addClause`) <=< (newStackFromList . map int2lit)) cls-  noConf <- simplifyDB s-  if noConf-    then do-        result <- solve s []-        if result-            then getModel s-            else return []-    else return []---- | validates a given assignment from STDIN for the CNF file (2nd arg).--- this is the entry point for standalone programs.-executeValidatorOn :: FilePath -> IO ()-executeValidatorOn path = executeValidator (miosDefaultOption { _targetFile = Just path })---- | validates a given assignment for the problem (2nd arg).--- This is another entry point for standalone programs; see app/mios.hs.-executeValidator :: MiosProgramOption -> IO ()-executeValidator opts@(_targetFile -> target@(Just cnfFile)) = do-  (desc, cls) <- parseHeader target <$> B.readFile cnfFile-  when (_numberOfVariables desc == 0) . error $ "couldn't load " ++ show cnfFile-  s <- newSolver (toMiosConf opts) desc-  parseClauses s desc cls-  when (_confVerbose opts) $-    hPutStrLn stderr $ cnfFile ++ " was loaded: #v = " ++ show (_numberOfVariables desc) ++ " #c = " ++ show (_numberOfClauses desc)-  when (_confVerbose opts) $ do-    nc <- nClauses s-    nl <- nLearnts s-    hPutStrLn stderr $ "(nv, nc, nl) = " ++ show (nVars s, nc, nl)-  asg <- read <$> getContents-  unless (_confNoAnswer opts) $ print asg-  result <- s `validate` (asg :: [Int])-  if result-    then putStrLn ("It's a valid assignment for " ++ cnfFile ++ ".") >> exitSuccess-    else putStrLn ("It's an invalid assignment for " ++ cnfFile ++ ".") >> exitFailure--executeValidator _  = return ()---- | returns True if a given assignment (2nd arg) satisfies the problem (1st arg).--- if you want to check the @answer@ which a @slover@ returned, run @solver `validate` answer@,--- where 'validate' @ :: Traversable t => Solver -> t Lit -> IO Bool@.-validateAssignment :: (Traversable m, Traversable n) => CNFDescription -> m [Int] -> n Int -> IO Bool-validateAssignment desc cls asg = do-  s <- newSolver defaultConfiguration desc-  mapM_ ((s `addClause`) <=< (newStackFromList . map int2lit)) cls-  s `validate` asg---- | dumps an assigment to file.--- 2nd arg is------ * @True@ if the assigment is satisfiable assigment------ * @False@ if not------ >>> do y <- solve s ... ; dumpAssigmentAsCNF "result.cnf" y <$> model s----dumpAssigmentAsCNF :: FilePath -> Bool -> [Int] -> IO ()-dumpAssigmentAsCNF fname False _ = do-  withFile fname WriteMode $ \h -> hPutStrLn h "UNSAT"--dumpAssigmentAsCNF fname True l = do-  withFile fname WriteMode $ \h -> do hPutStrLn h "SAT"; hPutStrLn h . unwords $ map show l------------------------------------------------------------------------------------- DIMACS CNF Reader-----------------------------------------------------------------------------------parseHeader :: Maybe FilePath -> B.ByteString -> (CNFDescription, B.ByteString)-parseHeader target bs = if B.head bs == 'p' then (parseP l, B.tail bs') else parseHeader target (B.tail bs')-  where-    (l, bs') = B.span ('\n' /=) bs-    -- format: p cnf n m, length "p cnf" == 5-    parseP line = case B.readInt $ B.dropWhile (`elem` " \t") (B.drop 5 line) of-      Just (x, second) -> case B.readInt (B.dropWhile (`elem` " \t") second) of-        Just (y, _) -> CNFDescription x y target-        _ -> CNFDescription 0 0 target-      _ -> CNFDescription 0 0 target--parseClauses :: Solver -> CNFDescription -> B.ByteString -> IO ()-parseClauses s (CNFDescription nv nc _) bs = do-  let maxLit = int2lit $ negate nv-  buffer <- newVec (maxLit + 1) 0-  polvec <- newVec (maxLit + 1) 0-  let-    loop :: Int -> B.ByteString -> IO ()-    loop ((< nc) -> False) _ = return ()-    loop i b = loop (i + 1) =<< readClause s buffer polvec b-  loop 0 bs-  -- static polarity-  let-    asg = assigns s-    checkPolarity :: Int -> IO ()-    checkPolarity ((< nv) -> False) = return ()-    checkPolarity v = do-      p <- getNth polvec $ var2lit v True-      n <- getNth polvec $ var2lit v False-      when (p == lFalse || n == lFalse) $ setNth asg v p-      checkPolarity $ v + 1-  checkPolarity 1--skipWhitespace :: B.ByteString -> B.ByteString-skipWhitespace s-  | elem c " \t\n" = skipWhitespace $ B.tail s-  | otherwise = s-    where-      c = B.head s---- | skip comment lines--- __Pre-condition:__ we are on the benngining of a line-skipComments :: B.ByteString -> B.ByteString-skipComments s-  | c == 'c' = skipComments . B.tail . B.dropWhile (/= '\n') $ s-  | otherwise = s-  where-    c = B.head s--parseInt :: B.ByteString -> (Int, B.ByteString)-parseInt st = do-  let-    zero = ord '0'-    loop :: B.ByteString -> Int -> (Int, B.ByteString)-    loop s val = case B.head s of-      c | '0' <= c && c <= '9'  -> loop (B.tail s) (val * 10 + ord c - zero)-      _ -> (val, B.tail s)-  case B.head st of-    '-' -> let (k, x) = loop (B.tail st) 0 in (negate k, x)-    '+' -> loop st (0 :: Int)-    c | '0' <= c && c <= '9'  -> loop st 0-    _ -> error "PARSE ERROR! Unexpected char"--readClause :: Solver -> Stack -> Vec Int -> B.ByteString -> IO B.ByteString-readClause s buffer bvec stream = do-  let-    loop :: Int -> B.ByteString -> IO B.ByteString-    loop i b = do-      let (k, b') = parseInt $ skipWhitespace b-      if k == 0-        then do-            -- putStrLn . ("clause: " ++) . show . map lit2int =<< asList stack-            setNth buffer 0 $ i - 1-            void $ addClause s buffer-            return b'-        else do-            let l = int2lit k-            setNth buffer i l-            setNth bvec l lTrue-            loop (i + 1) b'-  loop 1 . skipComments . skipWhitespace $ stream--showPath :: FilePath -> String-showPath str = replicate (len - length basename) ' ' ++ if elem '/' str then basename else basename'-  where-    len = 50-    basename = reverse . takeWhile (/= '/') . reverse $ str-    basename' = take len str
− SAT/Mios/Clause.hs
@@ -1,145 +0,0 @@-{-# LANGUAGE-    BangPatterns-  , FlexibleInstances-  , MagicHash-  , MultiParamTypeClasses-  , RecordWildCards-  , ViewPatterns-  #-}-{-# LANGUAGE Trustworthy #-}---- | Clause, supporting pointer-based equality-module SAT.Mios.Clause-       (-         Clause (..)---       , isLit---       , getLit-       , 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-              {-                learnt     :: !Bool     -- ^ whether this is a learnt 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.-  {-# SPECIALIZE INLINE asUVector :: Clause -> UVector Int #-}-  asUVector = asUVector . lits-  asList NullClause = return []-  asList Clause{..} = take <$> get' lits <*> 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---- returns True if it is a 'BinaryClause'.--- FIXME: this might be discarded in minisat 2.2--- isLit :: Clause -> Bool--- isLit (BinaryClause _) = True--- isLit _ = False---- returns the literal in a BinaryClause.--- FIXME: this might be discarded in minisat 2.2--- getLit :: Clause -> Lit--- getLit (BinaryClause x) = x---- 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 l <$> {- new' 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-{--  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
− SAT/Mios/ClauseManager.hs
@@ -1,234 +0,0 @@-{-# LANGUAGE-    BangPatterns-  , FlexibleInstances-  , MultiParamTypeClasses-  , RecordWildCards-  , ViewPatterns-  #-}-{-# LANGUAGE Trustworthy #-}---- | A shrinkable vector of 'C.Clause'-module SAT.Mios.ClauseManager-       (-         -- * higher level interface for ClauseVector-         ClauseManager (..)-         -- * Manager with an extra Int (used as sort key or blocking literal)-       , ClauseExtManager-       , pushClauseWithKey-       , getKeyVector-       , markClause---       , purifyManager-         -- * 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 ClauseExtManager = ClauseExtManager-  {-    _nActives     :: !Int'                         -- number of active clause-  , _purged       :: !Bool'                        -- whether it needs gc-  , _clauseVector :: IORef.IORef C.ClauseVector    -- clause list-  , _keyVector    :: IORef.IORef (UVector Int)     -- Int list-  }---- | 'ClauseExtManager' is a 'SingleStorage` on the numeber 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 +)---- | '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-      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 (UVector 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-newWatcherList :: Int -> Int -> IO WatcherList-newWatcherList n m = V.fromList <$> mapM (\_ -> newManager m) [0 .. int2lit (negate n) + 1]---- | 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]
− SAT/Mios/Main.hs
@@ -1,817 +0,0 @@-{-# LANGUAGE-    BangPatterns-  , RecordWildCards-  , ScopedTypeVariables-  , ViewPatterns-  #-}-{-# LANGUAGE Safe #-}---- | This is a part of MIOS; main heuristics.-module SAT.Mios.Main-       (-         simplifyDB-       , solve-       )-        where--import Control.Monad (unless, void, when)-import Data.Bits-import Data.Foldable (foldrM)-import SAT.Mios.Types-import SAT.Mios.Clause-import SAT.Mios.ClauseManager-import SAT.Mios.Solver---- | returns a rank of 'Clause'. Smaller value is better.-{-# INLINE rankOf #-}-rankOf :: Clause -> IO Int-rankOf = get'---- | #114: __RemoveWatch__-{-# INLINABLE removeWatch #-}-removeWatch :: Solver -> Clause -> IO ()-removeWatch (watches -> w) c = do-  let lvec = asUVector c-  l1 <- negateLit <$> getNth lvec 0-  markClause (getNthWatcher w l1) c-  l2 <- negateLit <$> getNth lvec 1-  markClause (getNthWatcher w l2) c------------------------------------------------------------------------------------- Operations on 'Clause'------------------------------------------------------------------------------------- | __Fig. 8. (p.12)__ creates a new LEARNT clause and adds it to watcher lists.--- This is a strippped-down version of 'newClause' in Solver.-{-# INLINABLE newLearntClause #-}-newLearntClause :: Solver -> Stack -> IO ()-newLearntClause s@Solver{..} ps = do-  good <- get' ok-  when good $ do-    -- ps is a 'SizedVectorInt'; ps[0] is the number of active literals-    -- Since this solver must generate only healthy learnt clauses, we need not to run misc check in 'newClause'-    k <- get' ps-    case k of-     1 -> do-       l <- getNth ps 1-       unsafeEnqueue s l NullClause-     _ -> do-       -- allocate clause:-       c <- newClauseFromStack True ps-       let vec = asUVector c-       -- Pick a second literal to watch:-       let-         findMax :: Int -> Int -> Int -> IO Int-         findMax ((< k) -> False) j _ = return j-         findMax i j val = do-           v <- lit2var <$> getNth vec i-           a <- getNth assigns v-           b <- getNth level v-           if (a /= lBottom) && (val < b)-             then findMax (i + 1) i b-             else findMax (i + 1) j val-       swapBetween vec 1 =<< findMax 0 0 0 -- Let @max_i@ be the index of the literal with highest decision level-       -- Bump, enqueue, store clause:-       set' (activity c) . fromIntegral =<< decisionLevel s -- newly learnt clauses should be considered active-       -- Add clause to all managers-       pushTo learnts c-       l <- getNth vec 0-       pushClauseWithKey (getNthWatcher watches (negateLit l)) c 0-       l1 <- negateLit <$> getNth vec 1-       pushClauseWithKey (getNthWatcher watches l1) c 0-       -- update the solver state by @l@-       unsafeEnqueue s l c-       -- Since unsafeEnqueue updates the 1st literal's level, setLBD should be called after unsafeEnqueue-       -- setRank s c-       set' (protected c) True---- | __Simplify.__ At the top-level, a constraint may be given the opportunity to--- simplify its representation (returns @False@) or state that the constraint is--- satisfied under the current assignment and can be removed (returns @True@).--- A constraint must /not/ be simplifiable to produce unit information or to be--- conflicting; in that case the propagation has not been correctly defined.------ MIOS NOTE: the original doesn't update watchers; only checks its satisfiabiliy.-{-# INLINABLE simplify #-}-simplify :: Solver -> Clause -> IO Bool-simplify s c = do-  n <- get' c-  let-    lvec = asUVector c-    loop ::Int -> IO Bool-    loop ((< n) -> False) = return False-    loop i = do-      v <- valueLit s =<< getNth lvec i-      if v == 1 then return True else loop (i + 1)-  loop 0------------------------------------------------------------------------------------- MIOS NOTE on Minor methods:------ * no (meaningful) 'newVar' in mios--- * 'assume' is defined in 'Solver'--- * `cancelUntil` is defined in 'Solver'------------------------------------------------------------------------------------- Major methods---- | M114: __Fig. 10. (p.15)__------ analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel :: int&) -> [void]------ __Description:_----   Analzye confilct and produce a reason clause.------ __Pre-conditions:__---   * 'out_learnt' is assumed to be cleared.---   * Corrent decision level must be greater than root level.------ __Post-conditions:__---   * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'.---   * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision level of the---     rest of literals. There may be others from the same level though.------ @analyze@ is invoked from @search@-{-# INLINABLE analyze #-}-analyze :: Solver -> Clause -> IO Int-analyze s@Solver{..} confl = do-  -- litvec-  reset litsLearnt-  pushTo litsLearnt 0 -- reserve the first place for the unassigned literal-  dl <- decisionLevel s-  let-    litsVec = asUVector litsLearnt-    trailVec = asUVector trail-    loopOnClauseChain :: Clause -> Lit -> Int -> Int -> Int -> IO Int-    loopOnClauseChain c p ti bl pathC = do -- p : literal, ti = trail index, bl = backtrack level-      when (learnt c) $ do-        claBumpActivity s c-{--        -- update LBD like #Glucose4.0-        d <- get' (lbd c)-        when (2 < d) $ do-          nblevels <- lbdOf s c-          when (nblevels + 1 < d) $ do -- improve the LBD-            when (d <= 30) $ set' (protected c) True -- 30 is `lbLBDFrozenClause`-            -- seems to be interesting: keep it fro the next round-            set' (lbd c) nblevels    -- Update it--}-      sc <- get' c-      let-        lvec = asUVector c-        loopOnLiterals :: Int -> Int -> Int -> IO (Int, Int)-        loopOnLiterals ((< sc) -> False) b pc = return (b, pc) -- b = btLevel, pc = pathC-        loopOnLiterals j b pc = do-          (q :: Lit) <- getNth lvec j-          let v = lit2var q-          sn <- getNth an'seen v-          l <- getNth level v-          if sn == 0 && 0 < l-            then do-                varBumpActivity s v-                setNth an'seen v 1-                if dl <= l      -- cancelUntil doesn't clear level of cancelled literals-                  then do-                      -- glucose heuristics-                      r <- getNth reason v-                      when (r /= NullClause && learnt r) $ pushTo an'lastDL q-                      -- end of glucose heuristics-                      loopOnLiterals (j + 1) b (pc + 1)-                  else pushTo litsLearnt q >> loopOnLiterals (j + 1) (max b l) pc-            else loopOnLiterals (j + 1) b pc-      (b', pathC') <- loopOnLiterals (if p == bottomLit then 0 else 1) bl pathC-      let-        -- select next clause to look at-        nextPickedUpLit :: Int -> IO Int-        nextPickedUpLit i = do-          x <- getNth an'seen . lit2var =<< getNth trailVec i-          if x == 0 then nextPickedUpLit $ i - 1 else return i-      ti' <- nextPickedUpLit ti-      nextP <- getNth trailVec ti'-      let nextV = lit2var nextP-      confl' <- getNth reason nextV-      setNth an'seen nextV 0-      if 1 < pathC'-        then loopOnClauseChain confl' nextP (ti' - 1) b' (pathC' - 1)-        else setNth litsVec 0 (negateLit nextP) >> return b'-  ti <- subtract 1 <$> get' trail-  levelToReturn <- loopOnClauseChain confl bottomLit ti 0 0-  -- Simplify phase (implemented only @expensive_ccmin@ path)-  n <- get' litsLearnt-  reset an'stack           -- analyze_stack.clear();-  reset an'toClear         -- out_learnt.copyTo(analyze_toclear);-  pushTo an'toClear =<< getNth litsVec 0-  let-    merger :: Int -> Int -> IO Int-    merger ((< n) -> False) b = return b-    merger i b = do-      l <- getNth litsVec i-      pushTo an'toClear l-      -- restrict the search depth (range) to 32-      merger (i + 1) . setBit b . (31 .&.) =<< getNth level (lit2var l)-  levels <- merger 1 0-  let-    loopOnLits :: Int -> Int -> IO ()-    loopOnLits ((< n) -> False) n' = shrinkBy litsLearnt $ n - n'-    loopOnLits i j = do-      l <- getNth litsVec i-      c1 <- (NullClause ==) <$> getNth reason (lit2var l)-      if c1-        then setNth litsVec j l >> loopOnLits (i + 1) (j + 1)-        else do-           c2 <- not <$> analyzeRemovable s l levels-           if c2-             then setNth litsVec j l >> loopOnLits (i + 1) (j + 1)-             else loopOnLits (i + 1) j-  loopOnLits 1 1                -- the first literal is specail-  -- glucose heuristics-  nld <- get' an'lastDL-  r <- get' litsLearnt -- this is not the right value-  let-    vec = asUVector an'lastDL-    loopOnLastDL :: Int -> IO ()-    loopOnLastDL ((< nld) -> False) = return ()-    loopOnLastDL i = do-      v <- lit2var <$> getNth vec i-      r' <- rankOf =<< getNth reason v-      when (r < r') $ varBumpActivity s v-      loopOnLastDL $ i + 1-  loopOnLastDL 0-  reset an'lastDL-  -- Clear seen-  k <- get' an'toClear-  let-    vec' = asUVector an'toClear-    cleaner :: Int -> IO ()-    cleaner ((< k) -> False) = return ()-    cleaner i = do-      v <- lit2var <$> getNth vec' i-      setNth an'seen v 0-      cleaner $ i + 1-  cleaner 0-  return levelToReturn---- | #M114--- Check if 'p' can be removed, 'abstract_levels' is used to abort early if the algorithm is--- visiting literals at levels that cannot be removed later.------ Implementation memo:------ *  @an'toClear@ is initialized by @ps@ in @analyze@ (a copy of 'learnt').---   This is used only in this function and @analyze@.----{-# INLINABLE analyzeRemovable #-}-analyzeRemovable :: Solver -> Lit -> Int -> IO Bool-analyzeRemovable Solver{..} p minLevel = do-  -- assert (reason[var(p)]!= NullCaulse);-  reset an'stack      -- analyze_stack.clear()-  pushTo an'stack p   -- analyze_stack.push(p);-  top <- get' an'toClear-  let-    loopOnStack :: IO Bool-    loopOnStack = do-      k <- get' an'stack  -- int top = analyze_toclear.size();-      if 0 == k-        then return True-        else do -- assert(reason[var(analyze_stack.last())] != GClause_NULL);-            sl <- lastOf an'stack-            popFrom an'stack             -- analyze_stack.pop();-            c <- getNth reason (lit2var sl) -- getRoot sl-            nl <- get' c-            let-              cvec = asUVector c-              loopOnLit :: Int -> IO Bool -- loopOnLit (int i = 1; i < c.size(); i++){-              loopOnLit ((< nl) -> False) = loopOnStack-              loopOnLit i = do-                p' <- getNth cvec i              -- valid range is [0 .. nl - 1]-                let v' = lit2var p'-                l' <- getNth level v'-                c1 <- (1 /=) <$> getNth an'seen v'-                if c1 && (0 /= l')   -- if (!analyze_seen[var(p)] && level[var(p)] != 0){-                  then do-                      c3 <- (NullClause /=) <$> getNth reason v'-                      if c3 && testBit minLevel (l' .&. 31) -- if (reason[var(p)] != GClause_NULL && ((1 << (level[var(p)] & 31)) & min_level) != 0){-                        then do-                            setNth an'seen v' 1        -- analyze_seen[var(p)] = 1;-                            pushTo an'stack p'    -- analyze_stack.push(p);-                            pushTo an'toClear p'  -- analyze_toclear.push(p);-                            loopOnLit $ i + 1-                        else do-                            -- loopOnLit (int j = top; j < analyze_toclear.size(); j++) analyze_seen[var(analyze_toclear[j])] = 0;-                            top' <- get' an'toClear-                            let-                              vec = asUVector an'toClear-                              clearAll :: Int -> IO ()-                              clearAll ((< top') -> False) = return ()-                              clearAll j = do x <- getNth vec j; setNth an'seen (lit2var x) 0; clearAll (j + 1)-                            clearAll top-                            -- analyze_toclear.shrink(analyze_toclear.size() - top); note: shrink n == repeat n pop-                            shrinkBy an'toClear $ top' - top-                            return False-                  else loopOnLit $ i + 1-            loopOnLit 1-  loopOnStack---- | #114--- analyzeFinal : (confl : Clause *) (skip_first : boot) -> [void]------ __Description:__---   Specialized analysis proceduce to express the final conflict in terms of assumptions.---   'root_level' is allowed to point beyond end of trace (useful if called after conflict while---   making assumptions). If 'skip_first' is TRUE, the first literal of 'confl' is ignored (needed---   if conflict arose before search even started).----{-# INLINABLE analyzeFinal #-}-analyzeFinal :: Solver -> Clause -> Bool -> IO ()-analyzeFinal Solver{..} confl skipFirst = do-  reset conflicts-  rl <- get' rootLevel-  unless (rl == 0) $ do-    n <- get' confl-    let-      lvec = asUVector confl-      loopOnConfl :: Int -> IO ()-      loopOnConfl ((< n) -> False) = return ()-      loopOnConfl i = do-        (x :: Var) <- lit2var <$> getNth lvec i-        lvl <- getNth level x-        when (0 < lvl) $ setNth an'seen x 1-        loopOnConfl $ i + 1-    loopOnConfl $ if skipFirst then 1 else 0-    tls <- get' trailLim-    trs <- get' trail-    tlz <- getNth (asUVector trailLim) 0-    let-      trailVec = asUVector trail-      loopOnTrail :: Int -> IO ()-      loopOnTrail ((tlz <=) -> False) = return ()-      loopOnTrail i = do-        (l :: Lit) <- getNth trailVec i-        let (x :: Var) = lit2var l-        saw <- getNth an'seen x-        when (saw == 1) $ do-          (r :: Clause) <- getNth reason x-          if r == NullClause-            then pushTo conflicts (negateLit l)-            else do-                k <- get' r-                let-                  cvec = asUVector r-                  loopOnLits :: Int -> IO ()-                  loopOnLits ((< k) -> False) = return ()-                  loopOnLits j = do-                    (v :: Var) <- lit2var <$> getNth cvec j-                    lv <- getNth level v-                    when (0 < lv) $ setNth an'seen v 1-                    loopOnLits $ i + 1-                loopOnLits 1-        setNth an'seen x 0-        loopOnTrail $ i - 1-    loopOnTrail =<< if tls <= rl then return (trs - 1) else getNth (asUVector trailLim) rl---- | M114:--- propagate : [void] -> [Clause+]------ __Description:__---   Porpagates all enqueued facts. If a conflict arises, the conflicting clause is returned.---   otherwise CRef_undef.------ __Post-conditions:__---   * the propagation queue is empty, even if there was a conflict.------ memo: @propagate@ is invoked by @search@,`simpleDB` and `solve`-{-# INLINABLE propagate #-}-propagate :: Solver -> IO Clause-propagate s@Solver{..} = do-  -- myVal <- getNth stats (fromEnum NumOfBackjump)-  let-{--    myVal = 0-    bumpAllVar :: IO ()         -- not in use-    bumpAllVar = do-      let-        loop :: Int -> IO ()-        loop ((<= nVars) -> False) = return ()-        loop i = do-          c <- getNth pr'seen i-          when (c == myVal) $ varBumpActivity s i-          loop $ i + 1-      loop 1--}-    trailVec = asUVector trail-    while :: Clause -> Bool -> IO Clause-    while confl False = {- bumpAllVar >> -} return confl-    while confl True = do-      (p :: Lit) <- getNth trailVec =<< get' qHead-      modify' qHead (+ 1)-      let (ws :: ClauseExtManager) = getNthWatcher watches p-      end <- get' ws-      cvec <- getClauseVector ws-      bvec <- getKeyVector ws---      rc <- getNth reason $ lit2var p---      byGlue <- if (rc /= NullClause) && learnt rc then (== 2) <$> get' (lbd rc) else return False-      let-{--        checkAllLiteralsIn :: Clause -> IO () -- not in use-        checkAllLiteralsIn c = do-          nc <- sizeOfClause c-          let-            vec = asuVector c-            loop :: Int -> IO ()-            loop((< nc) -> False) = return ()-            loop i = do-              (v :: Var) <- lit2var <$> getNth vec i-              setNth pr'seen v myVal-              loop $ i + 1-          loop 0--}-        forClause :: Clause -> Int -> Int -> IO Clause-        forClause confl i@((< end) -> False) j = do-          shrinkBy ws (i - j)-          while confl =<< ((<) <$> get' qHead <*> get' trail)-        forClause confl i j = do-          (l :: Lit) <- getNth bvec i-          bv <- if l == 0 then return lFalse else valueLit s l-          if bv == lTrue-            then do-                 unless (i == j) $ do -- NOTE: if i == j, the path doesn't require accesses to cvec!-                   (c :: Clause) <- getNth cvec i-                   setNth cvec j c-                   setNth bvec j l-                 forClause confl (i + 1) (j + 1)-            else do-                -- checkAllLiteralsIn c-                (c :: Clause) <- getNth cvec i-                let-                  lits = asUVector c-                  falseLit = negateLit p-                -- Make sure the false literal is data[1]-                ((falseLit ==) <$> getNth lits 0) >>= (`when` swapBetween lits 0 1)-                -- if 0th watch is true, then clause is already satisfied.-                (first :: Lit) <- getNth lits 0-                val <- valueLit s first-                if val == lTrue-                  then setNth cvec j c >> setNth bvec j first >> forClause confl (i + 1) (j + 1)-                  else do-                      -- Look for new watch-                      cs <- get' c-                      let-                        forLit :: Int -> IO Clause-                        forLit ((< cs) -> False) = do-                          -- Did not find watch; clause is unit under assignment:-                          setNth cvec j c-                          setNth bvec j 0-                          result <- enqueue s first c-                          if not result-                            then do-                                ((== 0) <$> decisionLevel s) >>= (`when` set' ok False)-                                -- #BBCP-                                set' qHead =<< get' trail-                                -- Copy the remaining watches:-                                let-                                  copy i'@((< end) -> False) j' = forClause c i' j'-                                  copy i' j' = do-                                    setNth cvec j' =<< getNth cvec i'-                                    setNth bvec j' =<< getNth bvec i'-                                    copy (i' + 1) (j' + 1)-                                copy (i + 1) (j + 1)-                            else forClause confl (i + 1) (j + 1)-                        forLit k = do-                          (l :: Lit) <- getNth lits k-                          lv <- valueLit s l-                          if lv /= lFalse-                            then do-                                swapBetween lits 1 k-                                pushClauseWithKey (getNthWatcher watches (negateLit l)) c l-                                forClause confl (i + 1) j-                            else forLit $ k + 1-                      forLit 2-      forClause confl 0 0-  while NullClause =<< ((<) <$> get' qHead <*> get' trail)---- | #M22--- reduceDB: () -> [void]------ __Description:__---   Remove half of the learnt clauses, minus the clauses locked by the current assigmnent. Locked---   clauses are clauses that are reason to some assignment. Binary clauses are never removed.-{-# INLINABLE reduceDB #-}-reduceDB :: Solver -> IO ()-reduceDB s@Solver{..} = do-  n <- nLearnts s-  vec <- getClauseVector learnts-  let-    loop :: Int -> IO ()-    loop ((< n) -> False) = return ()-    loop i = (removeWatch s =<< getNth vec i) >> loop (i + 1)-  k <- sortClauses s learnts (div n 2) -- k is the number of clauses not to be purged-  loop k                               -- CAVEAT: `vec` is a zero-based vector-  reset watches-  shrinkBy learnts (n - k)---- | (Good to Bad) Quick sort the key vector based on their activities and returns number of privileged clauses.--- this function uses the same metrix as reduceDB_lt in glucose 4.0:--- 1. binary clause--- 2. smaller rank--- 3. larger activity defined in MiniSat--- , where smaller value is better.------ they are coded into an Int as the following layout:------ * 14 bit: LBD or 0 for preserved clauses--- * 19 bit: converted activity--- * remain: clauseVector index----(rankWidth :: Int, activityWidth :: Int, indexWidth :: Int) = (l, a, w - (l + a + 1))-  where-    w = finiteBitSize (0:: Int)-    (l, a) = case () of-      _ | 64 <= w -> (8, 25)   -- 30 bit =>   1G clauses-      _ | 60 <= w -> (8, 24)   -- 26 bit =>  64M clauses-      _ | 32 <= w -> (6,  7)   -- 18 bit => 256K clauses-      _ | 29 <= w -> (6,  5)   -- 17 bit => 128K clauses---      _ -> error "Int on your CPU doesn't have sufficient bit width."--{-# INLINABLE sortClauses #-}-sortClauses :: Solver -> ClauseExtManager -> Int -> IO Int-sortClauses s cm nneeds = do-  -- constants-  let-    rankMax :: Int-    rankMax = 2 ^ rankWidth - 1-    activityMax :: Int-    activityMax = 2 ^ activityWidth - 1-    activityScale :: Double-    activityScale = fromIntegral activityMax-    indexMax :: Int-    indexMax = (2 ^ indexWidth - 1) -- 67,108,863 for 26-  n <- get' cm-  -- when (indexMax < n) $ error $ "## The number of learnt clauses " ++ show n ++ " exceeds mios's " ++ show indexWidth ++" bit manage capacity"-  vec <- getClauseVector cm-  keys <- getKeyVector cm-  -- 1: assign keys-  let-    assignKey :: Int -> Int -> IO Int-    assignKey ((< n) -> False) m = return m-    assignKey i m = do-      c <- getNth vec i-      k <- (\k -> if k == 2 then return k else fromEnum <$> get' (protected c)) =<< get' c-      case k of-        1 -> set' (protected c) False >> setNth keys i (shiftL 2 indexWidth + i) >> assignKey (i + 1) (m + 1)-        2 -> setNth keys i (shiftL 1 indexWidth + i) >> assignKey (i + 1) (m + 1)-        _ -> do-            l <- locked s c      -- this is expensive-            if l-              then setNth keys i (shiftL 1 indexWidth + i) >> assignKey (i + 1) (m + 1)-              else do-                  d <- rankOf c-                  b <- floor . (activityScale *) . (1 -) . logBase claActivityThreshold . max 1 <$> get' (activity c)-                  setNth keys i $ shiftL (min rankMax d) (activityWidth + indexWidth) + shiftL b indexWidth + i-                  assignKey (i + 1) m-  limit <- min n . (+ nneeds) <$> assignKey 0 0-  -- 2: sort keyVector-  let-    sortOnRange :: Int -> Int -> IO ()-    sortOnRange left right-      | limit < left = return ()-      | left >= right = return ()-      | left + 1 == right = do-          a <- getNth keys left-          b <- getNth keys right-          unless (a < b) $ swapBetween keys left right-      | otherwise = do-          let p = div (left + right) 2-          pivot <- getNth keys p-          swapBetween keys p left -- set a sentinel for r'-          let-            nextL :: Int -> IO Int-            nextL i@((<= right) -> False) = return i-            nextL i = do v <- getNth keys i; if v < pivot then nextL (i + 1) else return i-            nextR :: Int -> IO Int-            nextR i = do v <- getNth keys i; if pivot < v then nextR (i - 1) else return i-            divide :: Int -> Int -> IO Int-            divide l r = do-              l' <- nextL l-              r' <- nextR r-              if l' < r' then swapBetween keys l' r' >> divide (l' + 1) (r' - 1) else return r'-          m <- divide (left + 1) right-          swapBetween keys left m-          sortOnRange left (m - 1)-          sortOnRange (m + 1) right-  sortOnRange 0 (n - 1)-  -- 3: place clauses-  let-    seek :: Int -> IO ()-    seek ((< limit) -> False) = return ()-    seek i = do-      bits <- getNth keys i-      when (indexMax < bits) $ do-        c <- getNth vec i-        let-          sweep k = do-            k' <- (indexMax .&.) <$> getNth keys k-            setNth keys k k-            if k' == i-              then setNth vec k c-              else getNth vec k' >>= setNth vec k >> sweep k'-        sweep i-      seek $ i + 1-  seek 0-  return limit---- | #M22------ simplify : [void] -> [bool]------ __Description:__---   Simplify the clause database according to the current top-level assigment. Currently, the only---   thing done here is the removal of satisfied clauses, but more things can be put here.----{-# INLINABLE simplifyDB #-}-simplifyDB :: Solver -> IO Bool-simplifyDB s@Solver{..} = do-  good <- get' ok-  if good-    then do-      p <- propagate s-      if p /= NullClause-        then set' ok False >> return False-        else do-            -- Clear watcher lists:-            n <- get' trail-            let-              vec = asUVector trail-              loopOnLit ((< n) -> False) = return ()-              loopOnLit i = do-                l <- getNth vec i-                reset . getNthWatcher watches $ l-                reset . getNthWatcher watches $ negateLit l-                loopOnLit $ i + 1-            loopOnLit 0-            -- Remove satisfied clauses:-            let-              for :: Int -> IO Bool-              for ((< 2) -> False) = return True-              for t = do-                let ptr = if t == 0 then learnts else clauses-                vec' <- getClauseVector ptr-                n' <- get' ptr-                let-                  loopOnVector :: Int -> Int -> IO Bool-                  loopOnVector ((< n') -> False) j = shrinkBy ptr (n' - j) >> return True-                  loopOnVector i j = do-                        c <- getNth vec' i-                        l <- locked s c-                        r <- simplify s c-                        if not l && r-                          then removeWatch s c >> loopOnVector (i + 1) j-                          else setNth vec' j c >> loopOnVector (i + 1) (j + 1)-                loopOnVector 0 0-            ret <- for 0-            reset watches-            return ret-    else return False---- | #M22------ search : (nof_conflicts : int) (params : const SearchParams&) -> [lbool]------ __Description:__---   Search for a model the specified number of conflicts.---   NOTE: Use negative value for 'nof_conflicts' indicate infinity.------ __Output:__---   'l_True' if a partial assigment that is consistent with respect to the clause set is found. If---   all variables are decision variables, that means that the clause set is satisfiable. 'l_False'---   if the clause set is unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached.-{-# INLINABLE search #-}-search :: Solver -> Int -> Int -> IO Int-search s@Solver{..} nOfConflicts nOfLearnts = do-  -- clear model-  let-    loop :: Int -> IO Int-    loop conflictC = do-      !confl <- propagate s-      d <- decisionLevel s-      if confl /= NullClause-        then do-            -- CONFLICT-            incrementStat s NumOfBackjump 1-            r <- get' rootLevel-            if d == r-              then do-                  -- Contradiction found:-                  analyzeFinal s confl False-                  return lFalse-              else do---                  u <- (== 0) . (flip mod 5000) <$> getNth stats (fromEnum NumOfBackjump)---                  when u $ do---                    d <- get' varDecay---                    when (d < 0.95) $ modify' varDecay (+ 0.01)-                  backtrackLevel <- analyze s confl -- 'analyze' resets litsLearnt by itself-                  (s `cancelUntil`) . max backtrackLevel =<< get' rootLevel-                  newLearntClause s litsLearnt-                  k <- get' litsLearnt-                  when (k == 1) $ do-                    (v :: Var) <- lit2var <$> getNth (asUVector litsLearnt) 0-                    setNth level v 0-                  varDecayActivity s-                  -- claDecayActivity s-                  loop $ conflictC + 1-        else do                 -- NO CONFLICT-            -- Simplify the set of problem clauses:-            when (d == 0) . void $ simplifyDB s -- our simplifier cannot return @False@ here-            k1 <- get' learnts-            k2 <- nAssigns s-            when (k1 - k2 >= nOfLearnts) $ reduceDB s -- Reduce the set of learnt clauses-            case () of-             _ | k2 == nVars -> do-                   -- Model found:-                   let-                     toInt :: Var -> IO Lit-                     toInt v = (\p -> if lTrue == p then v else negate v) <$> valueVar s v-                     setModel :: Int -> IO ()-                     setModel ((<= nVars) -> False) = return ()-                     setModel v = (setNth model v =<< toInt v) >> setModel (v + 1)-                   setModel 1-                   return lTrue-             _ | conflictC >= nOfConflicts -> do-                   -- Reached bound on number of conflicts-                   (s `cancelUntil`) =<< get' rootLevel -- force a restart-                   claRescaleActivityAfterRestart s-                   incrementStat s NumOfRestart 1-                   return lBottom-             _ -> do-               -- New variable decision:-               v <- select s -- many have heuristic for polarity here-               -- << #phasesaving-               oldVal <- getNth phases v-               unsafeAssume s $ var2lit v (0 < oldVal) -- cannot return @False@-               -- >> #phasesaving-               loop conflictC-  good <- get' ok-  if good then loop 0 else return lFalse---- | __Fig. 16. (p.20)__--- Main solve method.------ __Pre-condition:__ If assumptions are used, 'simplifyDB' must be--- called right before using this method. If not, a top-level conflict (resulting in a--- non-usable internal state) cannot be distinguished from a conflict under assumptions.-{-# INLINABLE solve #-}-solve :: (Foldable t) => Solver -> t Lit -> IO Bool-solve s@Solver{..} assumps = do-  -- PUSH INCREMENTAL ASSUMPTIONS:-  let-    injector :: Lit -> Bool -> IO Bool-    injector _ False = return False-    injector a True = do-      b <- assume s a-      if not b-        then do                 -- conflict analyze-            (confl :: Clause) <- getNth reason (lit2var a)-            analyzeFinal s confl True-            pushTo conflicts (negateLit a)-            cancelUntil s 0-            return False-        else do-            confl <- propagate s-            if confl /= NullClause-              then do-                  analyzeFinal s confl True-                  cancelUntil s 0-                  return False-              else return True-  good <- simplifyDB s-  x <- if good then foldrM injector True assumps else return False-  if not x-    then return False-    else do-        set' rootLevel =<< decisionLevel s-        -- SOLVE:-        nc <- fromIntegral <$> nClauses s-        let-          while :: Double -> Double -> IO Bool-          while nOfConflicts nOfLearnts = do-            status <- search s (floor nOfConflicts) (floor nOfLearnts)-            if status == lBottom-              then while (1.5 * nOfConflicts) (1.1 * nOfLearnts)-              else cancelUntil s 0 >> return (status == lTrue)-        while 100 (nc / 3.0)---- | Though 'enqueue' is defined in 'Solver', most functions in M114 use @unsafeEnqueue@.-{-# INLINABLE unsafeEnqueue #-}-unsafeEnqueue :: Solver -> Lit -> Clause -> IO ()-unsafeEnqueue s@Solver{..} p from = do-  let v = lit2var p-  setNth assigns v $! if positiveLit p then lTrue else lFalse-  setNth level v =<< decisionLevel s-  setNth reason v from     -- NOTE: @from@ might be NULL!-  pushTo trail p---- | __Pre-condition:__ propagation queue is empty.-{-# INLINE unsafeAssume #-}-unsafeAssume :: Solver -> Lit -> IO ()-unsafeAssume s@Solver{..} p = do-  pushTo trailLim =<< get' trail-  unsafeEnqueue s p NullClause
− SAT/Mios/OptionParser.hs
@@ -1,132 +0,0 @@-{-# LANGUAGE Safe #-}---- | command line option parser for mios-module SAT.Mios.OptionParser-       (-         MiosConfiguration (..)-       , defaultConfiguration-       , MiosProgramOption (..)-       , miosDefaultOption-       , miosOptions-       , miosUsage-       , miosParseOptions-       , miosParseOptionsFromArgs-       , toMiosConf-       )-       where--import System.Console.GetOpt (ArgDescr(..), ArgOrder(..), getOpt, OptDescr(..), usageInfo)-import System.Environment (getArgs)-import SAT.Mios.Types (MiosConfiguration (..), defaultConfiguration)---- | configuration swithces-data MiosProgramOption = MiosProgramOption-                     {-                       _targetFile :: Maybe String-                     , _outputFile :: Maybe String-                     , _confVariableDecayRate :: !Double---                     , _confClauseDecayRate :: Double---                     , _confRandomDecisionRate :: Int-                     , _confCheckAnswer :: !Bool-                     , _confVerbose :: !Bool-                     , _confTimeProbe :: !Bool-                     , _confStatProbe :: !Bool-                     , _confNoAnswer :: !Bool-                     , _validateAssignment :: !Bool-                     , _displayHelp :: !Bool-                     , _displayVersion :: !Bool-                     }---- | default option settings-miosDefaultOption :: MiosProgramOption-miosDefaultOption = MiosProgramOption-  {-    _targetFile = Just ""-  , _outputFile = Nothing-  , _confVariableDecayRate = variableDecayRate defaultConfiguration---  , _confClauseDecayRate = clauseDecayRate defaultConfiguration---  , _confRandomDecisionRate = randomDecisionRate defaultConfiguration-  , _confCheckAnswer = False-  , _confVerbose = False-  , _confTimeProbe = False-  , _confStatProbe = False-  , _confNoAnswer = False-  , _validateAssignment = False-  , _displayHelp = False-  , _displayVersion = False-  }---- | definition of mios option-miosOptions :: [OptDescr (MiosProgramOption -> MiosProgramOption)]-miosOptions =-  [-    Option ['d'] ["variable-decay-rate"]-    (ReqArg (\v c -> c { _confVariableDecayRate = read v }) (show (_confVariableDecayRate miosDefaultOption)))-    "[solver] variable activity decay rate (0.0 - 1.0)"---  , Option ['c'] ["clause-decay-rate"]---    (ReqArg (\v c -> c { _confClauseDecayRate = read v }) (show (_confClauseDecayRate miosDefaultOption)))---    "[solver] clause activity decay rate (0.0 - 1.0)"---  , Option ['r'] ["random-decision-rate"]---    (ReqArg (\v c -> c { _confRandomDecisionRate = read v }) (show (_confRandomDecisionRate miosDefaultOption)))---    "[solver] random selection rate (0 - 1000)"-  , Option [':'] ["validate-assignment"]-    (NoArg (\c -> c { _validateAssignment = True }))-    "[solver] read an assignment from STDIN and validate it"-  , Option [] ["validate"]-    (NoArg (\c -> c { _confCheckAnswer = True }))-    "[solver] self-check the (satisfied) answer"-  , Option ['o'] ["output"]-    (ReqArg (\v c -> c { _outputFile = Just v })"file")-    "[option] filename to store the result"-{--  , Option [] ["stdin"]-    (NoArg (\c -> c { _targetFile = Nothing }))-    "[option] read a CNF from STDIN instead of a file"--}-  , Option ['v'] ["verbose"]-    (NoArg (\c -> c { _confVerbose = True }))-    "[option] display misc information"-  , Option ['X'] ["hide-solution"]-    (NoArg (\c -> c { _confNoAnswer = True }))-    "[option] hide the solution"-  , Option [] ["time"]-    (NoArg (\c -> c { _confTimeProbe = True }))-    "[option] display execution time"-  , Option [] ["stat"]-    (NoArg (\c -> c { _confStatProbe = True }))-    "[option] display statistics information"-  , Option ['h'] ["help"]-    (NoArg (\c -> c { _displayHelp = True }))-    "[misc] display this help message"-  , Option [] ["version"]-    (NoArg (\c -> c { _displayVersion = True }))-    "[misc] display program ID"-  ]---- | generates help message-miosUsage :: String -> String-miosUsage mes = usageInfo mes miosOptions---- | builds "MiosProgramOption" from string given as command option-miosParseOptions :: String -> [String] -> IO MiosProgramOption-miosParseOptions mes argv =-    case getOpt Permute miosOptions argv of-      (o, [], []) -> do-        return $ foldl (flip id) miosDefaultOption o-      (o, (n:_), []) -> do-        let conf = foldl (flip id) miosDefaultOption o-        return $ conf { _targetFile = Just n }-      (_, _, errs) -> ioError (userError (concat errs ++ miosUsage mes))---- | builds "MiosProgramOption" from a String-miosParseOptionsFromArgs :: String -> IO MiosProgramOption-miosParseOptionsFromArgs mes = miosParseOptions mes =<< getArgs---- | converts "MiosProgramOption" into "SIHConfiguration"-toMiosConf :: MiosProgramOption -> MiosConfiguration-toMiosConf opts = MiosConfiguration-                 {-                   variableDecayRate = _confVariableDecayRate opts---                 , clauseDecayRate = _confClauseDecayRate opts---                 , randomDecisionRate = _confRandomDecisionRate opts-                 }
− SAT/Mios/Solver.hs
@@ -1,633 +0,0 @@-{-# LANGUAGE-    BangPatterns-  , RecordWildCards-  , ScopedTypeVariables-  , TupleSections-  , ViewPatterns-  #-}-{-# LANGUAGE Safe #-}---- | This is a part of MIOS; main data-module SAT.Mios.Solver-       (-         -- * Solver-         Solver (..)-       , VarHeap-       , newSolver-       , getModel-         -- * Misc Accessors-       , nAssigns-       , nClauses-       , nLearnts-       , decisionLevel-       , valueVar-       , valueLit---       , oldLit-       , locked-         -- * State Modifiers-       , addClause-       , enqueue-       , assume-       , cancelUntil-         -- * Activities-       , claBumpActivity---       , claDecayActivity-       , claRescaleActivityAfterRestart-       , varBumpActivity-       , varDecayActivity-       , claActivityThreshold-         -- * Stats-       , StatIndex (..)-       , getStat-       , setStat-       , incrementStat-       , getStats-       )-        where--import Control.Monad (unless, when)-import SAT.Mios.Types-import SAT.Mios.Clause-import SAT.Mios.ClauseManager---- | __Fig. 2.(p.9)__ Internal State of the solver-data Solver = Solver-              {-{-            Public Interface -}-                model      :: !(Vec Int)         -- ^ If found, this vector has the model-              , conflicts  :: !Stack             -- ^ Set of literals in the case of conflicts-{-            Clause Database -}-              , clauses    :: !ClauseExtManager  -- ^ List of problem constraints.-              , learnts    :: !ClauseExtManager  -- ^ List of learnt clauses.-              , watches    :: !WatcherList       -- ^ list of constraint wathing 'p', literal-indexed-{-            Assignment Management -}-              , assigns    :: !(Vec Int)         -- ^ The current assignments indexed on variables-              , phases     :: !(Vec Int)         -- ^ The last assignments indexed on variables-              , trail      :: !Stack             -- ^ List of assignments in chronological order-              , trailLim   :: !Stack             -- ^ Separator indices for different decision levels in 'trail'.-              , qHead      :: !Int'              -- ^ 'trail' is divided at qHead; assignment part and queue part-              , reason     :: !ClauseVector      -- ^ For each variable, the constraint that implied its value-              , level      :: !(Vec Int)         -- ^ For each variable, the decision level it was assigned-{-            Variable Order -}-              , activities :: !(Vec Double)      -- ^ Heuristic measurement of the activity of a variable-              , order      :: !VarHeap           -- ^ Keeps track of the dynamic variable order.-{-            Configuration -}-              , config     :: !MiosConfiguration -- ^ search paramerters-              , nVars      :: !Int               -- ^ number of variables-{--              -- , claInc     :: !Double'           -- ^ Clause activity increment amount to bump with.-              -- , varDecay   :: !Double'           -- ^ used to set 'varInc'--}-              , varInc     :: !Double'           -- ^ Variable activity increment amount to bump with.-              , rootLevel  :: !Int'              -- ^ Separates incremental and search assumptions.-{-            Working Memory -}-              , ok         :: !Bool'             -- ^ /return value/ holder-              , an'seen    :: !(Vec Int)         -- ^ used in 'SAT.Mios.Main.analyze'-              , an'toClear :: !Stack             -- ^ used in 'SAT.Mios.Main.analyze'-              , an'stack   :: !Stack             -- ^ used in 'SAT.Mios.Main.analyze'-              , an'lastDL  :: !Stack             -- ^ last decision level used in 'SAT.Mios.Main.analyze'-              , litsLearnt :: !Stack             -- ^ used in 'SAT.Mios.Main.analyze' and 'SAT.Mios.Main.search' to create a learnt clause--{--              -- , pr'seen    :: !(Vec Int)         -- ^ used in 'SAT.Mios.Main.propagate'--}-              , stats      :: !(UVector Int)     -- ^ statistics information holder-{--              , lbd'seen   :: !Vec               -- ^ used in lbd computation-              , lbd'key    :: !Int'              -- ^ used in lbd computation--}-              }---- | returns an everything-is-initialized solver from the arguments.-newSolver :: MiosConfiguration -> CNFDescription -> IO Solver-newSolver conf (CNFDescription nv nc _) = do-  Solver-    -- Public Interface-    <$> newVec nv 0                        -- model-    <*> newStack nv                        -- coflict-    -- Clause Database-    <*> newManager nc                      -- clauses-    <*> newManager nc                      -- learnts-    <*> newWatcherList nv 2                -- watches-    -- Assignment Management-    <*> newVec nv lBottom                  -- assigns-    <*> newVec nv lBottom                  -- phases-    <*> newStack nv                        -- trail-    <*> newStack nv                        -- trailLim-    <*> new' 0                             -- qHead-    <*> newClauseVector (nv + 1)           -- reason-    <*> newVec nv (-1)                     -- level-    -- Variable Order-    <*> newVec nv 0                        -- activities-    <*> newVarHeap nv                      -- order-    -- Configuration-    <*> return conf                        -- config-    <*> return nv                          -- nVars---  <*> new' 1.0                           -- claInc---  <*> new' (variableDecayRate conf)      -- varDecay-    <*> new' 1.0                           -- varInc-    <*> new' 0                             -- rootLevel-    -- Working Memory-    <*> new' True                          -- ok-    <*> newVec nv 0                        -- an'seen-    <*> newStack nv                        -- an'toClear-    <*> newStack nv                        -- an'stack---    <*> newVec nv (-1)                     -- pr'seen-    <*> newStack nv                        -- litsLearnt-    <*> newStack nv                        -- lastDL-    <*> newVec (fromEnum EndOfStatIndex) 0 -- stats-{----    <*> newVec nv                        -- lbd'seen---    <*> newInt 0                         -- lbd'key--}------------------------------------------------------------------------------------- Accessors---- | returns the number of current assigments.-{-# INLINE nAssigns #-}-nAssigns :: Solver -> IO Int-nAssigns = get' . trail---- | returns the number of constraints (clauses).-{-# INLINE nClauses #-}-nClauses :: Solver -> IO Int-nClauses = get' . clauses---- | returns the number of learnt clauses.-{-# INLINE nLearnts #-}-nLearnts :: Solver -> IO Int-nLearnts = get' . learnts---- | returns the model as a list of literal.-getModel :: Solver -> IO [Int]-getModel = asList . model---- | returns the current decision level.-{-# INLINE decisionLevel #-}-decisionLevel :: Solver -> IO Int-decisionLevel = get' . trailLim---- | returns the assignment (:: 'LiftedBool' = @[-1, 0, -1]@) from 'Var'.-{-# INLINE valueVar #-}-valueVar :: Solver -> Var -> IO Int-valueVar = getNth . assigns---- | returns the assignment (:: 'LiftedBool' = @[-1, 0, -1]@) from 'Lit'.-{-# INLINE valueLit #-}-valueLit :: Solver -> Lit -> IO Int-valueLit (assigns -> a) p = (\x -> if positiveLit p then x else negate x) <$> getNth a (lit2var p)--{---- | returns the assignment (:: 'LiftedBool' = @[-1, 0, -1]@) from 'Lit' in phases.-{-# INLINE oldLit #-}-oldLit :: Solver -> Lit -> IO Lit-oldLit (phases -> a) (lit2var -> v) = (var2lit v . (== 1)) <$> getNth a v--}---- | __Fig. 7. (p.11)__--- returns @True@ if the clause is locked (used as a reason). __Learnt clauses only__-{-# INLINE locked #-}-locked :: Solver -> Clause -> IO Bool-locked s c = (c ==) <$> (getNth (reason s) . lit2var =<< getNth (lits c) 1)---------------------------------------------------------------------------------- Statistics---- | stat index-data StatIndex =-    NumOfBackjump               -- ^ the number of backjump-  | NumOfRestart                -- ^ the number of restart-  | EndOfStatIndex              -- ^ Don't use this dummy.-  deriving (Bounded, Enum, Eq, Ord, Read, Show)---- | returns the value of 'StatIndex'.-{-# INLINE getStat #-}-getStat :: Solver -> StatIndex -> IO Int-getStat (stats -> v) (fromEnum -> i) = getNth v i---- | sets to 'StatIndex'.-{-# INLINE setStat #-}-setStat :: Solver -> StatIndex -> Int -> IO ()-setStat (stats -> v) (fromEnum -> i) x = setNth v i x---- | increments a stat data corresponding to 'StatIndex'.-{-# INLINE incrementStat #-}-incrementStat :: Solver -> StatIndex -> Int -> IO ()-incrementStat (stats -> v) (fromEnum -> i) k = modifyNth v (+ k) i---- | returns the statistics as a list.-{-# INLINABLE getStats #-}-getStats :: Solver -> IO [(StatIndex, Int)]-getStats (stats -> v) = mapM (\i -> (i, ) <$> getNth v (fromEnum i)) [minBound .. maxBound :: StatIndex]---------------------------------------------------------------------------------- State Modifiers---- | returns @False@ if a conflict has occured.--- This function is called only before the solving phase to register the given clauses.-{-# INLINABLE addClause #-}-addClause :: Solver -> Stack -> IO Bool-addClause s@Solver{..} vecLits = do-  result <- clauseNew s vecLits False-  case result of-   Left b  -> return b   -- No new clause was returned becaues a confilct occured or the clause is a literal-   Right c -> pushTo clauses c >> return True---- | __Fig. 8. (p.12)__ create a new clause and adds it to watcher lists.--- Constructor function for clauses. Returns @False@ if top-level conflict is determined.--- @outClause@ may be set to Null if the new clause is already satisfied under the current--- top-level assignment.------ __Post-condition:__ @ps@ is cleared. For learnt clauses, all--- literals will be false except @lits[0]@ (this by design of the 'analyze' method).--- For the propagation to work, the second watch must be put on the literal which will--- first be unbound by backtracking. (Note that none of the learnt-clause specific things--- needs to done for a user defined contraint type.)------ * @Left False@ if the clause is in a confilct--- * @Left True@ if the clause is satisfied--- * @Right clause@ if the clause is enqueued successfully-{-# INLINABLE clauseNew #-}-clauseNew :: Solver -> Stack -> Bool -> IO (Either Bool Clause)-clauseNew s@Solver{..} ps isLearnt = do-  -- now ps[0] is the number of living literals-  exit <- do-    let-      handle :: Int -> Int -> Int -> IO Bool-      handle j l n      -- removes duplicates, but returns @True@ if this clause is satisfied-        | j > n = return False-        | otherwise = do-            y <- getNth ps j-            case () of-             _ | y == l -> do             -- finds a duplicate-                   swapBetween ps j n-                   modifyNth ps (subtract 1) 0-                   handle j l (n - 1)-             _ | - y == l -> reset ps >> return True -- p and negateLit p occurs in ps-             _ -> handle (j + 1) l n-      loopForLearnt :: Int -> IO Bool-      loopForLearnt i = do-        n <- get' ps-        if n < i-          then return False-          else do-              l <- getNth ps i-              sat <- handle (i + 1) l n-              if sat-                then return True-                else loopForLearnt $ i + 1-      loop :: Int -> IO Bool-      loop i = do-        n <- get' ps-        if n < i-          then return False-          else do-              l <- getNth ps i     -- check the i-th literal's satisfiability-              sat <- valueLit s l  -- any literal in ps is true-              case sat of-               1  -> reset ps >> return True-               -1 -> do-                 swapBetween ps i n-                 modifyNth ps (subtract 1) 0-                 loop i-               _ -> do-                 sat' <- handle (i + 1) l n-                 if sat'-                   then return True-                   else loop $ i + 1-    if isLearnt then loopForLearnt 1 else loop 1-  k <- get' ps-  case k of-   0 -> return (Left exit)-   1 -> do-     l <- getNth ps 1-     Left <$> enqueue s l NullClause-   _ -> do-    -- allocate clause:-     c <- newClauseFromStack isLearnt ps-     let vec = asUVector c-     when isLearnt $ do-       -- Pick a second literal to watch:-       let-         findMax :: Int -> Int -> Int -> IO Int-         findMax ((< k) -> False) j _ = return j-         findMax i j val = do-           v' <- lit2var <$> getNth vec i-           varBumpActivity s v' -- this is a just good chance to bump activities of literals in this clause-           a <- getNth assigns v'-           b <- getNth level v'-           if (a /= lBottom) && (val < b)-             then findMax (i + 1) i b-             else findMax (i + 1) j val-       -- Let @max_i@ be the index of the literal with highest decision level-       max_i <- findMax 0 0 0-       swapBetween vec 1 max_i-       -- check literals occurences-       -- x <- asList c-       -- unless (length x == length (nub x)) $ error "new clause contains a element doubly"-       -- Bumping:-       claBumpActivity s c -- newly learnt clauses should be considered active-     -- Add clause to watcher lists:-     l0 <- negateLit <$> getNth vec 0-     pushClauseWithKey (getNthWatcher watches l0) c 0-     l1 <- negateLit <$> getNth vec 1-     pushClauseWithKey (getNthWatcher watches l1) c 0-     return (Right c)---- | __Fig. 9 (p.14)__--- Puts a new fact on the propagation queue, as well as immediately updating the variable's value--- in the assignment vector. If a conflict arises, @False@ is returned and the propagation queue is--- cleared. The parameter 'from' contains a reference to the constraint from which 'p' was--- propagated (defaults to @Nothing@ if omitted).-{-# INLINABLE enqueue #-}-enqueue :: Solver -> Lit -> Clause -> IO Bool-enqueue s@Solver{..} p from = do-{--  -- bump psedue lbd of @from@-  when (from /= NullClause && learnt from) $ do-    l <- get' (lbd from)-    k <- (12 +) <$> decisionLevel s-    when (k < l) $ set' (lbd from) k--}-  let signumP = if positiveLit p then lTrue else lFalse-  let v = lit2var p-  val <- valueVar s v-  if val /= lBottom-    then do -- Existing consistent assignment -- don't enqueue-        return $ val == signumP-    else do-        -- New fact, store it-        setNth assigns v signumP-        setNth level v =<< decisionLevel s-        setNth reason v from     -- NOTE: @from@ might be NULL!-        pushTo trail p-        return True---- | __Fig. 12 (p.17)__--- returns @False@ if immediate conflict.------ __Pre-condition:__ propagation queue is empty-{-# INLINE assume #-}-assume :: Solver -> Lit -> IO Bool-assume s p = do-  pushTo (trailLim s) =<< get' (trail s)-  enqueue s p NullClause---- | #M22: Revert to the states at given level (keeping all assignment at 'level' but not beyond).-{-# INLINABLE cancelUntil #-}-cancelUntil :: Solver -> Int -> IO ()-cancelUntil s@Solver{..} lvl = do-  dl <- decisionLevel s-  when (lvl < dl) $ do-    let tr = asUVector trail-    let tl = asUVector trailLim-    lim <- getNth tl lvl-    ts <- get' trail-    ls <- get' trailLim-    let-      loopOnTrail :: Int -> IO ()-      loopOnTrail ((lim <=) -> False) = return ()-      loopOnTrail c = do-        x <- lit2var <$> getNth tr c-        setNth phases x =<< getNth assigns x-        setNth assigns x lBottom-        -- #reason to set reason Null-        -- if we don't clear @reason[x] :: Clause@ here, @reason[x]@ remains as locked.-        -- This means we can't reduce it from clause DB and affects the performance.-        setNth reason x NullClause -- 'analyze` uses reason without checking assigns-        -- FIXME: #polarity https://github.com/shnarazk/minisat/blosb/master/core/Solver.cc#L212-        undo s x-        -- insertHeap s x              -- insertVerOrder-        loopOnTrail $ c - 1-    loopOnTrail $ ts - 1-    shrinkBy trail (ts - lim)-    shrinkBy trailLim (ls - lvl)-    set' qHead =<< get' trail---------------------------------------------------------------------------------- VarOrder---- | Interfate to select a decision var based on variable activity.-instance VarOrder Solver where-{--  -- | __Fig. 6. (p.10)__-  -- Creates a new SAT variable in the solver.-  newVar _ = return 0-    -- i <- nVars s-    -- Version 0.4:: push watches =<< newVec      -- push'-    -- Version 0.4:: push watches =<< newVec      -- push'-    -- push undos =<< newVec        -- push'-    -- push reason NullClause       -- push'-    -- push assigns lBottom-    -- push level (-1)-    -- push activities (0.0 :: Double)-    -- newVar order-    -- growQueueSized (i + 1) propQ-    -- return i--}-  {-# SPECIALIZE INLINE update :: Solver -> Var -> IO () #-}-  update = increaseHeap-  {-# SPECIALIZE INLINE undo :: Solver -> Var -> IO () #-}-  undo s v = inHeap s v >>= (`unless` insertHeap s v)-  {-# SPECIALIZE INLINE select :: Solver -> IO Var #-}-  select s = do-    let-      asg = assigns s-      -- | returns the most active var (heap-based implementation)-      loop :: IO Var-      loop = do-        n <- numElementsInHeap s-        if n == 0-          then return 0-          else do-              v <- getHeapRoot s-              x <- getNth asg v-              if x == lBottom then return v else loop-    loop---------------------------------------------------------------------------------- Activities--varActivityThreshold :: Double-varActivityThreshold = 1e100---- | value for rescaling clause activity.-claActivityThreshold :: Double-claActivityThreshold = 1e20---- | __Fig. 14 (p.19)__ Bumping of clause activity-{-# INLINE varBumpActivity #-}-varBumpActivity :: Solver -> Var -> IO ()-varBumpActivity s@Solver{..} x = do-  !a <- (+) <$> getNth activities x <*> get' varInc-  setNth activities x a-  when (varActivityThreshold < a) $ varRescaleActivity s-  update s x                    -- update the position in heap---- | __Fig. 14 (p.19)__-{-# INLINABLE varDecayActivity #-}-varDecayActivity :: Solver -> IO ()-varDecayActivity Solver{..} = modify' varInc (/ variableDecayRate config)--- varDecayActivity Solver{..} = modifyDouble varInc . (flip (/)) =<< getDouble varDecay---- | __Fig. 14 (p.19)__-{-# INLINABLE varRescaleActivity #-}-varRescaleActivity :: Solver -> IO ()-varRescaleActivity Solver{..} = do-  let-    loop ((<= nVars) -> False) = return ()-    loop i = modifyNth activities (/ varActivityThreshold) i >> loop (i + 1)-  loop 1-  modify' varInc (/ varActivityThreshold)---- | __Fig. 14 (p.19)__-{-# INLINE claBumpActivity #-}-claBumpActivity :: Solver -> Clause -> IO ()-claBumpActivity s Clause{..} = do-  dl <- decisionLevel s-  a <- (fromIntegral dl +) <$> get' activity-  set' activity a-  -- set' protected True-  when (claActivityThreshold <= a) $ claRescaleActivity s--{---- | __Fig. 14 (p.19)__-{-# INLINE claDecayActivity #-}-claDecayActivity :: Solver -> IO ()-claDecayActivity Solver{..} = modifyDouble claInc (/ clauseDecayRate config)--}---- | __Fig. 14 (p.19)__-{-# INLINABLE claRescaleActivity #-}-claRescaleActivity :: Solver -> IO ()-claRescaleActivity Solver{..} = do-  vec <- getClauseVector learnts-  n <- get' learnts-  let-    loopOnVector :: Int -> IO ()-    loopOnVector ((< n) -> False) = return ()-    loopOnVector i = do-      c <- getNth vec i-      modify' (activity c) (/ claActivityThreshold)-      loopOnVector $ i + 1-  loopOnVector 0-  -- modifyDouble claInc (/ claActivityThreshold)---- | __Fig. 14 (p.19)__-{-# INLINABLE claRescaleActivityAfterRestart #-}-claRescaleActivityAfterRestart :: Solver -> IO ()-claRescaleActivityAfterRestart Solver{..} = do-  vec <- getClauseVector learnts-  n <- get' learnts-  let-    loopOnVector :: Int -> IO ()-    loopOnVector ((< n) -> False) = return ()-    loopOnVector i = do-      c <- getNth vec i-      d <- get' c-      if d < 9-        then modify' (activity c) sqrt-        else set' (activity c) 0-      set' (protected c) False-      loopOnVector $ i + 1-  loopOnVector 0---------------------------------------------------------------------------------- VarHeap---- | A heap tree built from two 'Vec'.--- This implementation is identical wtih that in Minisat-1.14.--- Note: the zero-th element of @heap@ is used for holding the number of elements.--- Note: VarHeap itself is not a @VarOrder@, because it requires a pointer to solver.-data VarHeap = VarHeap-                {-                  heap :: !Stack  -- order to var-                , idxs :: !Stack  -- var to order (index)-                }--newVarHeap :: Int -> IO VarHeap-newVarHeap n = do-  v1 <- newVec n 0-  v2 <- newVec n 0-  let-    loop :: Int -> IO ()-    loop ((<= n) -> False) = set' v1 n >> set' v2 n-    loop i = setNth v1 i i >> setNth v2 i i >> loop (i + 1)-  loop 1-  return $ VarHeap v1 v2--{-# INLINE numElementsInHeap #-}-numElementsInHeap :: Solver -> IO Int-numElementsInHeap = get' . heap . order--{-# INLINE inHeap #-}-inHeap :: Solver -> Var -> IO Bool-inHeap (order -> idxs -> at) n = (/= 0) <$> getNth at n--{-# INLINE increaseHeap #-}-increaseHeap :: Solver -> Int -> IO ()-increaseHeap s@(order -> idxs -> at) n = inHeap s n >>= (`when` (percolateUp s =<< getNth at n))--{-# INLINABLE percolateUp #-}-percolateUp :: Solver -> Int -> IO ()-percolateUp Solver{..} start = do-  let VarHeap to at = order-  v <- getNth to start-  ac <- getNth activities v-  let-    loop :: Int -> IO ()-    loop i = do-      let iP = div i 2          -- parent-      if iP == 0-        then setNth to i v >> setNth at v i -- end-        else do-            v' <- getNth to iP-            acP <- getNth activities v'-            if ac > acP-              then setNth to i v' >> setNth at v' i >> loop iP -- loop-              else setNth to i v >> setNth at v i              -- end-  loop start--{-# INLINABLE percolateDown #-}-percolateDown :: Solver -> Int -> IO ()-percolateDown Solver{..} start = do-  let (VarHeap to at) = order-  n <- getNth to 0-  v <- getNth to start-  ac <- getNth activities v-  let-    loop :: Int -> IO ()-    loop i = do-      let iL = 2 * i            -- left-      if iL <= n-        then do-            let iR = iL + 1     -- right-            l <- getNth to iL-            r <- getNth to iR-            acL <- getNth activities l-            acR <- getNth activities r-            let (ci, child, ac') = if iR <= n && acL < acR then (iR, r, acR) else (iL, l, acL)-            if ac' > ac-              then setNth to i child >> setNth at child i >> loop ci-              else setNth to i v >> setNth at v i -- end-        else setNth to i v >> setNth at v i       -- end-  loop start--{-# INLINABLE insertHeap #-}-insertHeap :: Solver -> Var -> IO ()-insertHeap s@(order -> VarHeap to at) v = do-  n <- (1 +) <$> getNth to 0-  setNth at v n-  setNth to n v-  set' to n-  percolateUp s n---- | returns the value on the root (renamed from @getmin@).-{-# INLINABLE getHeapRoot #-}-getHeapRoot :: Solver -> IO Int-getHeapRoot s@(order -> VarHeap to at) = do-  r <- getNth to 1-  l <- getNth to =<< getNth to 0 -- the last element's value-  setNth to 1 l-  setNth at l 1-  setNth at r 0-  modifyNth to (subtract 1) 0 -- pop-  n <- getNth to 0-  when (1 < n) $ percolateDown s 1-  return r
− SAT/Mios/Types.hs
@@ -1,257 +0,0 @@-{-# LANGUAGE-    BangPatterns-  , MultiParamTypeClasses-  #-}-{-# LANGUAGE Safe #-}---- | Basic data types used throughout mios.-module SAT.Mios.Types-       (-         module SAT.Mios.Vec-         -- *  Variable-       , Var-       , bottomVar-       , int2var-         -- * Internal encoded Literal-       , Lit-       , lit2int-       , int2lit-       , bottomLit---       , newLit-       , positiveLit-       , lit2var-       , var2lit-       , negateLit-         -- * Assignment on the lifted Bool domain---       , LiftedBool (..)---       , lbool-       , lFalse-       , lTrue-       , lBottom-       , VarOrder (..)-         -- * CNF-       , CNFDescription (..)-         -- * Solver Configuration-       , MiosConfiguration (..)-       , defaultConfiguration-       )-       where--import Data.Bits-import SAT.Mios.Vec---- | represents "Var".-type Var = Int---- | Special constant in 'Var' (p.7)-bottomVar :: Var-bottomVar = 0---- | converts a usual Int as literal to an internal 'Var' presentation.------ >>> int2var 1--- 1  -- the first literal is the first variable--- >>> int2var 2--- 2  -- literal @2@ is variable 2--- >>> int2var (-2)--- 2 -- literal @-2@ is corresponding to variable 2----{-# INLINE int2var #-}-int2var :: Int -> Int-int2var = abs---- | The literal data has an 'index' method which converts the literal to--- a "small" integer suitable for array indexing. The 'var'  method returns--- the underlying variable of the literal, and the 'sign' method if the literal--- is signed (False for /x/ and True for /-x/).-type Lit = Int---- | Special constant in 'Lit' (p.7)-bottomLit :: Lit-bottomLit = 0--{---- | converts "Var" into 'Lit'-newLit :: Var -> Lit-newLit = error "newLit undefined"--}---- | returns @True@ if the literal is positive-{-# INLINE positiveLit #-}-positiveLit :: Lit -> Bool-positiveLit = even---- | negates literal------ >>> negateLit 2--- 3--- >>> negateLit 3--- 2--- >>> negateLit 4--- 5--- >>> negateLit 5--- 4-{-# INLINE negateLit #-}-negateLit :: Lit -> Lit-negateLit l = complementBit l 0 -- if even l then l + 1 else l - 1------------------------------------------------------------ Var--------------------------------------------- | converts 'Lit' into 'Var'.------ >>> lit2var 2--- 1--- >>> lit2var 3--- 1--- >>> lit2var 4--- 2--- >>> lit2var 5--- 2-{-# INLINE lit2var #-}-lit2var :: Lit -> Var-lit2var !n = shiftR n 1---- | converts a 'Var' to the corresponing literal.------ >>> var2lit 1 True--- 2--- >>> var2lit 1 False--- 3--- >>> var2lit 2 True--- 4--- >>> var2lit 2 False--- 5-{-# INLINE var2lit #-}-var2lit :: Var -> Bool -> Lit-var2lit !v True = shiftL v 1-var2lit !v _ = shiftL v 1 + 1------------------------------------------------------------ Int--------------------------------------------- | converts 'Int' into 'Lit' as @lit2int . int2lit == id@.------ >>> int2lit 1--- 2--- >>> int2lit (-1)--- 3--- >>> int2lit 2--- 4--- >>> int2lit (-2)--- 5----{-# INLINE int2lit #-}-int2lit :: Int -> Lit-int2lit n-  | 0 < n = 2 * n-  | otherwise = -2 * n + 1---- | converts `Lit' into 'Int' as @int2lit . lit2int == id@.------ >>> lit2int 2--- 1--- >>> lit2int 3--- -1--- >>> lit2int 4--- 2--- >>> lit2int 5--- -2-{-# INLINE lit2int #-}-lit2int :: Lit -> Int-lit2int l = case divMod l 2 of-  (i, 0) -> i-  (i, _) -> - i--{---- | Lifted Boolean domain (p.7) that extends 'Bool' with "⊥" means /undefined/--- design note: _|_ should be null = 0; True literals are coded to even numbers. So it should be 2.-data LiftedBool = Bottom | LFalse | LTrue-  deriving (Bounded, Eq, Ord, Read, Show)--instance Enum LiftedBool where-  {-# SPECIALIZE INLINE toEnum :: Int -> LiftedBool #-}-  toEnum        1 = LTrue-  toEnum     (-1) = LFalse-  toEnum        _ = Bottom-  {-# SPECIALIZE INLINE fromEnum :: LiftedBool -> Int #-}-  fromEnum Bottom = 0-  fromEnum LFalse = 1-  fromEnum LTrue  = 2---- | converts 'Bool' into 'LBool'-{-# INLINE lbool #-}-lbool :: Bool -> LiftedBool-lbool True = LTrue-lbool False = LFalse--}---- | /FALSE/ on the Lifted Bool domain-lFalse:: Int-lFalse = -1---- | /TRUE/ on the Lifted Bool domain-lTrue :: Int-lTrue = 1---- | /UNDEFINED/ on the Lifted Bool domain-lBottom :: Int-lBottom = 0---- | Assisting ADT for the dynamic variable ordering of the solver.--- The constructor takes references to the assignment vector and the activity--- vector of the solver. The method 'select' will return the unassigned variable--- with the highest activity.-class VarOrder o where-{--  -- | constructor-  newVarOrder :: (VecFamily v1 Bool, VecFamily v2 Double) => v1 -> v2 -> IO o-  newVarOrder _ _ = error "newVarOrder undefined"--  -- | Called when a new variable is created.-  newVar :: o -> IO Var-  newVar = error "newVar undefined"--}-  -- | should be called when a variable has increased in activity.-  update :: o -> Var -> IO ()-  update _  = error "update undefined"-{--  -- | should be called when all variables have been assigned.-  updateAll :: o -> IO ()-  updateAll = error "updateAll undefined"--}-  -- | should be called when a variable becomes unbound (may be selected again).-  undo :: o -> Var -> IO ()-  undo _ _  = error "undo undefined"--  -- | returns a new, unassigned var as the next decision.-  select :: o -> IO Var-  select    = error "select undefined"---- | Misc information on a CNF-data CNFDescription = CNFDescription-  {-    _numberOfVariables :: !Int           -- ^ the number of variables-  , _numberOfClauses :: !Int             -- ^ the number of clauses-  , _pathname :: Maybe FilePath          -- ^ given filename-  }-  deriving (Eq, Ord, Show)---- | Solver's parameters; random decision rate was dropped.-data MiosConfiguration = MiosConfiguration-                         {-                           variableDecayRate  :: !Double  -- ^ decay rate for variable activity---                         , clauseDecayRate    :: !Double  -- ^ decay rate for clause activity-                         }---- | dafault configuration------ * Minisat-1.14 uses @(0.95, 0.999, 0.2 = 20 / 1000)@.--- * Minisat-2.20 uses @(0.95, 0.999, 0)@.--- * Gulcose-4.0  uses @(0.8 , 0.999, 0)@.--- * Mios-1.2     uses @(0.95, 0.999, 0)@.----defaultConfiguration :: MiosConfiguration-defaultConfiguration = MiosConfiguration 0.95 {- 0.999 -} {- 0 -}
− SAT/Mios/Util/BoolExp.hs
@@ -1,244 +0,0 @@-{-# LANGUAGE BangPatterns, FlexibleInstances, ViewPatterns, UndecidableInstances #-}-{-# LANGUAGE Safe #-}---- | Boolean Expression module to build CNF from arbitrary expressions--- Tseitin translation: http://en.wikipedia.org/wiki/Tseitin_transformation-module SAT.Mios.Util.BoolExp-       (-         -- * Class & Type-         BoolComponent (..)-       , BoolForm (..)-         -- * Expression contructors-       , (-|-)-       , (-&-)-       , (-=-)-       , (-!-)-       , (->-)-       , neg-         -- * List Operation-       , disjunctionOf-       , (-|||-)-       , conjunctionOf-       , (-&&&-)-         -- * Convert function-       , asList-       , asList_-       , asLatex-       , asLatex_-       , numberOfVariables-       , numberOfClauses-       , tseitinBase-       )-       where--import Data.List (foldl', intercalate)---- | the start index for the generated variables by Tseitin encoding-tseitinBase :: Int-tseitinBase = 1600000--data L = L Int---- | class of objects that can be interpeted as a bool expression-class BoolComponent a where-  toBF :: a -> BoolForm   -- lift to BoolForm---- | CNF expression-data BoolForm = Cnf (Int, Int) [[Int]]-    deriving (Eq, Show)--instance BoolComponent Int where-  toBF a = Cnf (abs a, max tseitinBase (abs a)) [[a]]--instance BoolComponent L where-  toBF (L a) = Cnf (abs a, max tseitinBase (abs a)) [[a]]--instance BoolComponent [Char] where-  toBF (read -> a) = Cnf (abs a, max tseitinBase (abs a)) [[a]]--instance BoolComponent BoolForm where-  toBF = id---- | returns the number of variables in the 'BoolForm'-numberOfVariables :: BoolForm -> Int-numberOfVariables (Cnf (a, b) _) = a + b - tseitinBase---- | returns the number of clauses in the 'BoolForm'-numberOfClauses :: BoolForm -> Int-numberOfClauses (Cnf _ l) = length l--boolFormTrue = Cnf (-1, 1) []-boolFormFalse = Cnf (-1, -1) []--instance BoolComponent Bool where-  toBF True = boolFormTrue-  toBF False = boolFormFalse--isTrue :: BoolForm -> Bool-isTrue = (== boolFormTrue)--isFalse :: BoolForm -> Bool-isFalse = (== boolFormFalse)---- | return a 'clause' list only if it contains some real clause (not a literal)-clausesOf :: BoolForm -> [[Int]]-clausesOf cnf@(Cnf _ [[]]) = []-clausesOf cnf@(Cnf _ [[x]]) = []-clausesOf cnf@(Cnf _ l) = l--maxRank :: BoolForm -> Int-maxRank (Cnf (n, _) _) = n---- | returns the number of valiable used as the output of this expression.--- and returns itself it the expression is a literal.--- Otherwise the number is a integer larger than 'tseitinBase'.--- Therefore @1 + max tseitinBase the-returned-value@ is the next literal variable for future.-tseitinNumber :: BoolForm -> Int-tseitinNumber (Cnf (m, n) [[x]]) = x-tseitinNumber (Cnf (_, n) _) = n--renumber :: Int -> BoolForm -> (BoolForm, Int)-renumber base (Cnf (m, n) l)-  | l == [] = (Cnf (m, n) l, 0)-  | tseitinBase < base = (Cnf (m, n') l', n')-  | otherwise = (Cnf (n', tseitinBase) l', n')-  where-    l' = map (map f) l-    n' = maximum $ map maximum l'-    offset = base - tseitinBase - 1-    f x = if abs x < tseitinBase then x else signum x * (abs x + offset)--instance Ord BoolForm where-  compare (Cnf _ a) (Cnf _ b) = compare a b---- | disjunction constructor------ >>> asList $ "3" -|- "4"--- [[3,4,-5],[-3,5],[-4,5]]------ >>> asList (("3" -|- "4") -|- "-1")--- [[3,4,-5],[-3,5],[-4,5],[5,-1,-6],[-5,6],[1,6]]----(-|-) :: (BoolComponent a, BoolComponent b) => a -> b -> BoolForm-(toBF -> e1) -|- (toBF -> e2')-  | isTrue e1 || isTrue e2' = boolFormTrue-  | isFalse e1 && isFalse e2' = boolFormFalse-  | isFalse e1 = e2'-  | isFalse e2' = e1-  | otherwise = Cnf (m, c) $ clausesOf e1 ++ clausesOf e2 ++ [[a, b, - c], [- a, c], [- b, c]]-  where-    a = tseitinNumber e1-    (e2, b) = renumber (1 + max tseitinBase a) e2'-    m = max (maxRank e1) (maxRank e2)-    c = 1 + max tseitinBase (max a b)---- | conjunction constructor------ >>> asList $ "3" -&- "-2"--- [[-3,2,4],[3,-4],[-2,-4]]------ >>> asList $ "3" -|- ("1" -&- "2")--- [[-1,-2,4],[1,-4],[2,-4],[3,4,-5],[-3,5],[-4,5]]----(-&-) :: (BoolComponent a, BoolComponent b) => a -> b -> BoolForm-(toBF -> e1) -&- (toBF -> e2')-  | isTrue e1 && isTrue e2' = boolFormTrue-  | isFalse e1 || isFalse e2' = boolFormFalse-  | isTrue e1 = e2'-  | isTrue e2' = e1-  | otherwise = Cnf (m, c) $ clausesOf e1 ++ clausesOf e2 ++ [[- a, - b, c], [a, - c], [b, - c]]-  where-    a = tseitinNumber e1-    (e2, b) = renumber (1 + max tseitinBase a) e2'-    m = max (maxRank e1) (maxRank e2)-    c = 1 + max tseitinBase (max a b)---- | negate a form------ >>> asList $ neg ("1" -|- "2")--- [[1,2,-3],[-1,3],[-2,3],[-3,-4],[3,4]]-neg :: (BoolComponent a) => a -> BoolForm-neg (toBF -> e) =-  Cnf (m, c) $ clausesOf e ++ [[- a, - c], [a, c]]-  where-    a = tseitinNumber e-    m = maxRank e-    c = 1 + max tseitinBase a---- | equal on BoolForm-(-=-) :: (BoolComponent a, BoolComponent b) => a -> b -> BoolForm-(toBF -> e1) -=- (toBF -> e2) = (e1 -&- e2) -|- (neg e1 -&- neg e2)---- | negation on BoolForm-(-!-) :: (BoolComponent a, BoolComponent b) => a -> b -> BoolForm-(toBF -> e1) -!- (toBF -> e2) = (neg e1 -&- e2) -|- (e1 -&- neg e2)---- | implication as a short cut------ >>> asList ("1" ->- "2")--- [[-1,-3],[1,3],[3,2,-4],[-3,4],[-2,4]]-(->-) :: (BoolComponent a, BoolComponent b) => a -> b -> BoolForm-(toBF -> a) ->- (toBF -> b) = (neg a) -|- b---- | merge [BoolForm] by '(-|-)'-disjunctionOf :: [BoolForm] -> BoolForm-disjunctionOf [] = boolFormFalse-disjunctionOf (x:l) = foldl' (-|-) x l---- | an alias of 'disjunctionOf'-(-|||-) = disjunctionOf---- | merge [BoolForm] by '(-&-)'-conjunctionOf :: [BoolForm] -> BoolForm-conjunctionOf [] = boolFormTrue-conjunctionOf (x:l) = foldl' (-&-) x l---- | an alias of 'conjunctionOf'-(-&&&-) = conjunctionOf---- | converts a BoolForm to "[[Int]]"-asList_ :: BoolForm -> [[Int]]-asList_ cnf@(Cnf (m,_) _)-  | isTrue cnf = []-  | isFalse cnf = [[]]-  | otherwise = l'-  where-    (Cnf _ l', _) = renumber (m + 1) cnf---- | converts a *satisfied* BoolForm to "[[Int]]"-asList :: BoolForm -> [[Int]]-asList cnf@(Cnf (m,n) l)-  | isTrue cnf = []-  | isFalse cnf = [[]]-  | n <= tseitinBase = l-  | otherwise = [m'] : l'-  where-    (Cnf (m', _) l', _) = renumber (m + 1) cnf---- | make latex string from CNF, using 'asList_'------ >>> asLatex $ "3" -|- "4"--- "\\begin{displaymath}\n( x_{3} \\vee x_{4} )\n\\end{displaymath}\n"----asLatex_ :: BoolForm -> String-asLatex_ b = beg ++ s ++ end-  where-    beg = "\\begin{displaymath}\n"-    end = "\n\\end{displaymath}\n"-    s = intercalate " \\wedge " [ makeClause c | c <- asList_ b]-    makeClause c = "(" ++ intercalate "\\vee" [makeLiteral l | l <- c] ++ ")"-    makeLiteral l-      | 0 < l = " x_{" ++ show l ++ "} "-      | otherwise = " \\neg " ++ "x_{" ++ show (negate l) ++ "} "---- | make latex string from CNF, using 'asList'-asLatex :: BoolForm -> String-asLatex b = beg ++ s ++ end-  where-    beg = "\\begin{displaymath}\n"-    end = "\n\\end{displaymath}\n"-    s = intercalate " \\wedge " [ makeClause c | c <- asList b]-    makeClause c = "(" ++ intercalate "\\vee" [makeLiteral l | l <- c] ++ ")"-    makeLiteral l-      | 0 < l = " x_{" ++ show l ++ "} "-      | otherwise = " \\neg " ++ "x_{" ++ show (negate l) ++ "} "
− SAT/Mios/Util/DIMACS.hs
@@ -1,31 +0,0 @@-{-# LANGUAGE Safe #-}---- | Read/Write a CNF file only with ghc standard libraries-module SAT.Mios.Util.DIMACS-       (-         -- * Input-         fromFile-       , clauseListFromFile-       , fromMinisatOutput-       , clauseListFromMinisatOutput-         -- * Output-       , toFile-       , toDIMACSString-       , asDIMACSString-       , asDIMACSString_-         -- * Bool Operation-       , module SAT.Mios.Util.BoolExp-       )-       where-import SAT.Mios.Util.DIMACS.Reader-import SAT.Mios.Util.DIMACS.Writer-import SAT.Mios.Util.DIMACS.MinisatReader-import SAT.Mios.Util.BoolExp---- | String from BoolFrom-asDIMACSString :: BoolForm -> String-asDIMACSString = toDIMACSString . asList---- | String from BoolFrom-asDIMACSString_ :: BoolForm -> String-asDIMACSString_ = toDIMACSString . asList_
− SAT/Mios/Util/DIMACS/MinisatReader.hs
@@ -1,73 +0,0 @@-{-# LANGUAGE Safe #-}---- | Read an output file of minisat-module SAT.Mios.Util.DIMACS.MinisatReader-       (-         -- * Interface-         fromMinisatOutput-       , clauseListFromMinisatOutput-       )-       where--- import Control.Applicative ((<$>), (<*>), (<*), (*>))-import Data.Char-import Text.ParserCombinators.ReadP---- parser--- |parse a non-signed integer-{-# INLINE pint #-}-pint = do-  n <- munch isDigit-  return (read n :: Int)--{-# INLINE mint #-}-mint = do-  char '-'-  n <- munch isDigit-  return (- (read n::Int))---- |parse a (signed) integer-{-# INLINE int #-}-int = mint <++ pint---- |return integer list that terminates at zero-{-# INLINE seqNums #-}-seqNums = do-  skipSpaces-  x <- int-  skipSpaces-  if (x == 0) then return []  else (x :) <$> seqNums---- |top level interface for parsing CNF-{-# INLINE parseMinisatOutput #-}-parseMinisatOutput :: ReadP ((Int, Int), [Int])-parseMinisatOutput = do-  string "SAT"-  skipSpaces-  l <- seqNums-  return ((length l,0), l)---- |read a minisat output:--- ((numbefOfVariables, 0), [Literal])------ >>>  fromFile "result"--- ((3, 0), [1, -2, 3])----{-# INLINE fromMinisatOutput #-}-fromMinisatOutput :: FilePath -> IO (Maybe ((Int, Int), [Int]))-fromMinisatOutput f = do-  c <- readFile f-  case readP_to_S parseMinisatOutput c of-    [(a, _)] -> return $ Just a-    _ -> return Nothing---- | return clauses as [[Int]] from 'file'------ >>> clauseListFromMinisatOutput "result"--- [1,-2,3]----clauseListFromMinisatOutput :: FilePath -> IO [Int]-clauseListFromMinisatOutput l = do-  res <- fromMinisatOutput l-  case res of-    Just p -> return (snd p)-    _ -> return []
− SAT/Mios/Util/DIMACS/Reader.hs
@@ -1,130 +0,0 @@-{-# LANGUAGE Safe #-}---- | Read a CNF file without haskell-platform-module SAT.Mios.Util.DIMACS.Reader-       (-         -- * Interface-         fromFile-       , clauseListFromFile-       )-       where-import Control.Applicative ((<$>), (<*>), (<*), (*>))-import Data.Char-import Text.ParserCombinators.ReadP---- parser-{-# INLINE newline #-}-newline = char '\n'--{-# INLINE digit #-}-digit = satisfy isDigit--{-# INLINE spaces #-}-spaces = munch (`elem` " \t")--{-# INLINE noneOf #-}-noneOf s = satisfy (`notElem` s)---- |parse a non-signed integer-{-# INLINE pint #-}-pint = do-  n <- munch isDigit-  return (read n :: Int)--{-# INLINE mint #-}-mint = do-  char '-'-  n <- munch isDigit-  return (- (read n::Int))---- |parse a (signed) integer-{-# INLINE int #-}-int = mint <++ pint---- |Parse something like: p FORMAT VARIABLES CLAUSES-{-# INLINE problemLine #-}-problemLine = do-  char 'p'-  skipSpaces-  (string "cnf" <++ string "CNF")-  skipSpaces-  vars <- pint-  skipSpaces-  clas <- pint-  spaces-  newline-  return (vars, clas)---- |Parse something like: c This in an example of a comment line.-{-# INLINE commentLines #-}-commentLines = do-  l <- look-  if (head l)  == 'c'-    then do-      munch ('\n' /=)-      newline-      commentLines-    else return ()--_commentLines = do-  char 'c'-  munch ('\n' /=)-  newline-  l <- look-  if (head l)  == 'c' then commentLines else return ()---- |Parse the preamble part-{-# INLINE preambleCNF #-}-preambleCNF = do-  commentLines-  problemLine---- |return integer list that terminates at zero-{-# INLINE seqNums #-}-seqNums = do-  skipSpaces-  x <- int-  skipSpaces-  if (x == 0) then return []  else (x :) <$> seqNums---- |Parse something like: 1 -2 0 4 0 -3 0-{-# INLINE parseClauses #-}-parseClauses :: Int -> ReadP [[Int]]-parseClauses n = count n seqNums---- |top level interface for parsing CNF-{-# INLINE parseCNF #-}-parseCNF :: ReadP ((Int, Int), [[Int]])-parseCNF = do-  a <- preambleCNF-  b <- parseClauses (snd a)-  return (a, b)---- |driver:: String -> Either ParseError Int-driver input = readP_to_S (parseClauses 1) input---- |read a CNF file and return:--- ((numbefOfVariables, numberOfClauses), [Literal])------ >>> fromFile "acnf"--- ((3, 4), [[1, 2], [-2, 3], [-1, 2, -3], [3]]----{-# INLINE fromFile #-}-fromFile :: FilePath -> IO (Maybe ((Int, Int), [[Int]]))-fromFile f = do-  c <- readFile f-  case readP_to_S parseCNF c of-    [(a, _)] -> return $ Just a-    _ -> return Nothing---- | return clauses as [[Int]] from 'file'------ >>> clauseListFromFile "a.cnf"--- [[1, 2], [-2, 3], [-1, 2, -3], [3]]----clauseListFromFile :: FilePath -> IO [[Int]]-clauseListFromFile l = do-  res <- fromFile l-  case res of-    Just (_, l) -> return l-    _ -> return []
− SAT/Mios/Util/DIMACS/Writer.hs
@@ -1,58 +0,0 @@-{-# LANGUAGE Safe #-}---- | Write SAT data to DIMACS file-module SAT.Mios.Util.DIMACS.Writer-       (-         -- * Interface-         toFile-       , toDIMACSString-       , toString-       , toLatexString-       )-       where-import Data.List (intercalate, nub, sort)-import System.IO---- | Write the DIMACS to file 'f', using 'toDIMACSString'-toFile :: FilePath -> [[Int]] -> IO ()-toFile f l = writeFile f $ toDIMACSString l---- | Convert [Clause] to String, where Clause is [Int]------ >>> toDIMACSString []--- "p cnf 0 0\n"------ >>> toDIMACSString [[-1, 2], [-3, -4]]--- "p cnf 4 2\n-1 2 0\n-3 -4 0\n"------ >>> toDIMACSString [[1], [-2], [-3, -4], [1,2,3,4]]--- "p cnf 4 4\n1 0\n-2 0\n-3 -4 0\n1 2 3 4 0\n"----toDIMACSString :: [[Int]] -> String-toDIMACSString l = hdr ++ str-  where-    hdr = "p cnf " ++ show numV ++ " " ++ show numC ++ "\n"-    numC = length l-    numV = last $ nub $ sort $ map abs $ concat l-    str = concat [intercalate " " (map show c) ++ " 0\n" | c <- l]---- | converts @[[Int]]@ to a String-toString  :: [[Int]] -> String -> String -> String-toString l and' or' = intercalate a ["(" ++ intercalate o [ lit x | x <- c] ++ ")" | c <- l]-  where-    lit x-      | 0 <= x = "X" ++ show x-      | otherwise = "-X" ++ show (abs x)-    a = pad and'-    o = pad or'-    pad s = " " ++ s ++ " "---- | converts @[[Int]]@ to a LaTeX expression-toLatexString  :: [[Int]] -> String-toLatexString l = "\\begin{eqnarray*}\n" ++ intercalate a ["(" ++ intercalate o [ lit x | x <- c] ++ ")" | c <- l] ++ "\n\\end{eqnarray*}"-  where-    lit x-      | 0 <= x = "X_{" ++ show x ++ "}"-      | otherwise = "\\overline{X_{" ++ show (abs x) ++ "}}"-    a = " \n\\wedge "-    o = " \\vee "
− SAT/Mios/Validator.hs
@@ -1,47 +0,0 @@-{-# LANGUAGE-    ViewPatterns-  #-}-{-# LANGUAGE Safe #-}---- | validate an assignment-module SAT.Mios.Validator-       (-         validate-       )-       where--import Data.Foldable (toList)-import SAT.Mios.Types-import SAT.Mios.Clause-import SAT.Mios.ClauseManager-import SAT.Mios.Solver---- | validates the assignment even if the implementation of 'Solver' is wrong; we re-implement some functions here.-validate :: Traversable t => Solver -> t Int -> IO Bool-validate s (toList -> map int2lit -> lst) = do-  assignment <- newVec (1 + nVars s) (0 :: Int) :: IO (Vec Int)-  vec <- getClauseVector (clauses s)-  nc <- get' (clauses s)-  let-    inject :: Lit -> IO ()-    inject l = setNth assignment (lit2var l) $ if positiveLit l then lTrue else lFalse-    -- returns True if the literal is satisfied under the assignment-    satisfied :: Lit -> IO Bool-    satisfied l-      | positiveLit l = (lTrue ==) <$> getNth assignment (lit2var l)-      | otherwise     = (lFalse ==) <$> getNth assignment (lit2var l)-    -- returns True is any literal in the given list-    satAny :: [Lit] -> IO Bool-    satAny [] = return False-    satAny (l:ls) = do-      sat' <- satisfied l-      if sat' then return True else satAny ls-    -- traverses all clauses in 'clauses'-    loopOnVector :: Int -> IO Bool-    loopOnVector ((< nc) -> False) = return True-    loopOnVector i = do-      sat' <- satAny =<< asList =<< getNth vec i-      if sat' then loopOnVector (i + 1) else return False-  if null lst-    then error "validator got an empty assignment."-    else mapM_ inject lst >> loopOnVector 0
− SAT/Mios/Vec.hs
@@ -1,276 +0,0 @@-{-# LANGUAGE-    BangPatterns-  , FlexibleContexts-  , FlexibleInstances-  , FunctionalDependencies-  , MultiParamTypeClasses-  , TypeFamilies-  #-}-{-# LANGUAGE Trustworthy #-}---- | Abstraction Layer for Mutable Vectors-module SAT.Mios.Vec-       (-         -- * Vector class-         VecFamily (..)-         -- * Vectors-       , UVector-       , Vec (..)-         -- * SingleStorage-       , SingleStorage (..)-       , Bool'-       , Double'-       , Int'-         -- * Stack-       , StackFamily (..)-       , Stack-       , newStackFromList-       )-       where--import qualified Data.Vector.Unboxed as U-import qualified Data.Vector.Unboxed.Mutable as UV---- | Interface on vectors.-class VecFamily v a | v -> a where-  -- | returns the /n/-th value.-  getNth ::v -> Int -> IO a-  -- | sets the /n/-th value.-  setNth :: v -> Int -> a -> IO ()-  -- | erases all elements in it.-  reset:: v -> IO ()-  -- | converts to an Int vector.-  asUVector :: (a ~ Int) => v -> UVector Int-  -- | returns the /n/-th value (index starts from zero in any case).-  -- | swaps two elements.-  swapBetween :: v -> Int -> Int -> IO ()-  -- | calls the update function.-  modifyNth :: v -> (a -> a) -> Int -> IO ()-  -- | returns a new vector.-  newVec :: Int -> a -> IO v-  -- | sets all elements.-  setAll :: v -> a -> IO ()-  -- | extends the size of stack by /n/; note: values in new elements aren't initialized maybe.-  growBy :: v -> Int -> IO v-  -- | converts to a list.-  asList :: v -> IO [a]-  {-# MINIMAL getNth, setNth #-}-  reset = error "no default method: reset"-  asUVector = error "no default method: asUVector"-  swapBetween = error "no default method: swapBetween"-  modifyNth = error "no default method: modifyNth"-  newVec = error "no default method: newVec"-  setAll = error "no default method: setAll"-  asList = error "no default method: asList"-  growBy = error "no default method: growBy"-{--  -- | (FOR DEBUG) dump the contents.-  dump :: Show a => String -> v -> IO String-  dump msg v = (msg ++) . show <$> asList v--}---------------------------------------------------------------------------------- UVector---- | A thin abstract layer for Mutable unboxed Vector-type UVector a = UV.IOVector a--instance VecFamily (UVector Int) Int where-  {-# SPECIALIZE INLINE getNth :: UVector Int -> Int -> IO Int #-}-  getNth = UV.unsafeRead-  {-# SPECIALIZE INLINE setNth :: UVector Int -> Int -> Int -> IO () #-}-  setNth = UV.unsafeWrite-  {-# SPECIALIZE INLINE modifyNth :: UVector Int -> (Int -> Int) -> Int -> IO () #-}-  modifyNth = UV.unsafeModify-  {-# SPECIALIZE INLINE swapBetween:: UVector Int -> Int -> Int -> IO () #-}-  swapBetween = UV.unsafeSwap-  {-# SPECIALIZE INLINE newVec :: Int -> Int -> IO (UVector Int) #-}-  newVec n 0 = UV.new n-  newVec n x = do-    v <- UV.new n-    UV.set v x-    return v-  {-# SPECIALIZE INLINE setAll :: UVector Int -> Int -> IO () #-}-  setAll = UV.set-  {-# SPECIALIZE INLINE growBy :: UVector Int -> Int -> IO (UVector Int) #-}-  growBy = UV.unsafeGrow-  asList v = mapM (UV.unsafeRead v) [0 .. UV.length v - 1]--instance VecFamily (UVector Double) Double where-  {-# SPECIALIZE INLINE getNth :: UVector Double -> Int -> IO Double #-}-  getNth = UV.unsafeRead-  {-# SPECIALIZE INLINE setNth :: UVector Double -> Int -> Double -> IO () #-}-  setNth = UV.unsafeWrite-  {-# SPECIALIZE INLINE modifyNth :: UVector Double -> (Double -> Double) -> Int -> IO () #-}-  modifyNth = UV.unsafeModify-  {-# SPECIALIZE INLINE swapBetween:: UVector Double -> Int -> Int -> IO () #-}-  swapBetween = UV.unsafeSwap-  {-# SPECIALIZE INLINE newVec :: Int -> Double -> IO (UVector Double) #-}-  newVec n x = do-    v <- UV.new n-    UV.set v x-    return v-  {-# SPECIALIZE INLINE setAll :: UVector Double -> Double -> IO () #-}-  setAll = UV.set-  {-# SPECIALIZE INLINE growBy :: UVector Double -> Int -> IO (UVector Double) #-}-  growBy = UV.unsafeGrow-  asList v = mapM (UV.unsafeRead v) [0 .. UV.length v - 1]---------------------------------------------------------------------------------- Vec---- | Another abstraction layer on 'UVector'.------ __Note__: the 0-th element of @Vec Int@ is reserved for internal tasks. If you want to use it, use @UVector Int@.-newtype Vec a  = Vec (UVector a)--instance VecFamily (Vec Int) Int where-  {-# SPECIALIZE INLINE getNth :: Vec Int -> Int -> IO Int #-}-  getNth (Vec v) = UV.unsafeRead v-  {-# SPECIALIZE INLINE setNth :: Vec Int -> Int -> Int -> IO () #-}-  setNth (Vec v) = UV.unsafeWrite v-  {-# SPECIALIZE INLINE reset :: Vec Int -> IO () #-}-  reset (Vec v) = setNth v 0 0-  {-# SPECIALIZE INLINE asUVector :: Vec Int -> UVector Int #-}-  asUVector (Vec a) = UV.unsafeTail a-  {-# SPECIALIZE INLINE modifyNth :: Vec Int -> (Int -> Int) -> Int -> IO () #-}-  modifyNth (Vec v) = UV.unsafeModify v-  {-# SPECIALIZE INLINE swapBetween :: Vec Int -> Int -> Int -> IO () #-}-  swapBetween (Vec v) = UV.unsafeSwap v-  {-# SPECIALIZE INLINE newVec :: Int -> Int -> IO (Vec Int) #-}-  newVec n x = Vec <$> newVec (n + 1) x-  {-# SPECIALIZE INLINE setAll :: Vec Int -> Int -> IO () #-}-  setAll (Vec v) = UV.set v-  {-# SPECIALIZE INLINE growBy :: Vec Int -> Int -> IO (Vec Int) #-}-  growBy (Vec v) n = Vec <$> UV.unsafeGrow v n-  asList (Vec v) = mapM (getNth v) [1 .. UV.length v - 1]--instance VecFamily (Vec Double) Double where-  {-# SPECIALIZE INLINE getNth :: Vec Double -> Int -> IO Double #-}-  getNth (Vec v) = UV.unsafeRead v-  {-# SPECIALIZE INLINE setNth :: Vec Double -> Int -> Double -> IO () #-}-  setNth (Vec v) = UV.unsafeWrite v-  {-# SPECIALIZE INLINE modifyNth :: Vec Double -> (Double -> Double) -> Int -> IO () #-}-  modifyNth (Vec v) = UV.unsafeModify v-  {-# SPECIALIZE INLINE swapBetween :: Vec Double -> Int -> Int -> IO () #-}-  swapBetween (Vec v) = UV.unsafeSwap v-  {-# SPECIALIZE INLINE newVec :: Int -> Double -> IO (Vec Double) #-}-  newVec n x = Vec <$> newVec (n + 1) x-  {-# SPECIALIZE INLINE setAll :: Vec Double -> Double -> IO () #-}-  setAll (Vec v) = UV.set v-  {-# SPECIALIZE INLINE growBy :: Vec Double -> Int -> IO (Vec Double) #-}-  growBy (Vec v) n = Vec <$> UV.unsafeGrow v n---------------------------------------------------------------------------------- SingleStorage---- | Interface for single mutable data-class SingleStorage s t | s -> t where-  -- | allocates and returns an new data.-  new' :: t -> IO s-  -- | gets the value.-  get' :: s -> IO t-  -- | sets the value.-  set' :: s -> t -> IO ()-  -- | calls an update function on it.-  modify' :: s -> (t -> t) -> IO ()-  {-# MINIMAL get', set' #-}-  new' = undefined-  modify' = undefined---- | Mutable Int--- __Note:__  Int' is the same with 'Stack'-type Int' = UV.IOVector Int--instance SingleStorage Int' Int where-  {-# SPECIALIZE INLINE new' :: Int -> IO Int' #-}-  new' k = do-    s <- UV.new 1-    UV.unsafeWrite s 0 k-    return s-  {-# SPECIALIZE INLINE get' :: Int' -> IO Int #-}-  get' val = UV.unsafeRead val 0-  {-# SPECIALIZE INLINE set' :: Int' -> Int -> IO () #-}-  set' val !x = UV.unsafeWrite val 0 x-  {-# SPECIALIZE INLINE modify' :: Int' -> (Int -> Int) -> IO () #-}-  modify' val f = UV.unsafeModify val f 0---- | Mutable Bool-type Bool' = UV.IOVector Bool--instance SingleStorage Bool' Bool where-  {-# SPECIALIZE INLINE new' :: Bool -> IO Bool' #-}-  new' k = do-    s <- UV.new 1-    UV.unsafeWrite s 0 k-    return s-  {-# SPECIALIZE INLINE get' :: Bool' -> IO Bool #-}-  get' val = UV.unsafeRead val 0-  {-# SPECIALIZE INLINE set' :: Bool' -> Bool -> IO () #-}-  set' val !x = UV.unsafeWrite val 0 x-  {-# SPECIALIZE INLINE modify' :: Bool' -> (Bool -> Bool) -> IO () #-}-  modify' val f = UV.unsafeModify val f 0---- | Mutable Double-type Double' = UV.IOVector Double--instance SingleStorage Double' Double where-  {-# SPECIALIZE INLINE new' :: Double -> IO Double' #-}-  new' k = do-    s <- UV.new 1-    UV.unsafeWrite s 0 k-    return s-  {-# SPECIALIZE INLINE get' :: Double' -> IO Double #-}-  get' val = UV.unsafeRead val 0-  {-# SPECIALIZE INLINE set' :: Double' -> Double -> IO () #-}-  set' val !x = UV.unsafeWrite val 0 x-  {-# SPECIALIZE INLINE modify' :: Double' -> (Double -> Double) -> IO () #-}-  modify' val f = UV.unsafeModify val f 0---------------------------------------------------------------------------------- Stack---- | Interface on stacks-class SingleStorage s Int => StackFamily s t | s -> t where-  -- | returns a new stack.-  newStack :: Int -> IO s-  -- | pushs an value to the tail of the stack.-  pushTo :: s -> t-> IO ()-  -- | pops the last element.-  popFrom :: s -> IO ()-  -- | peeks the last element.-  lastOf :: s -> IO t-  -- | shrinks the stack.-  shrinkBy :: s -> Int -> IO ()-  newStack = undefined-  pushTo = undefined-  popFrom = undefined-  lastOf = undefined-  shrinkBy = undefined---- | Alias of @Vec Int@. The 0-th element holds the number of elements.-type Stack = Vec Int--instance SingleStorage Stack Int where-  {-# SPECIALIZE INLINE get' :: Stack -> IO Int #-}-  get' (Vec v) = UV.unsafeRead v 0-  {-# SPECIALIZE INLINE set' :: Stack -> Int -> IO () #-}-  set' (Vec v) !x = UV.unsafeWrite v 0 x-  {-# SPECIALIZE INLINE modify' :: Stack -> (Int -> Int) -> IO () #-}-  modify' (Vec v) f = UV.unsafeModify v f 0--instance StackFamily Stack Int where-  {-# SPECIALIZE INLINE newStack :: Int -> IO Stack #-}-  newStack n = newVec n 0-  {-# SPECIALIZE INLINE pushTo :: Stack -> Int -> IO () #-}-  pushTo (Vec v) x = do-    i <- (+ 1) <$> UV.unsafeRead v 0-    UV.unsafeWrite v i x-    UV.unsafeWrite v 0 i-  {-# SPECIALIZE INLINE popFrom :: Stack -> IO () #-}-  popFrom (Vec v) = UV.unsafeModify v (subtract 1) 0-  {-# SPECIALIZE INLINE lastOf :: Stack -> IO Int #-}-  lastOf (Vec v) = UV.unsafeRead v =<< UV.unsafeRead v 0-  {-# SPECIALIZE INLINE shrinkBy :: Stack -> Int -> IO () #-}-  shrinkBy (Vec v) k = UV.unsafeModify v (subtract k) 0---- | returns a new 'Stack' from @[Int]@.-{-# INLINABLE newStackFromList #-}-newStackFromList :: [Int] -> IO Stack-newStackFromList !l = Vec <$> U.unsafeThaw (U.fromList (length l : l))
app/mios.hs view
@@ -1,3 +1,6 @@+{-# LANGUAGE+   MultiWayIf+  #-} -- | Executable of 'Minisat Implementation and Optimization Study' module Main        (@@ -7,14 +10,15 @@  import SAT.Mios +usage :: String+usage = miosUsage $ versionId ++ "\nUsage: mios [OPTIONS] target.cnf"+ -- | main main :: IO ()-main = do-  opts <- miosParseOptionsFromArgs versionId-  case () of-    _ | _displayVersion opts        -> putStrLn versionId-    _ | _displayHelp opts           -> putStrLn $ miosUsage $ versionId ++ "\nUsage: mios [OPTIONS] target.cnf"-    _ | _targetFile opts == Just "" -> putStrLn $ miosUsage $ versionId ++ "\nUsage: mios [OPTIONS] target.cnf"-    _ | _validateAssignment opts    -> executeValidator opts-    _ | otherwise                   -> executeSolver opts+main = do opts <- miosParseOptionsFromArgs versionId+          if | _displayVersion opts        -> putStrLn versionId+             | _displayHelp opts           -> putStrLn usage+             | _targetFile opts == Nothing -> putStrLn usage+             | _validateAssignment opts    -> executeValidator opts+             | otherwise                   -> executeSolver opts 
mios.cabal view
@@ -2,13 +2,12 @@ -- see http://haskell.org/cabal/users-guide/  name:                   mios-version:                1.4.0-synopsis:               A Minisat-based SAT solver in Haskell+version:                1.5.4+synopsis:               A Minisat-based CDCL SAT solver in Haskell description: -  A modern and fast SAT solver written in Haskell, based on Minisat-1.14 and 2.2.-  By using CDCL, watch literals, VSIDS, restart, blocking-literals, LBD and so on.-  The current version is only 2.0 time slower than Minisat-2.2.+  A modern and very fast SAT solver written in Haskell, using CDCL, watch literals, VSIDS,+  blocking-literals, phase saving, LBD, Glucose-like restart and so on.   'Mios' is an abbreviation of 'Minisat-based Implementation and Optimization Study on SAT solver'.   . @@ -20,7 +19,7 @@ category:               Artificial Intelligence, Constraints build-type:             Simple cabal-version:          >=1.16-extra-source-files:  app/sample.hs+extra-source-files:     app/sample.hs  source-repository head   type:                 git@@ -30,38 +29,41 @@   Description:	        Compile with llvm   Default:	        False -Flag lib-  Description:	        Build the solver library-  Default:	        True+Flag MultiConflict+  Description:	        Build tools in MultiConflict+  Default:	        False +Flag utils+  Description:	        Build misc utilities for developer+  Default:	        False+ library-  if flag(lib)-    buildable:	        True-  else-    buildable:	        False+  hs-source-dirs:	src   default-language:	Haskell2010   default-extensions:   Strict-  other-extensions:	    BangPatterns-                            FlexibleContexts-                            FlexibleInstances-                            FunctionalDependencies-                            MagicHash-                            MultiParamTypeClasses-                            RecordWildCards-                            ScopedTypeVariables-                            TypeFamilies-                            Trustworthy-                            TupleSections-                            Safe-                            UndecidableInstances-                            ViewPatterns+  other-extensions:	BangPatterns+                        FlexibleContexts+                        FlexibleInstances+                        FunctionalDependencies+                        MagicHash+                        MultiParamTypeClasses+                        RecordWildCards+                        ScopedTypeVariables+                        TypeFamilies+                        Trustworthy+                        TupleSections+                        Safe+                        UndecidableInstances+                        ViewPatterns   exposed-modules:                         SAT.Mios.Clause                         SAT.Mios.ClauseManager-                        SAT.Mios.Vec+                        SAT.Mios.ClausePool+                        SAT.Mios.Criteria                         SAT.Mios.Main                         SAT.Mios.OptionParser                         SAT.Mios.Solver+                        SAT.Mios.Vec                         SAT.Mios.Types                         SAT.Mios.Validator                         SAT.Mios.Util.DIMACS.MinisatReader@@ -70,29 +72,119 @@                         SAT.Mios.Util.DIMACS                         SAT.Mios.Util.BoolExp                         SAT.Mios-  build-depends:        base ==4.9.*, vector >=0.11, ghc-prim >=0.5, bytestring >=0.10+  build-depends:        base >=4.10 && < 5, vector >=0.12, ghc-prim >=0.5, bytestring >=0.10, primitive >=0.6   if flag(llvm)-    ghc-options:	-O2 -ignore-asserts -funbox-strict-fields -fllvm -optlo-O3+    ghc-options:	-O2 -funbox-strict-fields -fllvm -optlo-O3 -optlc-O3 -fwarn-missing-signatures   else-    ghc-options:	-O2 -ignore-asserts -funbox-strict-fields+    ghc-options:	-O2 -funbox-strict-fields -msse2 -fwarn-missing-signatures -executable mios-  main-is:              app/mios.hs+executable mios-1.5.4+  hs-source-dirs:	app+  main-is:              mios.hs   buildable:	        True   default-language:	Haskell2010-  default-extensions:  Strict-  build-depends:        base ==4.9.*,  vector >=0.11, ghc-prim >=0.5, bytestring >=0.10+  default-extensions:   Strict+  build-depends:        base >=4.10 && < 5, mios   if flag(llvm)-    ghc-options:	-O2 -ignore-asserts -funbox-strict-fields -fllvm -optlo-O3+    ghc-options:	-O2 -funbox-strict-fields -fllvm -optlo-O3 -optlc-O3 -rtsopts -fwarn-missing-signatures   else+    ghc-options:	-O2 -funbox-strict-fields -msse2 -rtsopts -fwarn-missing-signatures++executable cnf-stat+  hs-source-dirs:	utils+  main-is:              cnf-stat.hs+  if flag(utils)+    buildable:	        True+  else+    buildable:	        False+  default-language:	Haskell2010+  default-extensions:   Strict+  build-depends:        base >=4.10 && < 5, mios, bytestring >=0.10+  ghc-options:	        -O1 -ignore-asserts -funbox-strict-fields++executable mios-mc+  hs-source-dirs:	MultiConflict app+  main-is:              mios.hs+  if flag(MultiConflict)+    buildable:	        True+  else+    buildable:	        False+  default-language:	Haskell2010+  default-extensions:   Strict+  build-depends:        base >=4.10 && < 5, mios, bytestring >=0.10+  if flag(llvm)+    ghc-options:	-O2 -ignore-asserts -funbox-strict-fields -fllvm -optlo-O2 -optlc-O2+  else     ghc-options:	-O2 -ignore-asserts -funbox-strict-fields-  other-modules:-                        SAT.Mios.Clause-                        SAT.Mios.ClauseManager-                        SAT.Mios.Vec-                        SAT.Mios.Main-                        SAT.Mios.OptionParser-                        SAT.Mios.Solver-                        SAT.Mios.Types-                        SAT.Mios.Validator-                        SAT.Mios++executable mc-dump2csv+  hs-source-dirs:	MultiConflict+  main-is:              utils/dump2csv.hs+  if flag(MultiConflict) && flag(utils)+    buildable:	        True+  else+    buildable:	        False+  default-language:	Haskell2010+  default-extensions:   Strict+  build-depends:        base >=4.10 && < 5, mios, bytestring >=0.10+  ghc-options:	        -O1 -ignore-asserts -funbox-strict-fields++executable mc-averagecsv+  hs-source-dirs:	MultiConflict+  main-is:              utils/averagecsv.hs+  if flag(MultiConflict) && flag(utils)+    buildable:	        True+  else+    buildable:	        False+  default-language:	Haskell2010+  default-extensions:   Strict+  build-depends:        base >=4.10 && < 5, mios, bytestring >=0.10+  ghc-options:	        -O1 -ignore-asserts -funbox-strict-fields++executable mc-summary+  hs-source-dirs:	MultiConflict+  main-is:              utils/summary.hs+  if flag(MultiConflict) && flag(utils)+    buildable:	        True+  else+    buildable:	        False+  default-language:	Haskell2010+  default-extensions:   Strict+  build-depends:        base >=4.10 && < 5, mios, bytestring >=0.10+  ghc-options:	        -O1 -ignore-asserts -funbox-strict-fields++executable mc-stat2csv+  hs-source-dirs:	MultiConflict+  main-is:              utils/stat2csv.hs+  if flag(MultiConflict) && flag(utils)+    buildable:	        True+  else+    buildable:	        False+  default-language:	Haskell2010+  default-extensions:   Strict+  build-depends:        base >=4.10 && < 5, mios, bytestring >=0.10+  ghc-options:	        -O1 -ignore-asserts -funbox-strict-fields++executable mc-pickup+  hs-source-dirs:	MultiConflict+  main-is:              utils/pickup.hs+  if flag(MultiConflict) && flag(utils)+    buildable:	        True+  else+    buildable:	        False+  default-language:	Haskell2010+  default-extensions:   Strict+  build-depends:        base >=4.10 && < 5, mios, bytestring >=0.10+  ghc-options:	        -O1 -ignore-asserts -funbox-strict-fields++executable mc-numbers+  hs-source-dirs:	MultiConflict+  main-is:              utils/numbers.hs+  if flag(MultiConflict) && flag(utils)+    buildable:	        True+  else+    buildable:	        False+  default-language:	Haskell2010+  default-extensions:   Strict+  build-depends:        base >=4.10 && < 5, mios, bytestring >=0.10+  ghc-options:	        -O1 -ignore-asserts -funbox-strict-fields
+ src/SAT/Mios.hs view
@@ -0,0 +1,335 @@+-- | (This file is a part of MIOS.)+-- Minisat-based Implementation and Optimization Study on SAT solver+{-# LANGUAGE+    BangPatterns+  , LambdaCase+  , ViewPatterns+#-}+{-# LANGUAGE Safe #-}++module SAT.Mios+       (+         -- * Interface to the core of solver+         versionId+       , CNFDescription (..)+       , module SAT.Mios.OptionParser+       , runSolver+       , solveSAT+       , solveSATWithConfiguration+       , solve+       , SolverResult+       , Certificate (..)+         -- * Assignment Validator+       , validateAssignment+       , validate+         -- * For standalone programs+       , executeSolverOn+       , executeSolver+       , executeValidatorOn+       , executeValidator+         -- * File IO+       , parseCNF+       , injectClausesFromCNF+       , dumpAssigmentAsCNF+       )+       where++import Control.Concurrent (forkIO, killThread, myThreadId, threadDelay+                          , newEmptyMVar, putMVar, readMVar)+import Control.Exception+import Control.Monad ((<=<), unless, void, when)+import Data.Char+import qualified Data.ByteString.Char8 as B+import Numeric (showFFloat)+import System.CPUTime+import System.Exit+import System.IO++import SAT.Mios.Types+import SAT.Mios.Main+import SAT.Mios.OptionParser+import SAT.Mios.Validator++-- | version name+versionId :: String+versionId = "mios-1.5.4 -- https://github.com/shnarazk/mios"++reportElapsedTime :: Bool -> String -> Integer -> IO Integer+reportElapsedTime False _ 0 = return 0+reportElapsedTime False _ _ = getCPUTime+reportElapsedTime True mes t = do+  now <- getCPUTime+  let toSecond = 1000000000000 :: Double+  hPutStr stderr mes+  hPutStrLn stderr $ showFFloat (Just 3) (fromIntegral (now - t) / toSecond) " sec"+  return now++-- | executes a solver on the given CNF file.+-- This is the simplest entry to standalone programs; not for Haskell programs.+executeSolverOn :: FilePath -> IO ()+executeSolverOn path = executeSolver (miosDefaultOption { _targetFile = Just path })++-- | executes a solver on the given 'arg :: MiosConfiguration'.+-- This is another entry point for standalone programs.+executeSolver :: MiosProgramOption -> IO ()+executeSolver opts@(_targetFile -> (Just cnfFile)) = do+  t0 <- reportElapsedTime False "" $ if _confVerbose opts || 0 <= _confBenchmark opts then -1 else 0+  (desc, cls) <- parseCNF (_targetFile opts)+  -- when (_numberOfVariables desc == 0) $ error $ "couldn't load " ++ show cnfFile+  token <- newEmptyMVar --  :: IO (MVar (Maybe Solver))+  solverId <- myThreadId+  handle (\case+             UserInterrupt -> putStrLn "User interrupt recieved."+             ThreadKilled  -> reportResult opts t0 =<< readMVar token+             e -> print e) $ do+    when (0 < _confBenchmark opts) $+      void $ forkIO $ do let fromMicro = 1000000 :: Int+                         threadDelay $ fromMicro * fromIntegral (_confBenchmark opts)+                         putMVar token (Left TimeOut)+                         killThread solverId+    when (_confMaxSize opts < _numberOfVariables desc) $+      if -1 == _confBenchmark opts+        then errorWithoutStackTrace $ "ABORT: too many variables to solve, " ++ show desc+        else putMVar token (Left OutOfMemory) >> killThread solverId+    s <- newSolver (toMiosConf opts) desc+    injectClausesFromCNF s desc cls+    void $ reportElapsedTime (_confVerbose opts) ("## [" ++ showPath cnfFile ++ "] Parse: ") t0+    when (0 < _confDumpStat opts) $ dumpSolver DumpCSVHeader s+    result <- solve s []+    putMVar token result+    killThread solverId++executeSolver _ = return ()++-- | print messages on solver's result+-- Note: the last field of benchmark CSV is:+--   * 0 if UNSAT+--   * 1 if satisfiable (by finding an assignment)+--   * other bigger values are used for aborted cases.+reportResult :: MiosProgramOption -> Integer -> SolverResult -> IO ()+-- abnormal cases, catching 'too large CNF', 'timeout' for now.+reportResult opts@(_targetFile -> Just cnfFile) _ (Left flag) =+  putStrLn ("\"" ++ takeWhile (' ' /=) versionId ++ "\","+             ++ show (_confBenchSeq opts) ++ ","+             ++ "\"" ++ cnfFile ++ "\","+             ++ show (_confBenchmark opts) ++ "," ++ show (fromEnum flag))++-- solver terminated normally+reportResult opts@(_targetFile -> Just cnfFile) t0 (Right result) = do+  t2 <- reportElapsedTime (_confVerbose opts) ("## [" ++ showPath cnfFile ++ "] Total: ") t0+  case result of+    _ | 0 <= _confBenchmark opts -> return ()+    SAT _   | _confNoAnswer opts -> when (_confVerbose opts) $ hPutStrLn stderr "SATISFIABLE"+    UNSAT _ | _confNoAnswer opts -> when (_confVerbose opts) $ hPutStrLn stderr "UNSATISFIABLE"+    SAT asg -> print asg+    UNSAT t -> do when (_confVerbose opts) $ hPutStrLn stderr "UNSAT" -- contradiction+                  print t+  dumpAssigmentAsCNF (_outputFile opts) result+  valid <- if _confCheckAnswer opts || 0 <= _confBenchmark opts+           then case result of+                  SAT asg -> do (desc, cls) <- parseCNF (_targetFile opts)+                                s' <- newSolver (toMiosConf opts) desc+                                injectClausesFromCNF s' desc cls+                                validate s' asg+                  UNSAT _ -> return True+           else return True+  when (_confCheckAnswer opts) $ do+    if _confVerbose opts+      then hPutStrLn stderr $ if valid then "A vaild answer" else "Internal error: mios returns a wrong answer"+      else unless valid $ hPutStrLn stderr "Internal error: mios returns a wrong answer"+    void $ reportElapsedTime (_confVerbose opts) ("## [" ++ showPath cnfFile ++ "] Validate: ") t2+  when (0 <= _confBenchmark opts) $ do+    let fromPico = 1000000000000 :: Double+        phase = case result of { SAT _   -> 1; UNSAT _ -> 0::Int }+    putStrLn $ "\"" ++ takeWhile (' ' /=) versionId ++ "\","+      ++ show (_confBenchSeq opts) ++ ","+      ++ "\"" ++ cnfFile ++ "\","+      ++ if valid+         then showFFloat (Just 3) (fromIntegral (t2 - t0) / fromPico) "," ++ show phase+         else show (_confBenchmark opts) ++ "," ++ show (fromEnum InternalInconsistent)++reportResult _ _ _ = return ()++-- | new top-level interface that returns:+--+-- * conflicting literal set :: Left [Int]+-- * satisfiable assignment :: Right [Int]+--+runSolver :: Traversable t => MiosConfiguration -> CNFDescription -> t [Int] -> IO (Either [Int] [Int])+runSolver m d c = do+  s <- newSolver m d+  mapM_ ((s `addClause`) <=< (newStackFromList . map int2lit)) c+  noConf <- simplifyDB s+  if noConf+    then do+        x <- solve s []+        case x of+          Right (SAT a)   -> return $ Right a+          Right (UNSAT a) -> return $ Left a+          _ -> return $ Left []+    else return $ Left []++-- | The easiest interface for Haskell programs.+-- This returns the result @::[[Int]]@ for a given @(CNFDescription, [[Int]])@.+-- The first argument @target@ can be build by @Just target <- cnfFromFile targetfile@.+-- The second part of the first argument is a list of vector, which 0th element is the number of its real elements.+solveSAT :: Traversable m => CNFDescription -> m [Int] -> IO [Int]+solveSAT = solveSATWithConfiguration defaultConfiguration++-- | solves the problem (2rd arg) under the configuration (1st arg).+-- and returns an assignment as list of literals :: Int.+solveSATWithConfiguration :: Traversable m => MiosConfiguration -> CNFDescription -> m [Int] -> IO [Int]+solveSATWithConfiguration conf desc cls = do+  s <- newSolver conf desc+  -- mapM_ (const (newVar s)) [0 .. _numberOfVariables desc - 1]+  mapM_ ((s `addClause`) <=< (newStackFromList . map int2lit)) cls+  noConf <- simplifyDB s+  if noConf+    then do result <- solve s []+            case result of+              Right (SAT a) -> return a+              _             -> return []+    else return []++-- | validates a given assignment from STDIN for the CNF file (2nd arg).+-- this is the entry point for standalone programs.+executeValidatorOn :: FilePath -> IO ()+executeValidatorOn path = executeValidator (miosDefaultOption { _targetFile = Just path })++-- | validates a given assignment for the problem (2nd arg).+-- This is another entry point for standalone programs; see app/mios.hs.+executeValidator :: MiosProgramOption -> IO ()+executeValidator opts@(_targetFile -> target@(Just cnfFile)) = do+  (desc, cls) <- parseCNF target+  when (_numberOfVariables desc == 0) . error $ "couldn't load " ++ show cnfFile+  s <- newSolver (toMiosConf opts) desc+  injectClausesFromCNF s desc cls+  when (_confVerbose opts) $+    hPutStrLn stderr $ cnfFile ++ " was loaded: #v = " ++ show (_numberOfVariables desc) ++ " #c = " ++ show (_numberOfClauses desc)+  asg <- read <$> getContents+  unless (_confNoAnswer opts) $ print asg+  result <- s `validate` (asg :: [Int])+  if result+    then putStrLn ("It's a valid assignment for " ++ cnfFile ++ ".") >> exitSuccess+    else putStrLn ("It's an invalid assignment for " ++ cnfFile ++ ".") >> exitFailure++executeValidator _  = return ()++-- | returns True if a given assignment (2nd arg) satisfies the problem (1st arg).+-- if you want to check the @answer@ which a @slover@ returned, run @solver `validate` answer@,+-- where 'validate' @ :: Traversable t => Solver -> t Lit -> IO Bool@.+validateAssignment :: (Traversable m, Traversable n) => CNFDescription -> m [Int] -> n Int -> IO Bool+validateAssignment desc cls asg = do+  s <- newSolver defaultConfiguration desc+  mapM_ ((s `addClause`) <=< (newStackFromList . map int2lit)) cls+  s `validate` asg++-- | dumps an assigment to file.+-- 2nd arg is+--+-- * @True@ if the assigment is satisfiable assigment+--+-- * @False@ if not+--+-- >>> do y <- solve s ... ; dumpAssigmentAsCNF (Just "result.cnf") y <$> model s+--+dumpAssigmentAsCNF :: Maybe FilePath -> Certificate -> IO ()+dumpAssigmentAsCNF Nothing _ = return ()+-- | FIXME: swtich to DRAT+dumpAssigmentAsCNF (Just fname) (UNSAT _) =+  writeFile fname "s UNSAT\n0\n"+dumpAssigmentAsCNF (Just fname) (SAT l) =+  withFile fname WriteMode $ \h -> do hPutStrLn h "s SAT"; hPutStrLn h . (++ " 0") . unwords $ map show l++--------------------------------------------------------------------------------+-- DIMACS CNF Reader+--------------------------------------------------------------------------------++-- | parses the header of a CNF file+parseCNF :: Maybe FilePath -> IO (CNFDescription, B.ByteString)+parseCNF target@(Just cnfFile) = do+  let -- format: p cnf n m, length "p cnf" == 5+      parseP line = case parseInt (skipWhitespace (B.drop 5 line)) of+                      (x, second) -> case B.readInt (skipWhitespace second) of+                                       Just (y, _) -> CNFDescription x y target+      seek :: B.ByteString -> IO (CNFDescription, B.ByteString)+      seek bs+        | B.head bs == 'p' = return (parseP l, B.tail bs')+        | otherwise = seek (B.tail bs')+        where (l, bs') = B.span ('\n' /=) bs+  seek =<< B.readFile cnfFile++-- | parses ByteString then injects the clauses in it into a solver+injectClausesFromCNF :: Solver -> CNFDescription -> B.ByteString -> IO ()+injectClausesFromCNF s (CNFDescription nv nc _) bs = do+  let maxLit = int2lit $ negate nv+  buffer <- newVec (maxLit + 1) 0+  polvec <- newVec (maxLit + 1) 0+  let loop :: Int -> B.ByteString -> IO ()+      loop ((< nc) -> False) _ = return ()+      loop !i !b = loop (i + 1) =<< readClause s buffer polvec b+  loop 0 bs+  -- static polarity+  let checkPolarity :: Int -> IO ()+      checkPolarity ((< nv) -> False) = return ()+      checkPolarity v = do+        p <- getNth polvec $ var2lit v True+        if p == LiftedF+          then setAssign s v p+          else do n <- getNth polvec $ var2lit v False+                  when (n == LiftedF) $ setAssign s v p+        checkPolarity $ v + 1+  checkPolarity 1++{-# INLINE skipWhitespace #-}+skipWhitespace :: B.ByteString -> B.ByteString+skipWhitespace !s = B.dropWhile (`elem` " \t\n") s++-- | skip comment lines+-- __Pre-condition:__ we are on the benngining of a line+{-# INLINE skipComments #-}+skipComments :: B.ByteString -> B.ByteString+skipComments !s+  | c == 'c' = skipComments . B.tail . B.dropWhile (/= '\n') $ s+  | otherwise = s+  where+    c = B.head s++{-# INLINABLE parseInt #-}+parseInt :: B.ByteString -> (Int, B.ByteString)+parseInt !st = do+  let !zero = ord '0'+      loop :: B.ByteString -> Int -> (Int, B.ByteString)+      loop !s !val = case B.head s of+        c | '0' <= c && c <= '9'  -> loop (B.tail s) (val * 10 + ord c - zero)+        _ -> (val, B.tail s)+  case B.head st of+    '-' -> let (k, x) = loop (B.tail st) 0 in (negate k, x)+    '0' -> (0, B.tail st)+--    '+' -> loop st (0 :: Int)+    _   -> loop st 0+--    c | '0' <= c && c <= '9'  -> loop st 0+--    _ -> error "PARSE ERROR! Unexpected char"++{-# INLINABLE readClause #-}+readClause :: Solver -> Stack -> Vec Int -> B.ByteString -> IO B.ByteString+readClause s buffer bvec stream = do+  let+    loop :: Int -> B.ByteString -> IO B.ByteString+    loop !i !b = case parseInt $ skipWhitespace b of+                   (0, b') -> do setNth buffer 0 $ i - 1+                                 sortStack buffer+                                 void $ addClause s buffer+                                 return b'+                   (k, b') -> case int2lit k of+                                l -> do setNth buffer i l+                                        setNth bvec l LiftedT+                                        loop (i + 1) b'+  loop 1 . skipComments . skipWhitespace $ stream++showPath :: FilePath -> String+showPath str = replicate (len - length basename) ' ' ++ if elem '/' str then basename else basename'+  where+    len = 50+    basename = reverse . takeWhile (/= '/') . reverse $ str+    basename' = take len str
+ src/SAT/Mios/Clause.hs view
@@ -0,0 +1,129 @@+-- | (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
+ src/SAT/Mios/ClauseManager.hs view
@@ -0,0 +1,293 @@+-- | (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]
+ src/SAT/Mios/ClausePool.hs view
@@ -0,0 +1,75 @@+-- | (This is a part of MIOS.)+-- Recycling clauses+{-# LANGUAGE+    ViewPatterns+  #-}+{-# LANGUAGE Trustworthy #-}++module SAT.Mios.ClausePool+       (+         ClausePool+       , newClausePool+       , makeClauseFromStack+       , putBackToPool+       )+       where++import Control.Monad (when)+import qualified Data.Vector as V+import SAT.Mios.Vec+import SAT.Mios.Clause+import qualified SAT.Mios.ClauseManager as CM++-- | an immutable Vector of 'ClauseSimpleManager'+type ClausePool = V.Vector CM.ClauseSimpleManager++-- | biclause should be stored into index:0, so the real limit is 64.+storeLimit :: Int+storeLimit = 62++-- | returns a new 'ClausePool'+newClausePool ::Int -> IO ClausePool+newClausePool n = V.fromList <$> mapM (\_ -> CM.newManager n) [0 .. storeLimit]++-- | returns 'CM.ClauseManager' for caluses which have suitable sizes.+{-# INLINE getManager #-}+getManager :: ClausePool -> Int -> CM.ClauseSimpleManager+getManager p n = V.unsafeIndex p n++-- | If a nice candidate as a learnt is stored, return it.+-- Otherwise allocate a new clause in heap then return it.+{-# INLINABLE makeClauseFromStack #-}+makeClauseFromStack :: ClausePool -> Stack -> IO Clause+makeClauseFromStack pool v = do+  let pickup :: Int -> IO Clause+      pickup ((<= storeLimit) -> False) = return NullClause+      pickup i = do+        let mgr = getManager pool i+        nn <- get' mgr+        if 0 < nn+          then do c <- lastOf mgr+                  popFrom mgr+                  return c+          else pickup $ i + 1+  n <- get' v+  c <- pickup (n - 2)+  if c == NullClause+    then newClauseFromStack True v+    else do let lstack = lits c+                loop :: Int -> IO ()+                loop ((<= n) -> False) = return ()+                loop i = (setNth lstack i =<< getNth v i) >> loop (i + 1)+            loop 0+            -- the caller (newLearntClause) should set these slots+            --  - rank+            --  - protected+            set' (activity c) 0.0+            return c++-- | Note: only not-too-large and learnt clauses are recycled.+{-# INLINE putBackToPool #-}+putBackToPool :: ClausePool -> Clause -> IO ()+putBackToPool pool c = do+  l <- get' (rank c)+  when (0 /= l) $ do let n = realLengthOfStack (lits c) - 3+                     when (n <= storeLimit) $ pushTo (getManager pool n) c
+ src/SAT/Mios/Criteria.hs view
@@ -0,0 +1,327 @@+-- | (This is a part of MIOS.)+-- Advanced heuristics library for 'SAT.Mios.Main'+{-# LANGUAGE+    MultiWayIf+  , RecordWildCards+  , ViewPatterns+  #-}+{-# LANGUAGE Safe #-}++module SAT.Mios.Criteria+       (+         -- * Activities+         claBumpActivity+       , claDecayActivity+       , varBumpActivity+       , varDecayActivity+         -- * Clause+       , addClause+         -- * Literal Block Distance+       , lbdOf+         -- * Restart+       , checkRestartCondition+       )+        where++import Control.Monad (when)+import SAT.Mios.Types+import SAT.Mios.Clause+import SAT.Mios.ClauseManager+import SAT.Mios.Solver++-------------------------------------------------------------------------------- Activities++varActivityThreshold :: Double+varActivityThreshold = 1e100++-- | __Fig. 14 (p.19)__ Bumping of clause activity+{-# INLINE varBumpActivity #-}+varBumpActivity :: Solver -> Var -> IO ()+varBumpActivity s@Solver{..} x = do+  a <- (+) <$> getNth activities x <*> get' varInc+  setNth activities x a+  when (varActivityThreshold < a) $ varRescaleActivity s+  update s x                    -- update the position in heap++-- | __Fig. 14 (p.19)__+{-# INLINABLE varDecayActivity #-}+varDecayActivity :: Solver -> IO ()+varDecayActivity Solver{..} = modify' varInc (/ variableDecayRate config)++-- | __Fig. 14 (p.19)__+{-# INLINABLE varRescaleActivity #-}+varRescaleActivity :: Solver -> IO ()+varRescaleActivity Solver{..} = do+  let+    loop ((<= nVars) -> False) = return ()+    loop i = modifyNth activities (/ varActivityThreshold) i >> loop (i + 1)+  loop 1+  modify' varInc (/ varActivityThreshold)++-- | value for rescaling clause activity.+claActivityThreshold :: Double+claActivityThreshold = 1e20++-- | __Fig. 14 (p.19)__+{-# INLINE claBumpActivity #-}+claBumpActivity :: Solver -> Clause -> IO ()+claBumpActivity s@Solver{..} Clause{..} = do+  a <- (+) <$> get' activity <*> get' claInc+  set' activity a+  when (claActivityThreshold <= a) $ claRescaleActivity s++-- | __Fig. 14 (p.19)__+{-# INLINE claDecayActivity #-}+claDecayActivity :: Solver -> IO ()+claDecayActivity Solver{..} = modify' claInc (/ clauseDecayRate config)++-- | __Fig. 14 (p.19)__+{-# INLINABLE claRescaleActivity #-}+claRescaleActivity :: Solver -> IO ()+claRescaleActivity Solver{..} = do+  vec <- getClauseVector learnts+  n <- get' learnts+  let+    loopOnVector :: Int -> IO ()+    loopOnVector ((< n) -> False) = return ()+    loopOnVector i = do+      c <- getNth vec i+      modify' (activity c) (/ claActivityThreshold)+      loopOnVector $ i + 1+  loopOnVector 0+  modify' claInc (/ claActivityThreshold)++{-+-- | __Fig. 14 (p.19)__+{-# INLINABLE claRescaleActivityAfterRestart #-}+claRescaleActivityAfterRestart :: Solver -> IO ()+claRescaleActivityAfterRestart Solver{..} = do+  vec <- getClauseVector learnts+  n <- get' learnts+  let+    loopOnVector :: Int -> IO ()+    loopOnVector ((< n) -> False) = return ()+    loopOnVector i = do+      c <- getNth vec i+      d <- get' c+      if d < 9+        then modify' (activity c) sqrt+        else set' (activity c) 0+      -- set' (protected c) False+      loopOnVector $ i + 1+  loopOnVector 0+-}++-------------------------------------------------------------------------------- ClauseNew++-- | __Fig. 8. (p.12)__ create a new clause and adds it to watcher lists.+-- Constructor function for clauses. Returns @False@ if top-level conflict is determined.+-- @outClause@ may be set to Null if the new clause is already satisfied under the current+-- top-level assignment.+--+-- __Post-condition:__ @ps@ is cleared. For learnt clauses, all+-- literals will be false except @lits[0]@ (this by design of the 'analyze' method).+-- For the propagation to work, the second watch must be put on the literal which will+-- first be unbound by backtracking. (Note that none of the learnt-clause specific things+-- needs to done for a user defined contraint type.)+--+-- * @Left False@ if the clause is in a confilct+-- * @Left True@ if the clause is satisfied+-- * @Right clause@ if the clause is enqueued successfully+{-# INLINABLE clauseNew #-}+clauseNew :: Solver -> Stack -> Bool -> IO (Either Bool Clause)+clauseNew s@Solver{..} ps isLearnt = do+  -- now ps[0] is the number of living literals+  exit <- do+    let+      handle :: Int -> Int -> Int -> IO Bool+      handle j l n      -- removes duplicates, but returns @True@ if this clause is satisfied+        | j > n = return False+        | otherwise = do+            y <- getNth ps j+            if | y == l    -> do                      -- finds a duplicate+                   swapBetween ps j n+                   modifyNth ps (subtract 1) 0+                   handle j l (n - 1)+               | - y == l  -> reset ps >> return True -- p and negateLit p occurs in ps+               | otherwise -> handle (j + 1) l n+      loopForLearnt :: Int -> IO Bool+      loopForLearnt i = do+        n <- get' ps+        if n < i+          then return False+          else do+              l <- getNth ps i+              sat <- handle (i + 1) l n+              if sat+                then return True+                else loopForLearnt $ i + 1+      loop :: Int -> IO Bool+      loop i = do+        n <- get' ps+        if n < i+          then return False+          else do+              l <- getNth ps i     -- check the i-th literal's satisfiability+              sat <- valueLit s l  -- any literal in ps is true+              case sat of+               1  -> reset ps >> return True+               -1 -> do+                 swapBetween ps i n+                 modifyNth ps (subtract 1) 0+                 loop i+               _ -> do+                 sat' <- handle (i + 1) l n+                 if sat'+                   then return True+                   else loop $ i + 1+    if isLearnt then loopForLearnt 1 else loop 1+  k <- get' ps+  case k of+   0 -> return (Left exit)+   1 -> do+     l <- getNth ps 1+     Left <$> enqueue s l NullClause+   _ -> do+    -- allocate clause:+     c <- newClauseFromStack isLearnt ps+     let lstack = lits c+     when isLearnt $ do+       -- Pick a second literal to watch:+       let+         findMax :: Int -> Int -> Int -> IO Int+         findMax ((<= k) -> False) j _ = return j+         findMax i j val = do+           v' <- lit2var <$> getNth lstack i+           varBumpActivity s v' -- this is a just good chance to bump activities of literals in this clause+           a <- getNth assigns v'+           b <- getNth level v'+           if (a /= LBottom) && (val < b)+             then findMax (i + 1) i b+             else findMax (i + 1) j val+       -- Let @max_i@ be the index of the literal with highest decision level+       max_i <- findMax 1 1 0+       swapBetween lstack 2 max_i+       -- check literals occurences+       -- x <- asList c+       -- unless (length x == length (nub x)) $ error "new clause contains a element doubly"+       -- Bumping:+       claBumpActivity s c -- newly learnt clauses should be considered active+     -- Add clause to watcher lists:+     l1 <- getNth lstack 1+     l2 <- getNth lstack 2+     pushClauseWithKey (getNthWatcher watches (negateLit l1)) c 0+     pushClauseWithKey (getNthWatcher watches (negateLit l2)) c 0+     return (Right c)++-- | returns @False@ if a conflict has occured.+-- This function is called only before the solving phase to register the given clauses.+{-# INLINABLE addClause #-}+addClause :: Solver -> Stack -> IO Bool+addClause s@Solver{..} vecLits = do+  result <- clauseNew s vecLits False+  case result of+   Left b  -> return b   -- No new clause was returned becaues a confilct occured or the clause is a literal+   Right c -> pushTo clauses c >> return True++-------------------------------------------------------------------------------- LBD++-- | returns a POSIVITE value+{-# INLINABLE lbdOf #-}+lbdOf :: Solver -> Stack -> IO Int+lbdOf Solver{..} vec = do+  k <- (\k -> if 1000000 < k then 1 else k + 1) <$> get' lbd'key+  set' lbd'key k                -- store the last used value+  nv <- getNth vec 0+  let loop :: Int -> Int -> IO Int+      loop ((<= nv) -> False) n = return $ max 1 n+      loop i n = do l <- getNth level . lit2var =<< getNth vec i+                    x <- getNth lbd'seen l+                    if x /= k && l /= 0+                      then setNth lbd'seen l k >> loop (i + 1) (n + 1)+                      else loop (i + 1) n+  loop 1 0++{-+{-# INLINE setLBD #-}+setLBD :: Solver -> Clause -> IO ()+setLBD _ NullClause = error "LBD44"+setLBD s c = set' (rank c) =<< lbdOf s (lits c)++-- | update the lbd field of /c/+{-# INLINE updateLBD #-}+updateLBD :: Solver -> Clause -> IO ()+updateLBD s NullClause = error "LBD71"+updateLBD s c@Clause{..} = do+  k <- get' c+--  o <- getInt lbd+  n <- lbdOf s lits+  case () of+    _ | n == 1 -> set' rank (k - 1)+    -- _ | n < o -> setInt lbd n+    _ -> return ()+-}++-------------------------------------------------------------------------------- restart++ema1, ema2, ema3, ema4 :: Double+ema1 = 2 ** (-5)                -- coefficient for fast average of LBD+ema2 = 2 ** (-14)               -- coefficient for slow average of LBD+ema3 = 2 ** (-5)                -- coefficient for fast average of | assignment |+ema4 = 2 ** (-12)               -- coefficient for slow average of | assignment |++ema0 :: Int+ema0 = 2 ^ (14 :: Int)          -- = floor $ 1 / ema2++-- | #62+checkRestartCondition :: Solver -> Int -> IO Bool+checkRestartCondition s@Solver{..} (fromIntegral -> lbd) = do+  k <- getStat s NumOfRestart+  let step = 100+  next <- get' nextRestart+  count <- getStat s NumOfBackjump+  nas <- fromIntegral <$> nAssigns s+  let revise a f x  = do f' <- ((a * x) +) . ((1 - a) *) <$> get' f+                         set' f f'+                         return f'+      gef = 1.1 :: Double       -- geometric expansion factor+  df <- revise ema1 emaDFast lbd+  ds <- revise ema2 emaDSlow lbd+  af <- revise ema3 emaAFast nas+  as <- revise ema4 emaASlow nas+  mode <- get' restartMode+  if | count < next   -> return False+     | mode == 1      -> do+         when (ema0 < count && df < 2.0 * ds) $ set' restartMode 2 -- enter the second mode+         incrementStat s NumOfRestart 1+         incrementStat s NumOfGeometricRestart 1+         k' <- getStat s NumOfGeometricRestart+         set' nextRestart (count + floor (fromIntegral step * gef ** fromIntegral k'))+         when (3 == dumpStat config) $ dumpSolver DumpCSV s+         return True+     | 1.25 * as < af -> do+         incrementStat s NumOfBlockRestart 1+         set' nextRestart (count + floor (fromIntegral step + gef ** fromIntegral k))+         when (3 == dumpStat config) $ dumpSolver DumpCSV s+         return False+     | 1.25 * ds < df -> do+         incrementStat s NumOfRestart 1+         set' nextRestart (count + step)+         when (3 == dumpStat config) $ dumpSolver DumpCSV s+         return True+     | otherwise      -> return False++{-+{-# INLINABLE luby #-}+luby :: Double -> Int -> Double+luby y x_ = loop 1 0+  where+    loop :: Int -> Int -> Double+    loop sz sq+      | sz < x_ + 1 = loop (2 * sz + 1) (sq + 1)+      | otherwise   = loop2 x_ sz sq+    loop2 :: Int -> Int -> Int -> Double+    loop2 x sz sq+      | sz - 1 == x = y ** fromIntegral sq+      | otherwise   = let s = div (sz - 1) 2 in loop2 (mod x s) s (sq - 1)+-}
+ src/SAT/Mios/Main.hs view
@@ -0,0 +1,759 @@+-- | (This is a part of MIOS.)+-- Main part of solving satisfiability problem.+{-# LANGUAGE+    BangPatterns+  , MultiWayIf+  , RecordWildCards+  , ScopedTypeVariables+  , ViewPatterns+  #-}+{-# LANGUAGE Safe #-}++module SAT.Mios.Main+       (+         -- * Interface to 'Solver', imported from 'SAT.Mios.Criteria'+         Solver+       , newSolver+       , setAssign+       , addClause+       , dumpSolver+         -- * Main function+       , simplifyDB+       , solve+       )+        where++import Control.Monad (unless, void, when)+import Data.Bits+import Data.Foldable (foldrM)+import Data.Int+import SAT.Mios.Types+import SAT.Mios.Clause+import SAT.Mios.ClauseManager+import SAT.Mios.Solver+import SAT.Mios.ClausePool+import SAT.Mios.Criteria++-- | #114: __RemoveWatch__+{-# INLINABLE removeWatch #-}+removeWatch :: Solver -> Clause -> IO ()+removeWatch Solver{..} c = do+  let lstack = lits c+  l1 <- negateLit <$> getNth lstack 1+  markClause (getNthWatcher watches l1) c+  l2 <- negateLit <$> getNth lstack 2+  markClause (getNthWatcher watches l2) c+  putBackToPool clsPool c++--------------------------------------------------------------------------------+-- Operations on 'Clause'+--------------------------------------------------------------------------------++-- | __Fig. 8. (p.12)__ creates a new LEARNT clause and adds it to watcher lists.+-- This is a strippped-down version of 'newClause' in Solver.+newLearntClause :: Solver -> Stack -> IO Int+newLearntClause s@Solver{..} ps = do+  -- ps is a 'SizedVectorInt'; ps[0] is the number of active literals+  -- Since this solver must generate only healthy learnt clauses, we need not to run misc check in 'newClause'+  k <- get' ps+  case k of+   1 -> do l <- getNth ps 1+           unsafeEnqueue s l NullClause+           return 1+   _ -> do c <- makeClauseFromStack clsPool ps --  newClauseFromStack True ps+           let lstack = lits c+               findMax :: Int -> Int -> Int -> IO Int -- Pick a second literal to watch:+               findMax ((<= k) -> False) j _ = return j+               findMax i j val = do+                 v <- lit2var <$> getNth lstack i+                 a <- getNth assigns v+                 b <- getNth level v+                 if (a /= LBottom) && (val < b)+                   then findMax (i + 1) i b+                   else findMax (i + 1) j val+           swapBetween lstack 2 =<< findMax 1 1 0 -- Let @max_i@ be the index of the literal with highest decision level+           -- Bump, enqueue, store clause:+           claBumpActivity s c+           -- Add clause to all managers+           pushTo learnts c+           l1 <- getNth lstack 1+           l2 <- getNth lstack 2+           pushClauseWithKey (getNthWatcher watches (negateLit l1)) c l2+           pushClauseWithKey (getNthWatcher watches (negateLit l2)) c l1+           -- update the solver state by @l@+           unsafeEnqueue s l1 c+           -- Since unsafeEnqueue updates the 1st literal's level, setLBD should be called after unsafeEnqueue+           lbd <- lbdOf s (lits c)+           set' (rank c) lbd+           -- assert (0 < rank c)+           -- set' (protected c) True+           return lbd++-- | __Simplify.__ At the top-level, a constraint may be given the opportunity to+-- simplify its representation (returns @False@) or state that the constraint is+-- satisfied under the current assignment and can be removed (returns @True@).+-- A constraint must /not/ be simplifiable to produce unit information or to be+-- conflicting; in that case the propagation has not been correctly defined.+--+-- MIOS NOTE: the original doesn't update watchers; only checks its satisfiabiliy.+{-# INLINABLE simplify #-}+simplify :: Solver -> Clause -> IO Bool+simplify s c = do+  n <- get' c+  let lstack = lits c+      loop ::Int -> IO Bool+      loop ((<= n) -> False) = return False+      loop i = do v <- valueLit s =<< getNth lstack i+                  if v == 1 then return True else loop (i + 1)+  loop 1++--------------------------------------------------------------------------------+-- MIOS NOTE on Minor methods:+--+-- * no (meaningful) 'newVar' in mios+-- * 'assume' is defined in 'Solver'+-- * `cancelUntil` is defined in 'Solver'++--------------------------------------------------------------------------------+-- Major methods++-- | M114: __Fig. 10. (p.15)__+--+-- analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel :: int&) -> [void]+--+-- __Description:_-+--   Analzye confilct and produce a reason clause.+--+-- __Pre-conditions:__+--   * 'out_learnt' is assumed to be cleared.+--   * Corrent decision level must be greater than root level.+--+-- __Post-conditions:__+--   * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'.+--   * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision level of the+--     rest of literals. There may be others from the same level though.+--+-- @analyze@ is invoked from @search@+analyze :: Solver -> Clause -> IO Int+analyze s@Solver{..} confl = do+  -- litvec+  reset litsLearnt+  pushTo litsLearnt 0 -- reserve the first place for the unassigned literal+  dl <- decisionLevel s+  let loopOnClauseChain :: Clause -> Lit -> Int -> Int -> Int -> IO Int+      loopOnClauseChain c p ti bl pathC = do -- p : literal, ti = trail index, bl = backtrack level+        d <- get' (rank c)+        when (0 /= d) $ claBumpActivity s c+        -- update LBD like #Glucose4.0+        when (2 < d) $ do+          nblevels <- lbdOf s (lits c)+          when (nblevels + 1 < d) $ -- improve the LBD+            -- when (d <= 30) $ set' (protected c) True -- 30 is `lbLBDFrozenClause`+            -- seems to be interesting: keep it fro the next round+            set' (rank c) nblevels    -- Update it+        sc <- get' c+        let lstack = lits c+            loopOnLiterals :: Int -> Int -> Int -> IO (Int, Int)+            loopOnLiterals ((<= sc) -> False) b pc = return (b, pc) -- b = btLevel, pc = pathC+            loopOnLiterals j b pc = do+              (q :: Lit) <- getNth lstack j+              let v = lit2var q+              sn <- getNth an'seen v+              l <- getNth level v+              if sn == 0 && 0 < l+                then do+                    varBumpActivity s v+                    setNth an'seen v 1+                    if dl <= l      -- cancelUntil doesn't clear level of cancelled literals+                      then do+                          -- UPDATEVARACTIVITY: glucose heuristics+                          r <- getNth reason v+                          when (r /= NullClause) $ do+                            ra <- get' (rank r)+                            when (0 /= ra) $ pushTo an'lastDL q+                          -- end of glucose heuristics+                          loopOnLiterals (j + 1) b (pc + 1)+                      else pushTo litsLearnt q >> loopOnLiterals (j + 1) (max b l) pc+                else loopOnLiterals (j + 1) b pc+        (b', pathC') <- loopOnLiterals (if p == bottomLit then 1 else 2) bl pathC+        let nextPickedUpLit :: Int -> IO Int        -- select next clause to look at+            nextPickedUpLit i = do x <- getNth an'seen . lit2var =<< getNth trail i+                                   if x == 0 then nextPickedUpLit (i - 1) else return (i - 1)+        ti' <- nextPickedUpLit (ti + 1)+        nextP <- getNth trail (ti' + 1)+        let nextV = lit2var nextP+        confl' <- getNth reason nextV+        setNth an'seen nextV 0+        if 1 < pathC'+          then loopOnClauseChain confl' nextP (ti' - 1) b' (pathC' - 1)+          else setNth litsLearnt 1 (negateLit nextP) >> return b'+  ti <- subtract 1 <$> get' trail+  levelToReturn <- loopOnClauseChain confl bottomLit ti 0 0+  -- Simplify phase (implemented only @expensive_ccmin@ path)+  n <- get' litsLearnt+  reset an'stack           -- analyze_stack.clear();+  reset an'toClear         -- out_learnt.copyTo(analyze_toclear);+  pushTo an'toClear =<< getNth litsLearnt 1+  let merger :: Int -> Int64 -> IO Int64+      merger ((<= n) -> False) b = return b+      merger i b = do l <- getNth litsLearnt i+                      pushTo an'toClear l+                      -- restrict the search depth (range) to 63+                      merger (i + 1) . setBit b . (63 .&.) =<< getNth level (lit2var l)+  levels <- merger 2 0+  let loopOnLits :: Int -> Int -> IO ()+      loopOnLits ((<= n) -> False) n' = shrinkBy litsLearnt $ n - n' + 1+      loopOnLits i j = do+        l <- getNth litsLearnt i+        c1 <- (NullClause ==) <$> getNth reason (lit2var l)+        if c1+          then setNth litsLearnt j l >> loopOnLits (i + 1) (j + 1)+          else do+             c2 <- not <$> analyzeRemovable s l levels+             if c2+               then setNth litsLearnt j l >> loopOnLits (i + 1) (j + 1)+               else loopOnLits (i + 1) j+  loopOnLits 2 2                -- the first literal is specail+  -- UPDATEVARACTIVITY: glucose heuristics+  nld <- get' an'lastDL+  r <- get' litsLearnt -- this is an estimated LBD value based on the clause size+  let loopOnLastDL :: Int -> IO ()+      loopOnLastDL ((<= nld) -> False) = return ()+      loopOnLastDL i = do v <- lit2var <$> getNth an'lastDL i+                          r' <- get' =<< getNth reason v+                          when (r < r') $ varBumpActivity s v+                          loopOnLastDL $ i + 1+  loopOnLastDL 1+  reset an'lastDL+  -- Clear seen+  k <- get' an'toClear+  let cleaner :: Int -> IO ()+      cleaner ((<= k) -> False) = return ()+      cleaner i = do v <- lit2var <$> getNth an'toClear i+                     setNth an'seen v 0+                     cleaner $ i + 1+  cleaner 1+  return levelToReturn++-- | #M114+-- Check if 'p' can be removed, 'abstract_levels' is used to abort early if the algorithm is+-- visiting literals at levels that cannot be removed later.+--+-- Implementation memo:+--+-- *  @an'toClear@ is initialized by @ps@ in @analyze@ (a copy of 'learnt').+--   This is used only in this function and @analyze@.+--+analyzeRemovable :: Solver -> Lit -> Int64 -> IO Bool+analyzeRemovable Solver{..} p minLevel = do+  -- assert (reason[var(p)] != NullClause);+  reset an'stack      -- analyze_stack.clear()+  pushTo an'stack p   -- analyze_stack.push(p);+  top <- get' an'toClear+  let+    loopOnStack :: IO Bool+    loopOnStack = do+      k <- get' an'stack  -- int top = analyze_toclear.size();+      if 0 == k+        then return True+        else do -- assert(reason[var(analyze_stack.last())] != GClause_NULL);+            sl <- lastOf an'stack+            popFrom an'stack             -- analyze_stack.pop();+            c <- getNth reason (lit2var sl) -- getRoot sl+            nl <- get' c+            let+              lstack = lits c+              loopOnLit :: Int -> IO Bool -- loopOnLit (int i = 1; i < c.size(); i++){+              loopOnLit ((<= nl) -> False) = loopOnStack+              loopOnLit i = do+                p' <- getNth lstack i              -- valid range is [1 .. nl]+                let v' = lit2var p'+                l' <- getNth level v'+                c1 <- (1 /=) <$> getNth an'seen v'+                if c1 && (0 /= l')   -- if (!analyze_seen[var(p)] && level[var(p)] != 0){+                  then do+                      c3 <- (NullClause /=) <$> getNth reason v'+                      if c3 && testBit minLevel (l' .&. 63) -- if (reason[var(p)] != GClause_NULL && ((1 << (level[var(p)] & 31)) & min_level) != 0){+                        then do+                            setNth an'seen v' 1   -- analyze_seen[var(p)] = 1;+                            pushTo an'stack p'    -- analyze_stack.push(p);+                            pushTo an'toClear p'  -- analyze_toclear.push(p);+                            loopOnLit $ i + 1+                        else do+                            -- for (int j = top; j < analyze_toclear.size(); j++) analyze_seen[var(analyze_toclear[j])] = 0;+                            top' <- get' an'toClear+                            let clearAll :: Int -> IO ()+                                clearAll ((<= top') -> False) = return ()+                                clearAll j = do x <- getNth an'toClear j; setNth an'seen (lit2var x) 0; clearAll (j + 1)+                            clearAll $ top + 1+                            -- analyze_toclear.shrink(analyze_toclear.size() - top); note: shrink n == repeat n pop+                            shrinkBy an'toClear $ top' - top+                            return False+                  else loopOnLit $ i + 1+            loopOnLit 2+  loopOnStack++-- | #114+-- analyzeFinal : (confl : Clause *) (skip_first : boot) -> [void]+--+-- __Description:__+--   Specialized analysis proceduce to express the final conflict in terms of assumptions.+--   'root_level' is allowed to point beyond end of trace (useful if called after conflict while+--   making assumptions). If 'skip_first' is TRUE, the first literal of 'confl' is ignored (needed+--   if conflict arose before search even started).+--+analyzeFinal :: Solver -> Clause -> Bool -> IO ()+analyzeFinal Solver{..} confl skipFirst = do+  reset conflicts+  rl <- get' rootLevel+  unless (rl == 0) $ do+    n <- get' confl+    let lstack = lits confl+        loopOnConfl :: Int -> IO ()+        loopOnConfl ((<= n) -> False) = return ()+        loopOnConfl i = do+          (x :: Var) <- lit2var <$> getNth lstack i+          lvl <- getNth level x+          when (0 < lvl) $ setNth an'seen x 1+          loopOnConfl $ i + 1+    loopOnConfl $ if skipFirst then 2 else 1+    tls <- get' trailLim+    trs <- get' trail+    tlz <- getNth trailLim 1+    let loopOnTrail :: Int -> IO ()+        loopOnTrail ((tlz <=) -> False) = return ()+        loopOnTrail i = do+          (l :: Lit) <- getNth trail (i + 1)+          let (x :: Var) = lit2var l+          saw <- getNth an'seen x+          when (saw == 1) $ do+            (r :: Clause) <- getNth reason x+            if r == NullClause+              then pushTo conflicts (negateLit l)+              else do+                  k <- get' r+                  let lstack' = lits r+                      loopOnLits :: Int -> IO ()+                      loopOnLits ((<= k) -> False) = return ()+                      loopOnLits j = do+                        (v :: Var) <- lit2var <$> getNth lstack' j+                        lv <- getNth level v+                        when (0 < lv) $ setNth an'seen v 1+                        loopOnLits $ i + 1+                  loopOnLits 2+          setNth an'seen x 0+          loopOnTrail $ i - 1+    loopOnTrail =<< if tls <= rl then return (trs - 1) else getNth trailLim (rl + 1)++-- | M114:+-- propagate : [void] -> [Clause+]+--+-- __Description:__+--   Porpagates all enqueued facts. If a conflict arises, the conflicting clause is returned.+--   otherwise CRef_undef.+--+-- __Post-conditions:__+--   * the propagation queue is empty, even if there was a conflict.+--+-- memo: @propagate@ is invoked by @search@,`simpleDB` and `solve`+propagate :: Solver -> IO Clause+propagate s@Solver{..} = do+  let+    while :: Clause -> Bool -> IO Clause+    while confl False = return confl+    while confl True = do+      (p :: Lit) <- getNth trail . (1 +) =<< get' qHead+      modify' qHead (+ 1)+      incrementStat s NumOfPropagation 1+      let (ws :: ClauseExtManager) = getNthWatcher watches p+          !falseLit = negateLit p+      end <- get' ws+      cvec <- getClauseVector ws+      bvec <- getKeyVector ws+      let copy :: Int -> Int -> IO ()+          copy ((< end) -> False) _ = return ()+          copy !i' !j' = do setNth cvec j' =<< getNth cvec i'+                            setNth bvec j' =<< getNth bvec i'+                            copy (i' + 1) (j' + 1)+      let forClause :: Int -> Int -> IO Clause+          forClause i@((< end) -> False) !j = shrinkBy ws (i - j) >> return confl+          forClause !i !j = do+            (blocker :: Lit) <- getNth bvec i        -- Try to avoid inspecting the clause:+            bv <- if blocker == 0 then return LiftedF else valueLit s blocker+            if bv == LiftedT+              then do unless (i == j) $ do (c :: Clause) <- getNth cvec i+                                           setNth cvec j c+                                           setNth bvec j blocker+                      forClause (i + 1) (j + 1)+              else do                               -- Make sure the false literal is data[1]:+                  (c :: Clause) <- getNth cvec i+                  let !lstack = lits c+                  tmp <- getNth lstack 1+                  first <- if falseLit == tmp+                           then do l2 <- getNth lstack 2+                                   setNth lstack 2 tmp+                                   setNth lstack 1 l2+                                   return l2+                           else return tmp+                  fv <- valueLit s first+                  if fv == LiftedT+                    then do unless (i == j) $ setNth cvec j c+                            setNth bvec j first+                            forClause (i + 1) (j + 1)+                    else do cs <- get' c           -- Look for new watch:+                            let newWatch :: Int -> IO LiftedBool+                                newWatch ((<= cs) -> False) = do -- Did not find watch+                                  setNth cvec j c+                                  setNth bvec j first+                                  if fv == LiftedF+                                    then do ((== 0) <$> decisionLevel s) >>= (`when` set' ok LiftedF)+                                            set' qHead =<< get' trail+                                            copy (i + 1) (j + 1)+                                            return LiftedF                 -- conflict+                                    else do unsafeEnqueue s first c+                                            return LBottom                 -- unit clause+                                newWatch !k = do (l' :: Lit) <- getNth lstack k+                                                 lv <- valueLit s l'+                                                 if lv /= LiftedF+                                                   then do setNth lstack 2 l'+                                                           setNth lstack k falseLit+                                                           pushClauseWithKey (getNthWatcher watches (negateLit l')) c first+                                                           return LiftedT  -- found another watch+                                                   else newWatch $! k + 1+                            ret <- newWatch 3+                            case ret of+                              LiftedT -> forClause (i + 1) j               -- found another watch+                              LBottom -> forClause (i + 1) (j + 1)         -- unit clause+                              _       -> shrinkBy ws (i - j) >> return c   -- conflict+      c <- forClause 0 0+      while c =<< ((<) <$> get' qHead <*> get' trail)+  while NullClause =<< ((<) <$> get' qHead <*> get' trail)++-- | #M22+-- reduceDB: () -> [void]+--+-- __Description:__+--   Remove half of the learnt clauses, minus the clauses locked by the current assigmnent. Locked+--   clauses are clauses that are reason to some assignment. Binary clauses are never removed.+reduceDB :: Solver -> IO ()+reduceDB s@Solver{..} = do+  n <- nLearnts s+  cvec <- getClauseVector learnts+  let loop :: Int -> IO ()+      loop ((< n) -> False) = return ()+      loop i = do+        removeWatch s =<< getNth cvec i+        loop $ i + 1+  k <- sortClauses s learnts $ div n 2 -- k is the number of clauses not to be purged+{-+  -- #GLUCOSE3.0 keep more+  t3 <- get' . rank =<< getNth vec (thr -1)+  t5 <- get' . rank =<< getNth vec (lim -1)++  let k = case (t3 <= 3, t5 <= 5) of+            (True, True)   -> min n (thr + 2000)+            (False, False) -> thr+            (_, _)         -> min n (thr + 1000)+  -- let k = div thr 2+-}+  loop k                               -- CAVEAT: `vec` is a zero-based vector+  -- putStrLn $ "reduceDB: purge " ++ show (n - k) ++ " out of " ++ show n+  reset watches+  shrinkBy learnts (n - k)+  incrementStat s NumOfReduction 1++-- constants for sort key layout+rankWidth :: Int+rankWidth = 10+activityWidth :: Int+activityWidth = 50              -- note: the maximum clause activity is 1e20.+indexWidth :: Int+indexWidth = 32                 -- 4G+rankMax :: Int+rankMax = 2 ^ rankWidth - 1+activityMax :: Int+activityMax = 2 ^ activityWidth - 1+indexMax :: Int+indexMax = 2 ^ indexWidth - 1++-- | applies a (good to bad) quick semi-sort to the vector in a 'ClauseExtManager'+-- and returns the number of privileged clauses.+-- This function uses the same criteria as reduceDB_lt in glucose 4.0:+-- 1. binary clause+-- 2. smaller LBD+-- 3. larger activity defined as MiniSat+--+-- they are encoded into two "Int64"s as the following (10+52+32 layout):+--+-- * 10 bits for rank (LBD): 'rankWidth'+-- * 50 bits for converted activity: 'activityWidth'+-- * 32 bits for clauseVector index: 'indexWidth'+--+sortClauses :: Solver -> ClauseExtManager -> Int -> IO Int+sortClauses s cm limit' = do+  n <- get' cm+  -- assert (n < indexMax)+  vec <- getClauseVector cm+  bvec <- getKeyVector cm+  keys <- newVec (2 * n) 0 :: IO (Vec Int)+  at <- (0.1 *) . (/ fromIntegral n) <$> get' (claInc s) -- activity threshold+  -- 1: assign keys+  let shiftLBD = activityWidth+      shiftIndex = shiftL 1 indexWidth+      am = fromIntegral activityMax :: Double+      scaleAct :: Double -> Int+      scaleAct x+        | x < 1e-20 = activityMax+        | otherwise = floor $ am * (1 - logBase 10 (x * 1e20) / 40)+      assignKey :: Int -> Int -> IO Int+      assignKey ((< n) -> False) t = return t+      assignKey i t = do+        setNth keys (2 * i + 1) $ shiftIndex + i+        c <- getNth vec i+        k <- get' c+        if k == 2                  -- Main criteria. Like in MiniSat we keep all binary clauses+          then do setNth keys (2 * i) 0+                  assignKey (i + 1) (t + 1)+          else do a <- get' (activity c)               -- Second one... based on LBD+                  r <- get' (rank c)+                  l <- locked s c+                  let d =if | l -> 0+                            | a < at -> rankMax+                            | otherwise ->  min rankMax r                -- rank can be one+                  setNth keys (2 * i) $ shiftL d shiftLBD + scaleAct a+                  assignKey (i + 1) $ if l then t + 1 else t+  limit <- max limit' <$> assignKey 0 0+  -- 2: sort keyVector+  let limit2 = 2 * limit+      sortOnRange :: Int -> Int -> IO ()+      sortOnRange left right+        | limit2 < left = return ()+        | left >= right = return ()+        | left + 2 == right = do+            a <- getNth keys left+            b <- getNth keys right+            unless (a < b) $ do swapBetween keys left right+                                swapBetween keys (left + 1) (right + 1)+        | otherwise = do+            let p = 2 * div (left + right) 4+            pivot <- getNth keys p+            swapBetween keys p left -- set a sentinel for r'+            swapBetween keys (p + 1) (left + 1)+            let nextL :: Int -> IO Int+                nextL i@((<= right) -> False) = return i+                nextL i = do v <- getNth keys i; if v < pivot then nextL (i + 2) else return i+                nextR :: Int -> IO Int+                nextR i = do v <- getNth keys i; if pivot < v then nextR (i - 2) else return i+                divide :: Int -> Int -> IO Int+                divide l r = do+                  l' <- nextL l+                  r' <- nextR r+                  if l' < r'+                    then do swapBetween keys l' r'+                            swapBetween keys (l' + 1) (r' + 1)+                            divide (l' + 2) (r' - 2)+                    else return r'+            m <- divide (left + 2) right+            swapBetween keys left m+            swapBetween keys (left + 1) (m + 1)+            sortOnRange left (m - 2)+            sortOnRange (m + 2) right+  sortOnRange 0 $ 2 * (n - 1)+  -- 3: place clauses in 'vec' based on the order stored in 'keys'.+  -- To recycle existing clauses, we must reserve all clauses for now.+  let seek :: Int -> IO ()+      seek ((< n) -> False) = return ()+      seek i = do+        bits <- getNth keys (2 * i + 1)+        when (indexMax < bits) $ do+          c <- getNth vec i+          d <- getNth bvec i+          -- setNth keys i i+          let sweep k = do k' <- (indexMax .&.) <$> getNth keys (2 * k + 1)+                           setNth keys (2 * k + 1) (indexMax .&. k)+                           if k' == i+                             then do setNth vec k c+                                     setNth bvec k d+                             else do getNth vec k' >>= setNth vec k+                                     getNth bvec k' >>= setNth bvec k+                                     sweep k'+          sweep i -- (indexMax .&. bits)+        seek $ i + 1+  seek 0+  return limit++-- | #M22+--+-- simplify : [void] -> [bool]+--+-- __Description:__+--   Simplify the clause database according to the current top-level assigment. Currently, the only+--   thing done here is the removal of satisfied clauses, but more things can be put here.+--+simplifyDB :: Solver -> IO Bool+simplifyDB s@Solver{..} = do+  good <- (LiftedT ==) <$> get' ok+  if good+    then do+      p <- propagate s+      if p /= NullClause+        then set' ok LiftedF >> return False+        else do+            -- Remove satisfied clauses and their watcher lists:+            let+              for :: ClauseExtManager -> IO ()+              for mgr = do+                vec' <- getClauseVector mgr+                n' <- get' mgr+                let+                  loopOnVector :: Int -> Int -> IO ()+                  loopOnVector ((< n') -> False) j = shrinkBy mgr (n' - j)+                  loopOnVector i j = do+                        c <- getNth vec' i+                        l <- locked s c+                        r <- if l then return False else simplify s c+                        if r+                          then removeWatch s c >> loopOnVector (i + 1) j+                          else unless (i == j) (setNth vec' j c) >> loopOnVector (i + 1) (j + 1)+                loopOnVector 0 0+            for clauses+            for learnts+            reset watches+            return True+    else return False++-- | #M22+--+-- search : (nof_conflicts : int) (params : const SearchParams&) -> [lbool]+--+-- __Description:__+--   Search for a model the specified number of conflicts.+--   NOTE: Use negative value for 'nof_conflicts' indicate infinity.+--+-- __Output:__+--   * 'True' if a partial assigment that is consistent with respect to the clause set is found.+--      If all variables are decision variables, that means that the clause set is satisfiable.+--   * 'False' if the clause set is unsatisfiable or some error occured.+search :: Solver -> IO Bool+search s@Solver{..} = do+  -- clear model+  let loop :: Bool -> IO Bool+      loop restart = do+        confl <- propagate s+        d <- decisionLevel s+        if confl /= NullClause  -- CONFLICT+          then do incrementStat s NumOfBackjump 1+                  r <- get' rootLevel+                  if d == r                       -- Contradiction found:+                    then analyzeFinal s confl False >> return False+                    else do backtrackLevel <- analyze s confl -- 'analyze' resets litsLearnt by itself+                            (s `cancelUntil`) . max backtrackLevel =<< get' rootLevel+                            lbd' <- newLearntClause s litsLearnt+                            k <- get' litsLearnt+                            when (k == 1) $ do+                              (v :: Var) <- lit2var <$> getNth litsLearnt 1+                              setNth level v 0+                            varDecayActivity s+                            claDecayActivity s+                            -- learnt DB Size Adjustment+                            modify' learntSCnt (subtract 1)+                            cnt <- get' learntSCnt+                            when (cnt == 0) $ do+                              t' <- (* 1.5) <$> get' learntSAdj+                              set' learntSAdj t'+                              set' learntSCnt $ floor t'+                              -- modify' maxLearnts (* 1.1)+                              modify' maxLearnts (+ 300)+                            loop =<< checkRestartCondition s lbd'+          else do when (d == 0) . void $ simplifyDB s -- Simplify the set of problem clauses+                  k1 <- get' learnts+                  k2 <- nAssigns s+                  nl <- floor <$> get' maxLearnts+                  when (nl < k1 - k2) $ do+                    reduceDB s    -- Reduce the set of learnt clauses.+                    when (2 == dumpStat config) $ dumpSolver DumpCSV s+                  if | k2 == nVars -> return True     -- Model found+                     | restart -> do                  -- Reached bound on number of conflicts+                         (s `cancelUntil`) =<< get' rootLevel -- force a restart+                         -- claRescaleActivityAfterRestart s+{-+                         let toggle :: Int -> Int+                             toggle LiftedT = LiftedF+                             toggle LiftedF = LiftedT+                             toggle x = x+                             nv = nVars+                             toggleAt :: Int -> IO ()+                             toggleAt ((<= nv) -> False) = return ()+                             toggleAt i = modifyNth phases toggle i >> toggleAt (i + 1)+                         rm <- get' restartMode+                         when (rm == 1) $ toggleAt 1+-}+                         loop False+                     | otherwise -> do                -- New variable decision+                         v <- select s+                         -- #phasesaving <<<<  many have heuristic for polarity here+                         oldVal <- getNth phases v+                         unsafeAssume s $ var2lit v (0 < oldVal) -- cannot return @False@+                         -- #phasesaving >>>>+                         loop False+  loop False++-- | __Fig. 16. (p.20)__+-- Main solve method.+--+-- __Pre-condition:__ If assumptions are used, 'simplifyDB' must be+-- called right before using this method. If not, a top-level conflict (resulting in a+-- non-usable internal state) cannot be distinguished from a conflict under assumptions.+solve :: (Foldable t) => Solver -> t Lit -> IO SolverResult+solve s@Solver{..} assumps = do+  -- PUSH INCREMENTAL ASSUMPTIONS:+  let inject :: Lit -> Bool -> IO Bool+      inject _ False = return False+      inject a True = do+        b <- assume s a+        if not b                  -- conflict analyze+          then do (confl :: Clause) <- getNth reason (lit2var a)+                  analyzeFinal s confl True+                  pushTo conflicts (negateLit a)+                  cancelUntil s 0+                  return False+          else do confl <- propagate s+                  if confl /= NullClause+                    then do analyzeFinal s confl True+                            cancelUntil s 0+                            return False+                    else return True+  good <- simplifyDB s+  x <- if good then foldrM inject True assumps else return False+  if x+    then do set' rootLevel =<< decisionLevel s+            status <- search s+            -- post-proccesing should be done here+            let toInt :: Var -> IO Lit+                toInt v = (\p -> if LiftedT == p then v else negate v) <$> valueVar s v+            asg1 <- mapM toInt [1 .. nVars]+            asg2 <- map lit2int <$> asList conflicts+            when (0 < dumpStat config) $ dumpSolver DumpCSV s+            cancelUntil s 0     -- reset solver+            flag <- get' ok+            if | status && flag == LiftedT     -> return $ Right (SAT asg1)+               | not status && flag == LiftedF -> return $ Right (UNSAT asg2)+               | otherwise                     -> return $ Left InternalInconsistent+    else return $ Right (UNSAT [])++-- | Though 'enqueue' is defined in 'Solver', most functions in M114 use @unsafeEnqueue@.+{-# INLINABLE unsafeEnqueue #-}+unsafeEnqueue :: Solver -> Lit -> Clause -> IO ()+unsafeEnqueue s@Solver{..} p from = do+  let v = lit2var p+  setNth assigns v $ lit2lbool p+  setNth level v =<< decisionLevel s+  setNth reason v from     -- NOTE: @from@ might be NULL!+  pushTo trail p++-- | __Pre-condition:__ propagation queue is empty.+{-# INLINE unsafeAssume #-}+unsafeAssume :: Solver -> Lit -> IO ()+unsafeAssume s@Solver{..} p = do+  pushTo trailLim =<< get' trail+  unsafeEnqueue s p NullClause
+ src/SAT/Mios/OptionParser.hs view
@@ -0,0 +1,145 @@+-- | (This is a part of MIOS.)+-- Command line option parser+{-# LANGUAGE Safe #-}++module SAT.Mios.OptionParser+       (+         MiosConfiguration (..)+       , defaultConfiguration+       , MiosProgramOption (..)+       , miosDefaultOption+       , miosOptions+       , miosUsage+       , miosParseOptions+       , miosParseOptionsFromArgs+       , toMiosConf+       )+       where++import System.Console.GetOpt (ArgDescr(..), ArgOrder(..), getOpt, OptDescr(..), usageInfo)+import System.Environment (getArgs)+import SAT.Mios.Types (MiosConfiguration (..), defaultConfiguration)++-- | configuration swithces+data MiosProgramOption = MiosProgramOption+                     {+                       _targetFile :: Maybe String+                     , _targets :: [String]+                     , _outputFile :: Maybe String+                     , _confVariableDecayRate :: !Double+                     , _confClauseDecayRate :: Double+--                     , _confRandomDecisionRate :: Int+                     , _confMaxSize :: !Int+                     , _confCheckAnswer :: !Bool+                     , _confVerbose :: !Bool+                     , _confBenchmark :: Integer+                     , _confBenchSeq :: !Int+                     , _confNoAnswer :: !Bool+                     , _confDumpStat :: !Int+                     , _validateAssignment :: !Bool+                     , _displayHelp :: !Bool+                     , _displayVersion :: !Bool+                     }++-- | default option settings+miosDefaultOption :: MiosProgramOption+miosDefaultOption = MiosProgramOption+  {+    _targetFile = Nothing+  , _targets = []+  , _outputFile = Nothing+  , _confVariableDecayRate = variableDecayRate defaultConfiguration+  , _confClauseDecayRate = clauseDecayRate defaultConfiguration+--  , _confRandomDecisionRate = randomDecisionRate defaultConfiguration+  , _confMaxSize = 4000000    -- 4,000,000 = 4M+  , _confCheckAnswer = False+  , _confVerbose = False+  , _confBenchmark = -1+  , _confBenchSeq = 0+  , _confNoAnswer = False+  , _confDumpStat = dumpStat defaultConfiguration+  , _validateAssignment = False+  , _displayHelp = False+  , _displayVersion = False+  }++-- | definition of mios option+miosOptions :: [OptDescr (MiosProgramOption -> MiosProgramOption)]+miosOptions =+  [+    Option ['d'] ["variable-decay-rate"]+    (ReqArg (\v c -> c { _confVariableDecayRate = read v }) (show (_confVariableDecayRate miosDefaultOption)))+    "[solver] variable activity decay rate (0.0 - 1.0)"+  , Option ['c'] ["clause-decay-rate"]+    (ReqArg (\v c -> c { _confClauseDecayRate = read v }) (show (_confClauseDecayRate miosDefaultOption)))+    "[solver] clause activity decay rate (0.0 - 1.0)"+--  , Option ['r'] ["random-decision-rate"]+--    (ReqArg (\v c -> c { _confRandomDecisionRate = read v }) (show (_confRandomDecisionRate miosDefaultOption)))+--    "[solver] random selection rate (0 - 1000)"+  , Option [] ["maxsize"]+    (ReqArg (\v c -> c { _confMaxSize = read v }) (show (_confMaxSize miosDefaultOption)))+    "[solver] limit of the number of variables"+  , Option [':'] ["validate-assignment"]+    (NoArg (\c -> c { _validateAssignment = True }))+    "[solver] read an assignment from STDIN and validate it"+  , Option [] ["validate"]+    (NoArg (\c -> c { _confCheckAnswer = True }))+    "[solver] self-check (satisfiable) assignment"+  , Option ['o'] ["output"]+    (ReqArg (\v c -> c { _outputFile = Just v }) "file")+    "[option] filename to store result"+{-+  , Option [] ["stdin"]+    (NoArg (\c -> c { _targetFile = Nothing }))+    "[option] read a CNF from STDIN instead of a file"+-}+  , Option ['v'] ["verbose"]+    (NoArg (\c -> c { _confVerbose = True }))+    "[option] display misc information"+  , Option ['X'] ["hide-solution"]+    (NoArg (\c -> c { _confNoAnswer = True }))+    "[option] hide solution"+  , Option [] ["benchmark"]+    (ReqArg (\v c -> c { _confBenchmark = read v }) "-1/0/N")+    "[devel] No/Exhaustive/N-second timeout benchmark"+  , Option [] ["sequence"]+    (ReqArg (\v c -> c { _confBenchSeq = read v }) "NUM")+    "[devel] set 2nd field of a CSV generated by benchmark"+  , Option [] ["dump"]+    (ReqArg (\v c -> c { _confDumpStat = read v }) (show (dumpStat defaultConfiguration)))+    "[devel] dump level; 1:solved, 2:reduction, 3:restart"+  , Option ['h'] ["help"]+    (NoArg (\c -> c { _displayHelp = True }))+    "[misc] display this message"+  , Option [] ["version"]+    (NoArg (\c -> c { _displayVersion = True }))+    "[misc] display program ID"+  ]++-- | generates help message+miosUsage :: String -> String+miosUsage mes = usageInfo mes miosOptions++-- | builds "MiosProgramOption" from string given as command option+miosParseOptions :: String -> [String] -> IO MiosProgramOption+miosParseOptions mes argv =+    case getOpt Permute miosOptions argv of+      (o, [], []) -> return $ foldl (flip id) miosDefaultOption o+      (o, l, []) -> do+        let conf = foldl (flip id) miosDefaultOption o+        return $ conf { _targetFile = Just (head l), _targets = l }+      (_, _, errs) -> ioError (userError (concat errs ++ miosUsage mes))++-- | builds "MiosProgramOption" from a String+miosParseOptionsFromArgs :: String -> IO MiosProgramOption+miosParseOptionsFromArgs mes = miosParseOptions mes =<< getArgs++-- | converts "MiosProgramOption" into "SIHConfiguration"+toMiosConf :: MiosProgramOption -> MiosConfiguration+toMiosConf opts = MiosConfiguration+                 {+                   variableDecayRate = _confVariableDecayRate opts+                 , clauseDecayRate = _confClauseDecayRate opts+--                 , randomDecisionRate = _confRandomDecisionRate opts+                 , dumpStat = _confDumpStat opts+                 }
+ src/SAT/Mios/Solver.hs view
@@ -0,0 +1,454 @@+-- | (This is a part of MIOS.)+-- Solver, the main data structure+{-# LANGUAGE+    MultiWayIf+  , RecordWildCards+  , ScopedTypeVariables+  , TupleSections+  , ViewPatterns+  #-}+{-# LANGUAGE Safe #-}++module SAT.Mios.Solver+       (+         -- * Solver+         Solver (..)+       , newSolver+         -- * Misc Accessors+       , nAssigns+       , nClauses+       , nLearnts+       , decisionLevel+       , valueVar+       , valueLit+       , locked+         -- * State Modifiers+       , setAssign+       , enqueue+       , assume+       , cancelUntil+         -- * Stats+       , StatIndex (..)+       , getStat+       , setStat+       , incrementStat+       , getStats+       , dumpSolver+       )+        where++import Control.Monad (unless, when)+import Data.List (intercalate)+import Numeric (showFFloat)+import SAT.Mios.Types+import SAT.Mios.Clause+import SAT.Mios.ClauseManager+import SAT.Mios.ClausePool++-- | __Fig. 2.(p.9)__ Internal State of the solver+data Solver = Solver+              {+                -------- Database+                clauses    :: !ClauseExtManager  -- ^ List of problem constraints.+              , learnts    :: !ClauseExtManager  -- ^ List of learnt clauses.+              , watches    :: !WatcherList       -- ^ list of constraint wathing 'p', literal-indexed+                -------- Assignment Management+              , assigns    :: !(Vec Int)         -- ^ The current assignments indexed on variables+              , phases     :: !(Vec Int)         -- ^ The last assignments indexed on variables+              , trail      :: !Stack             -- ^ List of assignments in chronological order+              , trailLim   :: !Stack             -- ^ Separator indices for different decision levels in 'trail'.+              , qHead      :: !Int'              -- ^ 'trail' is divided at qHead; assignment part and queue part+              , reason     :: !ClauseVector      -- ^ For each variable, the constraint that implied its value+              , level      :: !(Vec Int)         -- ^ For each variable, the decision level it was assigned+              , conflicts  :: !Stack             -- ^ Set of literals in the case of conflicts+                -------- Variable Order+              , activities :: !(Vec Double)      -- ^ Heuristic measurement of the activity of a variable+              , order      :: !VarHeap           -- ^ Keeps track of the dynamic variable order.+                -------- Configuration+              , config     :: !MiosConfiguration -- ^ search paramerters+              , nVars      :: !Int               -- ^ number of variables+              , claInc     :: !Double'           -- ^ Clause activity increment amount to bump with.+              , varInc     :: !Double'           -- ^ Variable activity increment amount to bump with.+              , rootLevel  :: !Int'              -- ^ Separates incremental and search assumptions.+                -------- DB Size Adjustment+              , learntSAdj :: Double'            -- ^ used in 'SAT.Mios.Main.search'+              , learntSCnt :: Int'               -- ^ used in 'SAT.Mios.Main.search'+              , maxLearnts :: Double'            -- ^ used in 'SAT.Mios.Main.search'+                -------- Working Memory+              , ok         :: !Int'              -- ^ internal flag+              , an'seen    :: !(Vec Int)         -- ^ used in 'SAT.Mios.Main.analyze'+              , an'toClear :: !Stack             -- ^ used in 'SAT.Mios.Main.analyze'+              , an'stack   :: !Stack             -- ^ used in 'SAT.Mios.Main.analyze'+              , an'lastDL  :: !Stack             -- ^ last decision level used in 'SAT.Mios.Main.analyze'+              , clsPool    :: ClausePool         -- ^ clause recycler+              , litsLearnt :: !Stack             -- ^ used in 'SAT.Mios.Main.analyze' and 'SAT.Mios.Main.search' to create a learnt clause+              , stats      :: !(Vec [Int])       -- ^ statistics information holder+              , lbd'seen   :: !(Vec Int)         -- ^ used in lbd computation+              , lbd'key    :: !Int'              -- ^ used in lbd computation+                -------- restart heuristics #62+              , emaDFast    :: !Double'          -- ^ fast ema value of LBD+              , emaDSlow    :: !Double'          -- ^ slow ema value of LBD+              , emaAFast    :: !Double'          -- ^ fast ema value of assignment+              , emaASlow    :: !Double'          -- ^ slow ema value of assignment+              , nextRestart :: !Int'             -- ^ next restart in number of conflict+              , restartMode :: Int'              -- ^ mode of restart+              }++-- | returns an everything-is-initialized solver from the arguments.+newSolver :: MiosConfiguration -> CNFDescription -> IO Solver+newSolver conf (CNFDescription nv dummy_nc _) =+  Solver+    -- Clause Database+    <$> newManager dummy_nc                -- clauses+    <*> newManager 2000                    -- learnts+    <*> newWatcherList nv 2                -- watches+    -- Assignment Management+    <*> newVec nv LBottom                  -- assigns+    <*> newVec nv LBottom                  -- phases+    <*> newStack nv                        -- trail+    <*> newStack nv                        -- trailLim+    <*> new' 0                             -- qHead+    <*> newClauseVector (nv + 1)           -- reason+    <*> newVec nv (-1)                     -- level+    <*> newStack nv                        -- conflicts+    -- Variable Order+    <*> newVec nv 0                        -- activities+    <*> newVarHeap nv                      -- order+    -- Configuration+    <*> return conf                        -- config+    <*> return nv                          -- nVars+    <*> new' 1.0                           -- claInc+    <*> new' 1.0                           -- varInc+    <*> new' 0                             -- rootLevel+    -- Learnt DB Size Adjustment+    <*> new' 100                           -- learntSAdj+    <*> new' 100                           -- learntSCnt+    <*> new' 2000                          -- maxLearnts+    -- Working Memory+    <*> new' LiftedT                       -- ok+    <*> newVec nv 0                        -- an'seen+    <*> newStack nv                        -- an'toClear+    <*> newStack nv                        -- an'stack+    <*> newStack nv                        -- an'lastDL+    <*> newClausePool 10                   -- clsPool+    <*> newStack nv                        -- litsLearnt+    <*> newVec (fromEnum EndOfStatIndex) 0 -- stats+    <*> newVec nv 0                        -- lbd'seen+    <*> new' 0                             -- lbd'key+    -- restart heuristics #62+    <*> new' 0.0                           -- emaDFast+    <*> new' 0.0                           -- emaDSlow+    <*> new' 0.0                           -- emaAFast+    <*> new' 0.0                           -- emaASlow+    <*> new' 100                           -- nextRestart+    <*> new' 1                             -- restartMode++--------------------------------------------------------------------------------+-- Accessors++-- | returns the number of current assigments.+{-# INLINE nAssigns #-}+nAssigns :: Solver -> IO Int+nAssigns = get' . trail++-- | returns the number of constraints (clauses).+{-# INLINE nClauses #-}+nClauses :: Solver -> IO Int+nClauses = get' . clauses++-- | returns the number of learnt clauses.+{-# INLINE nLearnts #-}+nLearnts :: Solver -> IO Int+nLearnts = get' . learnts++-- | returns the current decision level.+{-# INLINE decisionLevel #-}+decisionLevel :: Solver -> IO Int+decisionLevel = get' . trailLim++-- | returns the assignment (:: 'LiftedBool' = @[-1, 0, -1]@) from 'Var'.+{-# INLINE valueVar #-}+valueVar :: Solver -> Var -> IO Int+valueVar = getNth . assigns++-- | returns the assignment (:: 'LiftedBool' = @[-1, 0, -1]@) from 'Lit'.+{-# INLINE valueLit #-}+valueLit :: Solver -> Lit -> IO Int+valueLit (assigns -> a) p = (\x -> if positiveLit p then x else negate x) <$> getNth a (lit2var p)++-- | __Fig. 7. (p.11)__+-- returns @True@ if the clause is locked (used as a reason). __Learnt clauses only__+{-# INLINE locked #-}+locked :: Solver -> Clause -> IO Bool+locked s c = (c ==) <$> (getNth (reason s) . lit2var =<< getNth (lits c) 1)++-------------------------------------------------------------------------------- Statistics++-- | returns the value of 'StatIndex'.+{-# INLINE getStat #-}+getStat :: Solver -> StatIndex -> IO Int+getStat (stats -> v) (fromEnum -> i) = getNth v i++-- | sets to 'StatIndex'.+{-# INLINE setStat #-}+setStat :: Solver -> StatIndex -> Int -> IO ()+setStat (stats -> v) (fromEnum -> i) x = setNth v i x++-- | increments a stat data corresponding to 'StatIndex'.+{-# INLINE incrementStat #-}+incrementStat :: Solver -> StatIndex -> Int -> IO ()+incrementStat (stats -> v) (fromEnum -> i) k = modifyNth v (+ k) i++-- | returns the statistics as a list.+{-# INLINABLE getStats #-}+getStats :: Solver -> IO [(StatIndex, Int)]+getStats (stats -> v) = mapM (\i -> (i, ) <$> getNth v (fromEnum i)) [minBound .. maxBound :: StatIndex]++-------------------------------------------------------------------------------- State Modifiers++-- | assigns a value to the /n/-th variable+setAssign :: Solver -> Int -> LiftedBool -> IO ()+setAssign Solver{..} v x = setNth assigns v x++-- | __Fig. 9 (p.14)__+-- Puts a new fact on the propagation queue, as well as immediately updating the variable's value+-- in the assignment vector. If a conflict arises, @False@ is returned and the propagation queue is+-- cleared. The parameter 'from' contains a reference to the constraint from which 'p' was+-- propagated (defaults to @Nothing@ if omitted).+{-# INLINABLE enqueue #-}+enqueue :: Solver -> Lit -> Clause -> IO Bool+enqueue s@Solver{..} p from = do+{-+  -- bump psedue lbd of @from@+  when (from /= NullClause && learnt from) $ do+    l <- get' (lbd from)+    k <- (12 +) <$> decisionLevel s+    when (k < l) $ set' (lbd from) k+-}+  let signumP = lit2lbool p+  let v = lit2var p+  val <- valueVar s v+  if val /= LBottom+    then return $ val == signumP     -- Existing consistent assignment -- don't enqueue+    else do setNth assigns v signumP -- New fact, store it+            setNth level v =<< decisionLevel s+            setNth reason v from     -- NOTE: @from@ might be NULL!+            pushTo trail p+            return True++-- | __Fig. 12 (p.17)__+-- returns @False@ if immediate conflict.+--+-- __Pre-condition:__ propagation queue is empty+{-# INLINE assume #-}+assume :: Solver -> Lit -> IO Bool+assume s p = do+  pushTo (trailLim s) =<< get' (trail s)+  enqueue s p NullClause++-- | #M22: Revert to the states at given level (keeping all assignment at 'level' but not beyond).+{-# INLINABLE cancelUntil #-}+cancelUntil :: Solver -> Int -> IO ()+cancelUntil s@Solver{..} lvl = do+  dl <- decisionLevel s+  when (lvl < dl) $ do+    lim <- getNth trailLim (lvl + 1)+    ts <- get' trail+    ls <- get' trailLim+    let+      loopOnTrail :: Int -> IO ()+      loopOnTrail ((lim <) -> False) = return ()+      loopOnTrail c = do+        x <- lit2var <$> getNth trail c+        setNth phases x =<< getNth assigns x+        setNth assigns x LBottom+        -- #reason to set reason Null+        -- if we don't clear @reason[x] :: Clause@ here, @reason[x]@ remains as locked.+        -- This means we can't reduce it from clause DB and affects the performance.+        setNth reason x NullClause -- 'analyze` uses reason without checking assigns+        -- FIXME: #polarity https://github.com/shnarazk/minisat/blosb/master/core/Solver.cc#L212+        undo s x+        -- insertHeap s x              -- insertVerOrder+        loopOnTrail $ c - 1+    loopOnTrail ts+    shrinkBy trail (ts - lim)+    shrinkBy trailLim (ls - lvl)+    set' qHead =<< get' trail++-------------------------------------------------------------------------------- VarOrder++-- | Interfate to select a decision var based on variable activity.+instance VarOrder Solver where+{-+  -- | __Fig. 6. (p.10)__+  -- Creates a new SAT variable in the solver.+  newVar _ = return 0+    -- i <- nVars s+    -- Version 0.4:: push watches =<< newVec      -- push'+    -- Version 0.4:: push watches =<< newVec      -- push'+    -- push undos =<< newVec        -- push'+    -- push reason NullClause       -- push'+    -- push assigns LBottom+    -- push level (-1)+    -- push activities (0.0 :: Double)+    -- newVar order+    -- growQueueSized (i + 1) propQ+    -- return i+-}+  {-# SPECIALIZE INLINE update :: Solver -> Var -> IO () #-}+  update = increaseHeap+  {-# SPECIALIZE INLINE undo :: Solver -> Var -> IO () #-}+  undo s v = inHeap s v >>= (`unless` insertHeap s v)+  {-# SPECIALIZE INLINE select :: Solver -> IO Var #-}+  select s = do+    let+      asg = assigns s+      -- | returns the most active var (heap-based implementation)+      loop :: IO Var+      loop = do+        n <- numElementsInHeap s+        if n == 0+          then return 0+          else do+              v <- getHeapRoot s+              x <- getNth asg v+              if x == LBottom then return v else loop+    loop++-------------------------------------------------------------------------------- VarHeap++-- | A heap tree built from two 'Vec'.+-- This implementation is identical wtih that in Minisat-1.14.+-- Note: the zero-th element of @heap@ is used for holding the number of elements.+-- Note: VarHeap itself is not a @VarOrder@, because it requires a pointer to solver.+data VarHeap = VarHeap+                {+                  heap :: !Stack  -- order to var+                , idxs :: !Stack  -- var to order (index)+                }++newVarHeap :: Int -> IO VarHeap+newVarHeap n = do+  v1 <- newVec n 0+  v2 <- newVec n 0+  let+    loop :: Int -> IO ()+    loop ((<= n) -> False) = set' v1 n >> set' v2 n+    loop i = setNth v1 i i >> setNth v2 i i >> loop (i + 1)+  loop 1+  return $ VarHeap v1 v2++{-# INLINE numElementsInHeap #-}+numElementsInHeap :: Solver -> IO Int+numElementsInHeap = get' . heap . order++{-# INLINE inHeap #-}+inHeap :: Solver -> Var -> IO Bool+inHeap Solver{..} n = case idxs order of at -> (/= 0) <$> getNth at n++{-# INLINE increaseHeap #-}+increaseHeap :: Solver -> Int -> IO ()+increaseHeap s@Solver{..} n = case idxs order of+                                at -> inHeap s n >>= (`when` (percolateUp s =<< getNth at n))++{-# INLINABLE percolateUp #-}+percolateUp :: Solver -> Int -> IO ()+percolateUp Solver{..} start = do+  let VarHeap to at = order+  v <- getNth to start+  ac <- getNth activities v+  let+    loop :: Int -> IO ()+    loop i = do+      let iP = div i 2          -- parent+      if iP == 0+        then setNth to i v >> setNth at v i -- end+        else do+            v' <- getNth to iP+            acP <- getNth activities v'+            if ac > acP+              then setNth to i v' >> setNth at v' i >> loop iP -- loop+              else setNth to i v >> setNth at v i              -- end+  loop start++{-# INLINABLE percolateDown #-}+percolateDown :: Solver -> Int -> IO ()+percolateDown Solver{..} start = do+  let (VarHeap to at) = order+  n <- getNth to 0+  v <- getNth to start+  ac <- getNth activities v+  let+    loop :: Int -> IO ()+    loop i = do+      let iL = 2 * i            -- left+      if iL <= n+        then do+            let iR = iL + 1     -- right+            l <- getNth to iL+            r <- getNth to iR+            acL <- getNth activities l+            acR <- getNth activities r+            let (ci, child, ac') = if iR <= n && acL < acR then (iR, r, acR) else (iL, l, acL)+            if ac' > ac+              then setNth to i child >> setNth at child i >> loop ci+              else setNth to i v >> setNth at v i -- end+        else setNth to i v >> setNth at v i       -- end+  loop start++{-# INLINABLE insertHeap #-}+insertHeap :: Solver -> Var -> IO ()+insertHeap s@(order -> VarHeap to at) v = do+  n <- (1 +) <$> getNth to 0+  setNth at v n+  setNth to n v+  set' to n+  percolateUp s n++-- | returns the value on the root (renamed from @getmin@).+{-# INLINABLE getHeapRoot #-}+getHeapRoot :: Solver -> IO Int+getHeapRoot s@(order -> VarHeap to at) = do+  r <- getNth to 1+  l <- getNth to =<< getNth to 0 -- the last element's value+  setNth to 1 l+  setNth at l 1+  setNth at r 0+  modifyNth to (subtract 1) 0 -- pop+  n <- getNth to 0+  when (1 < n) $ percolateDown s 1+  return r++-------------------------------------------------------------------------------- dump++{-# INLINABLE dumpSolver #-}+-- | print statatistic data to stdio. This should be called after each restart.+dumpSolver :: DumpMode -> Solver -> IO ()++dumpSolver NoDump _ = return ()++dumpSolver DumpCSVHeader s@Solver{..} = do+  sts <- init <$> getStats s+  let labels = map (show . fst) sts  ++ ["emaDFast", "emaDSlow", "emaAFast", "emaASlow"]+  putStrLn $ intercalate "," labels++dumpSolver DumpCSV s@Solver{..} = do+  -- First update the stat data+  df <- get' emaDFast+  ds <- get' emaDSlow+  af <- get' emaAFast+  as <- get' emaASlow+  sts <- init <$> getStats s+  va <- get' trailLim+  setStat s NumOfVariable . (nVars -) =<< if va == 0 then get' trail else getNth trailLim 1+  setStat s NumOfAssigned =<< nAssigns s+  setStat s NumOfClause =<< get' clauses+  setStat s NumOfLearnt =<< get' learnts+  -- Additional data which type is Double+  let emas = [("emaDFast", df), ("emaDSlow", ds), ("emaAFast", af), ("emaASlow", as)]+      fs x = showFFloat (Just 3) x ""+      vals = map (show . snd) sts ++ map (fs . snd) emas+  putStrLn $ intercalate "," vals++-- | FIXME: use Util/Stat+dumpSolver DumpJSON _ = return ()                -- mode 2: JSON
+ src/SAT/Mios/Types.hs view
@@ -0,0 +1,337 @@+-- | (This is a part of MIOS.)+-- Basic data types used throughout mios.+{-# LANGUAGE+    BangPatterns+  , PatternSynonyms+  #-}+{-# LANGUAGE Safe #-}++module SAT.Mios.Types+       (+         -- * Interface to caller+         SolverResult+       , Certificate (..)+       , SolverException (..)+       , CNFDescription (..)+         -- * Solver Configuration+       , MiosConfiguration (..)+       , defaultConfiguration+         -- * internal structure+       ,  module SAT.Mios.Vec+         -- *  Variable+       , Var+       , bottomVar+       , int2var+         -- * Internal encoded Literal+       , Lit+       , lit2int+       , int2lit+       , bottomLit+       , positiveLit+       , lit2var+       , var2lit+       , negateLit+         -- * Assignment on the lifted Bool domain+       , LiftedBool+       , lit2lbool+       , Int (LiftedF, LiftedT, LBottom, Conflict)+       -- a heap+       , VarOrder (..)+         -- * statistics+       , StatIndex (..)+       , DumpMode (..)+{-+         -- * dump statistics+       , DumpTag (..)+       , DumpedValue+       , MiosStats (..)+       , QuadLearntC (..)+       , MiosDump (..)+-}+       )+       where++import Data.Bits+import SAT.Mios.Vec++-- | terminate and find an SAT/UNSAT answer+data Certificate+  = SAT [Int]+  | UNSAT [Int]                 -- FIXME: replace with DRAT+  deriving (Eq, Ord, Read, Show)++-- | abnormal termination flags+data SolverException+  = StateUNSAT                  -- 0+  | StateSAT                    -- 1+  | OutOfMemory                 -- 2+  | TimeOut                     -- 3+  | InternalInconsistent        -- 4+  | UndescribedError            -- 5+  deriving (Bounded, Enum, Eq, Ord, Show)++-- | the type that Mios returns+-- This captures the following three cases:+--  * solved with a satisfiable assigment,+--  * proved that it's an unsatisfiable problem, and+--  * aborted due to Mios specification or an internal error+type SolverResult = Either SolverException Certificate++-- | represents "Var".+type Var = Int++-- | Special constant in 'Var' (p.7)+bottomVar :: Var+bottomVar = 0++-- | converts a usual Int as literal to an internal 'Var' presentation.+--+-- >>> int2var 1+-- 1  -- the first literal is the first variable+-- >>> int2var 2+-- 2  -- literal @2@ is variable 2+-- >>> int2var (-2)+-- 2 -- literal @-2@ is corresponding to variable 2+--+{-# INLINE int2var #-}+int2var :: Int -> Int+int2var = abs++-- | The literal data has an 'index' method which converts the literal to+-- a "small" integer suitable for array indexing. The 'var'  method returns+-- the underlying variable of the literal, and the 'sign' method if the literal+-- is signed (False for /x/ and True for /-x/).+type Lit = Int++-- | Special constant in 'Lit' (p.7)+bottomLit :: Lit+bottomLit = 0++{-+-- | converts "Var" into 'Lit'+newLit :: Var -> Lit+newLit = error "newLit undefined"+-}++-- | returns @True@ if the literal is positive+{-# INLINE positiveLit #-}+positiveLit :: Lit -> Bool+positiveLit = even++-- | negates literal+--+-- >>> negateLit 2+-- 3+-- >>> negateLit 3+-- 2+-- >>> negateLit 4+-- 5+-- >>> negateLit 5+-- 4+{-# INLINE negateLit #-}+negateLit :: Lit -> Lit+negateLit l = complementBit l 0 -- if even l then l + 1 else l - 1++----------------------------------------+----------------- Var+----------------------------------------++-- | converts 'Lit' into 'Var'.+--+-- >>> lit2var 2+-- 1+-- >>> lit2var 3+-- 1+-- >>> lit2var 4+-- 2+-- >>> lit2var 5+-- 2+{-# INLINE lit2var #-}+lit2var :: Lit -> Var+lit2var !n = shiftR n 1++-- | converts a 'Var' to the corresponing literal.+--+-- >>> var2lit 1 True+-- 2+-- >>> var2lit 1 False+-- 3+-- >>> var2lit 2 True+-- 4+-- >>> var2lit 2 False+-- 5+{-# INLINE var2lit #-}+var2lit :: Var -> Bool -> Lit+var2lit !v True = shiftL v 1+var2lit !v _ = shiftL v 1 + 1++----------------------------------------+----------------- Int+----------------------------------------++-- | converts 'Int' into 'Lit' as @lit2int . int2lit == id@.+--+-- >>> int2lit 1+-- 2+-- >>> int2lit (-1)+-- 3+-- >>> int2lit 2+-- 4+-- >>> int2lit (-2)+-- 5+--+{-# INLINE int2lit #-}+int2lit :: Int -> Lit+int2lit n+  | 0 < n = 2 * n+  | otherwise = -2 * n + 1++-- | converts `Lit' into 'Int' as @int2lit . lit2int == id@.+--+-- >>> lit2int 2+-- 1+-- >>> lit2int 3+-- -1+-- >>> lit2int 4+-- 2+-- >>> lit2int 5+-- -2+{-# INLINE lit2int #-}+lit2int :: Lit -> Int+lit2int l = case divMod l 2 of+  (i, 0) -> i+  (i, _) -> - i++-- | Lifted Boolean domain (p.7) that extends 'Bool' with "⊥" means /undefined/+-- design note: _|_ should be null = 0; True literals are coded to even numbers. So it should be 2.+type LiftedBool = Int++-- | /FALSE/ on the Lifted Bool domain+pattern LiftedF :: Int+pattern LiftedF = -1++-- | /TRUE/ on the Lifted Bool domain+pattern LiftedT :: Int+pattern LiftedT = 1++-- | /UNDEFINED/ on the Lifted Bool domain+pattern LBottom :: Int+pattern LBottom = 0++-- | /CONFLICT/ on the Lifted Bool domain+pattern Conflict :: Int+pattern Conflict = 2++-- | returns the value of a literal as a 'LiftedBool'+{-# INLINE lit2lbool #-}+lit2lbool :: Lit -> LiftedBool+lit2lbool l = if positiveLit l then LiftedT else LiftedF++{-+-- | converts 'Bool' into 'LBool'+{-# INLINE lbool #-}+lbool :: Bool -> LiftedBool+lbool True = LTrue+lbool False = LFalse+-}++-- | Assisting ADT for the dynamic variable ordering of the solver.+-- The constructor takes references to the assignment vector and the activity+-- vector of the solver. The method 'select' will return the unassigned variable+-- with the highest activity.+class VarOrder o where+{-+  -- | constructor+  newVarOrder :: (VecFamily v1 Bool, VecFamily v2 Double) => v1 -> v2 -> IO o+  newVarOrder _ _ = error "newVarOrder undefined"++  -- | Called when a new variable is created.+  newVar :: o -> IO Var+  newVar = error "newVar undefined"+-}+  -- | should be called when a variable has increased in activity.+  update :: o -> Var -> IO ()+  update _  = error "update undefined"+{-+  -- | should be called when all variables have been assigned.+  updateAll :: o -> IO ()+  updateAll = error "updateAll undefined"+-}+  -- | should be called when a variable becomes unbound (may be selected again).+  undo :: o -> Var -> IO ()+  undo _ _  = error "undo undefined"++  -- | returns a new, unassigned var as the next decision.+  select :: o -> IO Var+  select    = error "select undefined"++-- | Misc information on a CNF+data CNFDescription = CNFDescription+  {+    _numberOfVariables :: !Int           -- ^ the number of variables+  , _numberOfClauses :: !Int             -- ^ the number of clauses+  , _pathname :: Maybe FilePath          -- ^ given filename+  }+  deriving (Eq, Ord, Read, Show)++-- | Solver's parameters; random decision rate was dropped.+data MiosConfiguration = MiosConfiguration+                         {+                           variableDecayRate  :: !Double  -- ^ decay rate for variable activity+                         , clauseDecayRate    :: !Double  -- ^ decay rate for clause activity+                         , dumpStat           :: !Int     -- ^ dump stats data during solving+                         }+  deriving (Eq, Ord, Read, Show)++-- | dafault configuration+--+-- * Minisat-1.14 uses @(0.95, 0.999, 0.2 = 20 / 1000)@.+-- * Minisat-2.20 uses @(0.95, 0.999, 0)@.+-- * Gulcose-4.0  uses @(0.8 , 0.999, 0)@.+-- * Mios-1.2     uses @(0.95, 0.999, 0)@.+--+defaultConfiguration :: MiosConfiguration+defaultConfiguration = MiosConfiguration 0.95 0.999 0++-------------------------------------------------------------------------------- Statistics++-- | stat index+data StatIndex =+    NumOfBackjump               -- ^ the number of backjump+  | NumOfRestart                -- ^ the number of restart+  | NumOfBlockRestart           -- ^ the number of blacking start+  | NumOfGeometricRestart       -- ^ the number of classic restart+  | NumOfPropagation            -- ^ the number of propagation+  | NumOfReduction              -- ^ the number of reduction+  | NumOfClause                 -- ^ the number of 'alive' given clauses+  | NumOfLearnt                 -- ^ the number of 'alive' learnt clauses+  | NumOfVariable               -- ^ the number of 'alive' variables+  | NumOfAssigned               -- ^ the number of assigned variables+  | EndOfStatIndex              -- ^ Don't use this dummy.+  deriving (Bounded, Enum, Eq, Ord, Read, Show)++-- | formats of state dump+data DumpMode = NoDump | DumpCSVHeader | DumpCSV | DumpJSON+  deriving (Bounded, Enum, Eq, Ord, Read, Show)++data DumpTag = TerminateS+             | PropagationS+             | ConflictS+             | LearntS+             | BackjumpS+             | RestartS+             | LearningRateS+             | ExtraS+             deriving (Bounded, Enum, Eq, Ord, Read, Show)++type DumpedValue = (DumpTag, Either Double Int)++newtype MiosStats = MiosStats [DumpedValue]+  deriving (Eq, Ord, Read, Show)++data MiosDump =+  MiosDump { _dumpedConf ::  (String, MiosConfiguration)+           , _dupmedCNFDesc :: CNFDescription+           , _dumpedStat :: MiosStats+           }+  deriving (Eq, Ord, Read, Show)
+ src/SAT/Mios/Util/BoolExp.hs view
@@ -0,0 +1,249 @@+{-# LANGUAGE BangPatterns, FlexibleInstances, ViewPatterns, UndecidableInstances #-}+{-# LANGUAGE Safe #-}++-- | Boolean Expression module to build CNF from arbitrary expressions+-- Tseitin translation: http://en.wikipedia.org/wiki/Tseitin_transformation+module SAT.Mios.Util.BoolExp+       (+         -- * Class & Type+         BoolComponent (..)+       , BoolForm (..)+         -- * Expression contructors+       , (-|-)+       , (-&-)+       , (-=-)+       , (-!-)+       , (->-)+       , neg+         -- * List Operation+       , disjunctionOf+       , (-|||-)+       , conjunctionOf+       , (-&&&-)+         -- * Convert function+       , asList+       , asList_+       , asLatex+       , asLatex_+       , numberOfVariables+       , numberOfClauses+       , tseitinBase+       )+       where++import Data.List (foldl', intercalate)++-- | the start index for the generated variables by Tseitin encoding+tseitinBase :: Int+tseitinBase = 1600000++data L = L Int++-- | class of objects that can be interpeted as a bool expression+class BoolComponent a where+  toBF :: a -> BoolForm   -- lift to BoolForm++-- | CNF expression+data BoolForm = Cnf (Int, Int) [[Int]]+    deriving (Eq, Show)++instance BoolComponent Int where+  toBF a = Cnf (abs a, max tseitinBase (abs a)) [[a]]++instance BoolComponent L where+  toBF (L a) = Cnf (abs a, max tseitinBase (abs a)) [[a]]++instance BoolComponent [Char] where+  toBF (read -> a) = Cnf (abs a, max tseitinBase (abs a)) [[a]]++instance BoolComponent BoolForm where+  toBF = id++-- | returns the number of variables in the 'BoolForm'+numberOfVariables :: BoolForm -> Int+numberOfVariables (Cnf (a, b) _) = a + b - tseitinBase++-- | returns the number of clauses in the 'BoolForm'+numberOfClauses :: BoolForm -> Int+numberOfClauses (Cnf _ l) = length l++boolFormTrue :: BoolForm+boolFormTrue = Cnf (-1, 1) []++boolFormFalse :: BoolForm+boolFormFalse = Cnf (-1, -1) []++instance BoolComponent Bool where+  toBF True = boolFormTrue+  toBF False = boolFormFalse++isTrue :: BoolForm -> Bool+isTrue = (== boolFormTrue)++isFalse :: BoolForm -> Bool+isFalse = (== boolFormFalse)++-- | return a 'clause' list only if it contains some real clause (not a literal)+clausesOf :: BoolForm -> [[Int]]+clausesOf cnf@(Cnf _ [[]]) = []+clausesOf cnf@(Cnf _ [[x]]) = []+clausesOf cnf@(Cnf _ l) = l++maxRank :: BoolForm -> Int+maxRank (Cnf (n, _) _) = n++-- | returns the number of valiable used as the output of this expression.+-- and returns itself it the expression is a literal.+-- Otherwise the number is a integer larger than 'tseitinBase'.+-- Therefore @1 + max tseitinBase the-returned-value@ is the next literal variable for future.+tseitinNumber :: BoolForm -> Int+tseitinNumber (Cnf (m, n) [[x]]) = x+tseitinNumber (Cnf (_, n) _) = n++renumber :: Int -> BoolForm -> (BoolForm, Int)+renumber base (Cnf (m, n) l)+  | l == [] = (Cnf (m, n) l, 0)+  | tseitinBase < base = (Cnf (m, n') l', n')+  | otherwise = (Cnf (n', tseitinBase) l', n')+  where+    l' = map (map f) l+    n' = maximum $ map maximum l'+    offset = base - tseitinBase - 1+    f x = if abs x < tseitinBase then x else signum x * (abs x + offset)++instance Ord BoolForm where+  compare (Cnf _ a) (Cnf _ b) = compare a b++-- | disjunction constructor+--+-- >>> asList $ "3" -|- "4"+-- [[3,4,-5],[-3,5],[-4,5]]+--+-- >>> asList (("3" -|- "4") -|- "-1")+-- [[3,4,-5],[-3,5],[-4,5],[5,-1,-6],[-5,6],[1,6]]+--+(-|-) :: (BoolComponent a, BoolComponent b) => a -> b -> BoolForm+(toBF -> e1) -|- (toBF -> e2')+  | isTrue e1 || isTrue e2' = boolFormTrue+  | isFalse e1 && isFalse e2' = boolFormFalse+  | isFalse e1 = e2'+  | isFalse e2' = e1+  | otherwise = Cnf (m, c) $ clausesOf e1 ++ clausesOf e2 ++ [[a, b, - c], [- a, c], [- b, c]]+  where+    a = tseitinNumber e1+    (e2, b) = renumber (1 + max tseitinBase a) e2'+    m = max (maxRank e1) (maxRank e2)+    c = 1 + max tseitinBase (max a b)++-- | conjunction constructor+--+-- >>> asList $ "3" -&- "-2"+-- [[-3,2,4],[3,-4],[-2,-4]]+--+-- >>> asList $ "3" -|- ("1" -&- "2")+-- [[-1,-2,4],[1,-4],[2,-4],[3,4,-5],[-3,5],[-4,5]]+--+(-&-) :: (BoolComponent a, BoolComponent b) => a -> b -> BoolForm+(toBF -> e1) -&- (toBF -> e2')+  | isTrue e1 && isTrue e2' = boolFormTrue+  | isFalse e1 || isFalse e2' = boolFormFalse+  | isTrue e1 = e2'+  | isTrue e2' = e1+  | otherwise = Cnf (m, c) $ clausesOf e1 ++ clausesOf e2 ++ [[- a, - b, c], [a, - c], [b, - c]]+  where+    a = tseitinNumber e1+    (e2, b) = renumber (1 + max tseitinBase a) e2'+    m = max (maxRank e1) (maxRank e2)+    c = 1 + max tseitinBase (max a b)++-- | negate a form+--+-- >>> asList $ neg ("1" -|- "2")+-- [[1,2,-3],[-1,3],[-2,3],[-3,-4],[3,4]]+neg :: (BoolComponent a) => a -> BoolForm+neg (toBF -> e) =+  Cnf (m, c) $ clausesOf e ++ [[- a, - c], [a, c]]+  where+    a = tseitinNumber e+    m = maxRank e+    c = 1 + max tseitinBase a++-- | equal on BoolForm+(-=-) :: (BoolComponent a, BoolComponent b) => a -> b -> BoolForm+(toBF -> e1) -=- (toBF -> e2) = (e1 -&- e2) -|- (neg e1 -&- neg e2)++-- | negation on BoolForm+(-!-) :: (BoolComponent a, BoolComponent b) => a -> b -> BoolForm+(toBF -> e1) -!- (toBF -> e2) = (neg e1 -&- e2) -|- (e1 -&- neg e2)++-- | implication as a short cut+--+-- >>> asList ("1" ->- "2")+-- [[-1,-3],[1,3],[3,2,-4],[-3,4],[-2,4]]+(->-) :: (BoolComponent a, BoolComponent b) => a -> b -> BoolForm+(toBF -> a) ->- (toBF -> b) = (neg a) -|- b++-- | merge [BoolForm] by '(-|-)'+disjunctionOf :: [BoolForm] -> BoolForm+disjunctionOf [] = boolFormFalse+disjunctionOf (x:l) = foldl' (-|-) x l++-- | an alias of 'disjunctionOf'+(-|||-) :: [BoolForm] -> BoolForm+(-|||-) = disjunctionOf++-- | merge [BoolForm] by '(-&-)'+conjunctionOf :: [BoolForm] -> BoolForm+conjunctionOf [] = boolFormTrue+conjunctionOf (x:l) = foldl' (-&-) x l++-- | an alias of 'conjunctionOf'+(-&&&-) :: [BoolForm] -> BoolForm+(-&&&-) = conjunctionOf++-- | converts a BoolForm to "[[Int]]"+asList_ :: BoolForm -> [[Int]]+asList_ cnf@(Cnf (m,_) _)+  | isTrue cnf = []+  | isFalse cnf = [[]]+  | otherwise = l'+  where+    (Cnf _ l', _) = renumber (m + 1) cnf++-- | converts a *satisfied* BoolForm to "[[Int]]"+asList :: BoolForm -> [[Int]]+asList cnf@(Cnf (m,n) l)+  | isTrue cnf = []+  | isFalse cnf = [[]]+  | n <= tseitinBase = l+  | otherwise = [m'] : l'+  where+    (Cnf (m', _) l', _) = renumber (m + 1) cnf++-- | make latex string from CNF, using 'asList_'+--+-- >>> asLatex $ "3" -|- "4"+-- "\\begin{displaymath}\n( x_{3} \\vee x_{4} )\n\\end{displaymath}\n"+--+asLatex_ :: BoolForm -> String+asLatex_ b = beg ++ s ++ end+  where+    beg = "\\begin{displaymath}\n"+    end = "\n\\end{displaymath}\n"+    s = intercalate " \\wedge " [ makeClause c | c <- asList_ b]+    makeClause c = "(" ++ intercalate "\\vee" [makeLiteral l | l <- c] ++ ")"+    makeLiteral l+      | 0 < l = " x_{" ++ show l ++ "} "+      | otherwise = " \\neg " ++ "x_{" ++ show (negate l) ++ "} "++-- | make latex string from CNF, using 'asList'+asLatex :: BoolForm -> String+asLatex b = beg ++ s ++ end+  where+    beg = "\\begin{displaymath}\n"+    end = "\n\\end{displaymath}\n"+    s = intercalate " \\wedge " [ makeClause c | c <- asList b]+    makeClause c = "(" ++ intercalate "\\vee" [makeLiteral l | l <- c] ++ ")"+    makeLiteral l+      | 0 < l = " x_{" ++ show l ++ "} "+      | otherwise = " \\neg " ++ "x_{" ++ show (negate l) ++ "} "
+ src/SAT/Mios/Util/DIMACS.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE Safe #-}++-- | Read/Write a CNF file only with ghc standard libraries+module SAT.Mios.Util.DIMACS+       (+         -- * Input+         fromFile+       , clauseListFromFile+       , fromMinisatOutput+       , clauseListFromMinisatOutput+         -- * Output+       , toFile+       , toDIMACSString+       , asDIMACSString+       , asDIMACSString_+         -- * Bool Operation+       , module SAT.Mios.Util.BoolExp+       )+       where+import SAT.Mios.Util.DIMACS.Reader+import SAT.Mios.Util.DIMACS.Writer+import SAT.Mios.Util.DIMACS.MinisatReader+import SAT.Mios.Util.BoolExp++-- | String from BoolFrom+asDIMACSString :: BoolForm -> String+asDIMACSString = toDIMACSString . asList++-- | String from BoolFrom+asDIMACSString_ :: BoolForm -> String+asDIMACSString_ = toDIMACSString . asList_
+ src/SAT/Mios/Util/DIMACS/MinisatReader.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE Safe #-}++-- | Read an output file of minisat+module SAT.Mios.Util.DIMACS.MinisatReader+       (+         -- * Interface+         fromMinisatOutput+       , clauseListFromMinisatOutput+       )+       where+-- import Control.Applicative ((<$>), (<*>), (<*), (*>))+import Data.Char+import Text.ParserCombinators.ReadP++-- parser+-- |parse a non-signed integer+{-# INLINE pint #-}+pint :: ReadP Int+pint = do+  n <- munch isDigit+  return (read n :: Int)++{-# INLINE mint #-}+mint :: ReadP Int+mint = do+  char '-'+  n <- munch isDigit+  return (- (read n::Int))++-- |parse a (signed) integer+{-# INLINE int #-}+int :: ReadP Int+int = mint <++ pint++-- |return integer list that terminates at zero+{-# INLINE seqNums #-}+seqNums :: ReadP [Int]+seqNums = do+  skipSpaces+  x <- int+  skipSpaces+  if x == 0 then return []  else (x :) <$> seqNums++-- |top level interface for parsing CNF+{-# INLINE parseMinisatOutput #-}+parseMinisatOutput :: ReadP ((Int, Int), [Int])+parseMinisatOutput = do+  string "SAT"+  skipSpaces+  l <- seqNums+  return ((length l,0), l)++-- |read a minisat output:+-- ((numbefOfVariables, 0), [Literal])+--+-- >>>  fromFile "result"+-- ((3, 0), [1, -2, 3])+--+{-# INLINE fromMinisatOutput #-}+fromMinisatOutput :: FilePath -> IO (Maybe ((Int, Int), [Int]))+fromMinisatOutput f = do+  c <- readFile f+  case readP_to_S parseMinisatOutput c of+    [(a, _)] -> return $ Just a+    _ -> return Nothing++-- | return clauses as [[Int]] from 'file'+--+-- >>> clauseListFromMinisatOutput "result"+-- [1,-2,3]+--+clauseListFromMinisatOutput :: FilePath -> IO [Int]+clauseListFromMinisatOutput l = do+  res <- fromMinisatOutput l+  case res of+    Just p -> return (snd p)+    _ -> return []
+ src/SAT/Mios/Util/DIMACS/Reader.hs view
@@ -0,0 +1,143 @@+{-# LANGUAGE Safe #-}++-- | Read a CNF file without haskell-platform+module SAT.Mios.Util.DIMACS.Reader+       (+         -- * Interface+         fromFile+       , clauseListFromFile+       )+       where+import Control.Applicative ((<$>), (<*>), (<*), (*>))+import Data.Char+import Text.ParserCombinators.ReadP++-- parser+{-# INLINE newline #-}+newline :: ReadP Char+newline = char '\n'++{-# INLINE digit #-}+digit :: ReadP Char+digit = satisfy isDigit++{-# INLINE spaces #-}+spaces :: ReadP String+spaces = munch (`elem` " \t")++{-# INLINE noneOf #-}+noneOf :: Foldable t => t Char -> ReadP Char+noneOf s = satisfy (`notElem` s)++-- |parse a non-signed integer+{-# INLINE pint #-}+pint :: ReadP Int+pint = do+  n <- munch isDigit+  return (read n :: Int)++{-# INLINE mint #-}+mint :: ReadP Int+mint = do+  char '-'+  n <- munch isDigit+  return (- (read n::Int))++-- |parse a (signed) integer+{-# INLINE int #-}+int :: ReadP Int+int = mint <++ pint++-- |Parse something like: p FORMAT VARIABLES CLAUSES+{-# INLINE problemLine #-}+problemLine :: ReadP (Int, Int)+problemLine = do+  char 'p'+  skipSpaces+  (string "cnf" <++ string "CNF")+  skipSpaces+  vars <- pint+  skipSpaces+  clas <- pint+  spaces+  newline+  return (vars, clas)++-- |Parse something like: c This in an example of a comment line.+{-# INLINE commentLines #-}+commentLines :: ReadP ()+commentLines = do+  l <- look+  if (head l)  == 'c'+    then do+      munch ('\n' /=)+      newline+      commentLines+    else return ()++_commentLines :: ReadP ()+_commentLines = do+  char 'c'+  munch ('\n' /=)+  newline+  l <- look+  if (head l)  == 'c' then commentLines else return ()++-- |Parse the preamble part+{-# INLINE preambleCNF #-}+preambleCNF :: ReadP (Int, Int)+preambleCNF = do+  commentLines+  problemLine++-- |return integer list that terminates at zero+{-# INLINE seqNums #-}+seqNums :: ReadP [Int]+seqNums = do+  skipSpaces+  x <- int+  skipSpaces+  if (x == 0) then return []  else (x :) <$> seqNums++-- |Parse something like: 1 -2 0 4 0 -3 0+{-# INLINE parseClauses #-}+parseClauses :: Int -> ReadP [[Int]]+parseClauses n = count n seqNums++-- |top level interface for parsing CNF+{-# INLINE parseCNF #-}+parseCNF :: ReadP ((Int, Int), [[Int]])+parseCNF = do+  a <- preambleCNF+  b <- parseClauses (snd a)+  return (a, b)++-- |driver:: String -> Either ParseError Int+driver :: String -> [([[Int]], String)]+driver input = readP_to_S (parseClauses 1) input++-- |read a CNF file and return:+-- ((numbefOfVariables, numberOfClauses), [Literal])+--+-- >>> fromFile "acnf"+-- ((3, 4), [[1, 2], [-2, 3], [-1, 2, -3], [3]]+--+{-# INLINE fromFile #-}+fromFile :: FilePath -> IO (Maybe ((Int, Int), [[Int]]))+fromFile f = do+  c <- readFile f+  case readP_to_S parseCNF c of+    [(a, _)] -> return $ Just a+    _ -> return Nothing++-- | return clauses as [[Int]] from 'file'+--+-- >>> clauseListFromFile "a.cnf"+-- [[1, 2], [-2, 3], [-1, 2, -3], [3]]+--+clauseListFromFile :: FilePath -> IO [[Int]]+clauseListFromFile l = do+  res <- fromFile l+  case res of+    Just (_, l) -> return l+    _ -> return []
+ src/SAT/Mios/Util/DIMACS/Writer.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE Safe #-}++-- | Write SAT data to DIMACS file+module SAT.Mios.Util.DIMACS.Writer+       (+         -- * Interface+         toFile+       , toDIMACSString+       , toString+       , toLatexString+       )+       where+import Data.List (intercalate, nub, sort)+import System.IO++-- | Write the DIMACS to file 'f', using 'toDIMACSString'+toFile :: FilePath -> [[Int]] -> IO ()+toFile f l = writeFile f $ toDIMACSString l++-- | Convert [Clause] to String, where Clause is [Int]+--+-- >>> toDIMACSString []+-- "p cnf 0 0\n"+--+-- >>> toDIMACSString [[-1, 2], [-3, -4]]+-- "p cnf 4 2\n-1 2 0\n-3 -4 0\n"+--+-- >>> toDIMACSString [[1], [-2], [-3, -4], [1,2,3,4]]+-- "p cnf 4 4\n1 0\n-2 0\n-3 -4 0\n1 2 3 4 0\n"+--+toDIMACSString :: [[Int]] -> String+toDIMACSString l = hdr ++ str+  where+    hdr = "p cnf " ++ show numV ++ " " ++ show numC ++ "\n"+    numC = length l+    numV = last $ nub $ sort $ map abs $ concat l+    str = concat [intercalate " " (map show c) ++ " 0\n" | c <- l]++-- | converts @[[Int]]@ to a String+toString  :: [[Int]] -> String -> String -> String+toString l and' or' = intercalate a ["(" ++ intercalate o [ lit x | x <- c] ++ ")" | c <- l]+  where+    lit x+      | 0 <= x = "X" ++ show x+      | otherwise = "-X" ++ show (abs x)+    a = pad and'+    o = pad or'+    pad s = " " ++ s ++ " "++-- | converts @[[Int]]@ to a LaTeX expression+toLatexString  :: [[Int]] -> String+toLatexString l = "\\begin{eqnarray*}\n" ++ intercalate a ["(" ++ intercalate o [ lit x | x <- c] ++ ")" | c <- l] ++ "\n\\end{eqnarray*}"+  where+    lit x+      | 0 <= x = "X_{" ++ show x ++ "}"+      | otherwise = "\\overline{X_{" ++ show (abs x) ++ "}}"+    a = " \n\\wedge "+    o = " \\vee "
+ src/SAT/Mios/Validator.hs view
@@ -0,0 +1,69 @@+-- | (This is a part of MIOS.)+-- Validate an assignment+{-# LANGUAGE+    RecordWildCards+  , ViewPatterns+  #-}+{-# LANGUAGE Safe #-}++module SAT.Mios.Validator+       (+         validate+--       , checkUniqueness+       )+       where++import Control.Monad (when)+import Data.Foldable (toList)+import Data.List (sort)+import SAT.Mios.Types+import SAT.Mios.Clause+import SAT.Mios.ClauseManager+import SAT.Mios.Solver++-- | validates the assignment even if the implementation of 'Solver' is wrong; we re-implement some functions here.+validate :: Traversable t => Solver -> t Int -> IO Bool+validate s t = do+  assignment <- newVec (1 + nVars s) (0 :: Int) :: IO (Vec Int)+  vec <- getClauseVector (clauses s)+  nc <- get' (clauses s)+  let+    lst = map int2lit $ toList t+    inject :: Lit -> IO ()+    inject l = setNth assignment (lit2var l) $ lit2lbool l+    -- returns True if the literal is satisfied under the assignment+    satisfied :: Lit -> IO Bool+    satisfied l+      | positiveLit l = (LiftedT ==) <$> getNth assignment (lit2var l)+      | otherwise     = (LiftedF ==) <$> getNth assignment (lit2var l)+    -- returns True is any literal in the given list+    satAny :: [Lit] -> IO Bool+    satAny [] = return False+    satAny (l:ls) = do+      sat' <- satisfied l+      if sat' then return True else satAny ls+    -- traverses all clauses in 'clauses'+    loopOnVector :: Int -> IO Bool+    loopOnVector ((< nc) -> False) = return True+    loopOnVector i = do+      sat' <- satAny =<< asList =<< getNth vec i+      if sat' then loopOnVector (i + 1) else return False+  if null lst+    then error "validator got an empty assignment."+    else mapM_ inject lst >> loopOnVector 0++-- | checks uniqueness of learnts+checkUniqueness :: Solver -> Clause -> IO ()+checkUniqueness Solver{..} c = do+  n <- get' learnts+  cvec <- getClauseVector learnts+  cls <- sort <$> asList c+  let+    loop :: Int -> IO ()+    loop ((< n) -> False) = return ()+    loop i = do+      c' <- getNth cvec i+      cls' <- sort <$> asList c'+      when (cls' == cls) $ errorWithoutStackTrace "reinsert a same clause"+      loop (i + 1)+  loop 0
+ src/SAT/Mios/Vec.hs view
@@ -0,0 +1,359 @@+-- | (This is a part of MIOS.)+-- Abstraction Layer for Mutable Vectors+{-# LANGUAGE+    BangPatterns+  , FlexibleContexts+  , FlexibleInstances+  , FunctionalDependencies+  , MultiParamTypeClasses+  , TypeFamilies+  #-}+{-# LANGUAGE Trustworthy #-}++module SAT.Mios.Vec+       (+         -- * Vector class and type+         VecFamily (..)+       , Vec (..)+         -- * SingleStorage+       , SingleStorage (..)+       , Bool'+       , Double'+       , Int'+         -- * Stack+       , StackFamily (..)+       , Stack+       , newStackFromList+       , realLengthOfStack+       , sortStack+       )+       where++import qualified Data.Vector.Unboxed.Mutable as UV+import qualified Data.Primitive.ByteArray as BA+import Control.Monad.Primitive++-------------------------------------------------------------------------------- VecFamily+-- | The interface on vectors.+class VecFamily v a | v -> a where+  -- | returns the /n/-th value.+  getNth ::v -> Int -> IO a+  -- | sets the /n/-th value.+  setNth :: v -> Int -> a -> IO ()+  -- | erases all elements in it.+  reset:: v -> IO ()+  -- | returns the /n/-th value (index starts from zero in any case).+  -- | swaps two elements.+  swapBetween :: v -> Int -> Int -> IO ()+  -- | calls the update function.+  modifyNth :: v -> (a -> a) -> Int -> IO ()+  -- | returns a new vector.+  newVec :: Int -> a -> IO v+  -- | sets all elements.+  setAll :: v -> a -> IO ()+  -- | extends the size of stack by /n/; note: values in new elements aren't initialized maybe.+  growBy :: v -> Int -> IO v+  -- | converts to a list.+  asList :: v -> IO [a]+  {-# MINIMAL getNth, setNth #-}+  reset = errorWithoutStackTrace "no default method: reset"+  swapBetween = errorWithoutStackTrace "no default method: swapBetween"+  modifyNth = errorWithoutStackTrace "no default method: modifyNth"+  newVec = errorWithoutStackTrace "no default method: newVec"+  setAll = errorWithoutStackTrace "no default method: setAll"+  asList = errorWithoutStackTrace "no default method: asList"+  growBy = errorWithoutStackTrace "no default method: growBy"+  -- | (FOR DEBUG) dump the contents.+  -- dump :: Show a => String -> v -> IO String+  -- dump msg v = (msg ++) . show <$> asList v++-------------------------------------------------------------------------------- Vec+-- | Another abstraction layer on 'Vector' which reserves zero element for internal use.+-- __Note__: If you want to use the 0-th element, use @UVector Int@.++data family Vec a;++-------------------------------------------------------------------------------- UVector++-- | A thin abstract layer for mutable unboxed Vector+type UVector a = UV.IOVector a++instance VecFamily (UVector Int) Int where+  {-# SPECIALIZE INLINE getNth :: UVector Int -> Int -> IO Int #-}+  getNth = UV.unsafeRead+  {-# SPECIALIZE INLINE setNth :: UVector Int -> Int -> Int -> IO () #-}+  setNth = UV.unsafeWrite+  {-# SPECIALIZE INLINE modifyNth :: UVector Int -> (Int -> Int) -> Int -> IO () #-}+  modifyNth = UV.unsafeModify+  {-# SPECIALIZE INLINE swapBetween:: UVector Int -> Int -> Int -> IO () #-}+  swapBetween = UV.unsafeSwap+  {-# SPECIALIZE INLINE newVec :: Int -> Int -> IO (UVector Int) #-}+  newVec n 0 = UV.new n+  newVec n x = do v <- UV.new n+                  UV.set v x+                  return v+  {-# SPECIALIZE INLINE setAll :: UVector Int -> Int -> IO () #-}+  setAll = UV.set+  {-# SPECIALIZE INLINE growBy :: UVector Int -> Int -> IO (UVector Int) #-}+  growBy = UV.unsafeGrow+  asList v = mapM (UV.unsafeRead v) [0 .. UV.length v - 1]++-- Note: type @[Int]@ is selected for 'UVector' not to export it.+data instance Vec [Int] = Vec (UVector Int)++instance VecFamily (Vec [Int]) Int where+  {-# SPECIALIZE INLINE getNth :: Vec [Int] -> Int -> IO Int #-}+  getNth (Vec v) = UV.unsafeRead v+  {-# SPECIALIZE INLINE setNth :: Vec [Int] -> Int -> Int -> IO () #-}+  setNth (Vec v) = UV.unsafeWrite v+  {-# SPECIALIZE INLINE reset :: Vec [Int] -> IO () #-}+  reset (Vec v) = setNth v 0 0+  {-# SPECIALIZE INLINE modifyNth :: Vec [Int] -> (Int -> Int) -> Int -> IO () #-}+  modifyNth (Vec v) = UV.unsafeModify v+  {-# SPECIALIZE INLINE swapBetween :: Vec [Int] -> Int -> Int -> IO () #-}+  swapBetween (Vec v) = UV.unsafeSwap v+  {-# SPECIALIZE INLINE newVec :: Int -> Int -> IO (Vec [Int]) #-}+  newVec n x = Vec <$> newVec (n + 1) x+  {-# SPECIALIZE INLINE setAll :: Vec [Int] -> Int -> IO () #-}+  setAll (Vec v) = UV.set v+  {-# SPECIALIZE INLINE growBy :: Vec [Int] -> Int -> IO (Vec [Int]) #-}+  growBy (Vec v) n = Vec <$> UV.unsafeGrow v n+  asList (Vec v) = mapM (getNth v) [0 .. UV.length v - 1]++{- NOT IN USE+data instance Vec [Double] = Vec (UVector Double)++instance VecFamily (UVector Double) Double where+  {-# SPECIALIZE INLINE getNth :: UVector Double -> Int -> IO Double #-}+  getNth = UV.unsafeRead+  {-# SPECIALIZE INLINE setNth :: UVector Double -> Int -> Double -> IO () #-}+  setNth = UV.unsafeWrite+  {-# SPECIALIZE INLINE modifyNth :: UVector Double -> (Double -> Double) -> Int -> IO () #-}+  modifyNth = UV.unsafeModify+  {-# SPECIALIZE INLINE swapBetween:: UVector Double -> Int -> Int -> IO () #-}+  swapBetween = UV.unsafeSwap+  {-# SPECIALIZE INLINE newVec :: Int -> Double -> IO (UVector Double) #-}+  newVec n x = do v <- UV.new n+                  UV.set v x+                  return v+  {-# SPECIALIZE INLINE setAll :: UVector Double -> Double -> IO () #-}+  setAll = UV.set+  {-# SPECIALIZE INLINE growBy :: UVector Double -> Int -> IO (UVector Double) #-}+  growBy = UV.unsafeGrow+  asList v = mapM (UV.unsafeRead v) [0 .. UV.length v - 1]++instance VecFamily (Vec Double) Double where+  {-# SPECIALIZE INLINE getNth :: Vec Double -> Int -> IO Double #-}+  getNth (Vec v) = UV.unsafeRead v+  {-# SPECIALIZE INLINE setNth :: Vec Double -> Int -> Double -> IO () #-}+  setNth (Vec v) = UV.unsafeWrite v+  {-# SPECIALIZE INLINE modifyNth :: Vec Double -> (Double -> Double) -> Int -> IO () #-}+  modifyNth (Vec v) = UV.unsafeModify v+  {-# SPECIALIZE INLINE swapBetween :: Vec Double -> Int -> Int -> IO () #-}+  swapBetween (Vec v) = UV.unsafeSwap v+  {-# SPECIALIZE INLINE newVec :: Int -> Double -> IO (Vec Double) #-}+  newVec n x = Vec <$> newVec (n + 1) x+  {-# SPECIALIZE INLINE setAll :: Vec Double -> Double -> IO () #-}+  setAll (Vec v) = UV.set v+  {-# SPECIALIZE INLINE growBy :: Vec Double -> Int -> IO (Vec Double) #-}+  growBy (Vec v) n = Vec <$> UV.unsafeGrow v n+-}++-------------------------------------------------------------------------------- ByteArray++data instance Vec Int = ByteArrayInt (BA.MutableByteArray RealWorld)+data instance Vec Double = ByteArrayDouble (BA.MutableByteArray RealWorld)++type ByteArrayInt = Vec Int+type ByteArrayDouble = Vec Double++instance VecFamily ByteArrayInt Int where+  {-# SPECIALIZE INLINE getNth :: ByteArrayInt -> Int -> IO Int #-}+  getNth (ByteArrayInt v) i = BA.readByteArray v i+  {-# SPECIALIZE INLINE setNth :: ByteArrayInt -> Int -> Int -> IO () #-}+  setNth (ByteArrayInt v) i x = BA.writeByteArray v i x+  {-# SPECIALIZE INLINE modifyNth :: ByteArrayInt -> (Int -> Int) -> Int -> IO () #-}+  modifyNth (ByteArrayInt v) f i = BA.writeByteArray v i . f =<< BA.readByteArray v i+  {-# SPECIALIZE INLINE swapBetween:: ByteArrayInt -> Int -> Int -> IO () #-}+  swapBetween (ByteArrayInt v) i j = do x <- BA.readByteArray v i+                                        y <- BA.readByteArray v j+                                        BA.writeByteArray v i (y :: Int)+                                        BA.writeByteArray v j (x :: Int)+  {-# SPECIALIZE INLINE reset :: ByteArrayInt -> IO () #-}+  reset (ByteArrayInt v) = BA.writeByteArray v 0 (0 :: Int)+  newVec n k = do v <- BA.newByteArray (8 * (n + 1))+                  BA.writeByteArray v 0 (0 :: Int)+                  BA.setByteArray v 1 n k+                  return $ ByteArrayInt v+  asList (ByteArrayInt v) = mapM (BA.readByteArray v) [0 .. div (BA.sizeofMutableByteArray v) 8 - 1]++instance VecFamily ByteArrayDouble Double where+  {-# SPECIALIZE INLINE getNth :: ByteArrayDouble -> Int -> IO Double #-}+  getNth (ByteArrayDouble v) i = BA.readByteArray v i+  {-# SPECIALIZE INLINE setNth :: ByteArrayDouble -> Int -> Double -> IO () #-}+  setNth (ByteArrayDouble v) i x = BA.writeByteArray v i x+  {-# SPECIALIZE INLINE modifyNth :: ByteArrayDouble -> (Double -> Double) -> Int -> IO () #-}+  modifyNth (ByteArrayDouble v) f i = BA.writeByteArray v i . f =<< BA.readByteArray v i+  {-# SPECIALIZE INLINE swapBetween:: ByteArrayDouble -> Int -> Int -> IO () #-}+  swapBetween (ByteArrayDouble v) i j = do x <- BA.readByteArray v i+                                           y <- BA.readByteArray v j+                                           BA.writeByteArray v i (y :: Int)+                                           BA.writeByteArray v j (x :: Int)+  {-# SPECIALIZE INLINE reset :: ByteArrayDouble -> IO () #-}+  reset (ByteArrayDouble v) = BA.writeByteArray v 0 (0 :: Double)+  newVec n k = do v <- BA.newByteArray (8 * (n + 1))+                  BA.writeByteArray v 0 (0 :: Double)+                  BA.setByteArray v 1 n k+                  return $ ByteArrayDouble v+  asList (ByteArrayDouble v) = mapM (BA.readByteArray v) [0 .. div (BA.sizeofMutableByteArray v) 8 - 1]++-------------------------------------------------------------------------------- SingleStorage++-- | Interface for single (one-length vector) mutable data+class SingleStorage s t | s -> t where+  -- | allocates and returns an new data.+  new' :: t -> IO s+  -- | gets the value.+  get' :: s -> IO t+  -- | sets the value.+  set' :: s -> t -> IO ()+  -- | calls an update function on it.+  modify' :: s -> (t -> t) -> IO ()+  {-# MINIMAL get', set' #-}+  new' = undefined+  modify' = undefined++-- | Mutable Bool+type Bool' = UV.IOVector Bool++instance SingleStorage Bool' Bool where+  {-# SPECIALIZE INLINE new' :: Bool -> IO Bool' #-}+  new' k = do s <- UV.new 1+              UV.unsafeWrite s 0 k+              return s+  {-# SPECIALIZE INLINE get' :: Bool' -> IO Bool #-}+  get' val = UV.unsafeRead val 0+  {-# SPECIALIZE INLINE set' :: Bool' -> Bool -> IO () #-}+  set' val !x = UV.unsafeWrite val 0 x+  {-# SPECIALIZE INLINE modify' :: Bool' -> (Bool -> Bool) -> IO () #-}+  modify' val f = UV.unsafeModify val f 0++-- | Mutable Int+-- __Note:__  Int' is identical to 'Stack'+type Int' = ByteArrayInt++instance SingleStorage ByteArrayInt Int where+  {-# SPECIALIZE INLINE new' :: Int -> IO ByteArrayInt #-}+  new' k = do s <- BA.newByteArray 8+              BA.writeByteArray s 0 k+              return $ ByteArrayInt s+  {-# SPECIALIZE INLINE get' :: ByteArrayInt -> IO Int #-}+  get' (ByteArrayInt v) = BA.readByteArray v 0+  {-# SPECIALIZE INLINE set' :: ByteArrayInt -> Int -> IO () #-}+  set' (ByteArrayInt v) !x = BA.writeByteArray v 0 x+  {-# SPECIALIZE INLINE modify' :: ByteArrayInt -> (Int -> Int) -> IO () #-}+  modify' (ByteArrayInt v) f = BA.writeByteArray v 0 . f =<< BA.readByteArray v 0++-- | Mutable Double+type Double' = ByteArrayDouble++instance SingleStorage ByteArrayDouble Double where+  {-# SPECIALIZE INLINE new' :: Double -> IO ByteArrayDouble #-}+  new' k = do s <- BA.newByteArray 8+              BA.writeByteArray s 0 k+              return $ ByteArrayDouble s+  {-# SPECIALIZE INLINE get' :: ByteArrayDouble -> IO Double #-}+  get' (ByteArrayDouble v) = BA.readByteArray v 0+  {-# SPECIALIZE INLINE set' :: ByteArrayDouble -> Double -> IO () #-}+  set' (ByteArrayDouble v) !x = BA.writeByteArray v 0 x+  {-# SPECIALIZE INLINE modify' :: ByteArrayDouble -> (Double -> Double) -> IO () #-}+  modify' (ByteArrayDouble v) f = BA.writeByteArray v 0 . f =<< BA.readByteArray v 0++-------------------------------------------------------------------------------- Stack++-- | Interface on stacks+class SingleStorage s Int => StackFamily s t | s -> t where+  -- | returns a new stack.+  newStack :: Int -> IO s+  -- | pushs an value to the tail of the stack.+  pushTo :: s -> t-> IO ()+  -- | pops the last element.+  popFrom :: s -> IO ()+  -- | peeks the last element.+  lastOf :: s -> IO t+  -- | shrinks the stack.+  shrinkBy :: s -> Int -> IO ()+  newStack = undefined+  pushTo = undefined+  popFrom = undefined+  lastOf = undefined+  shrinkBy = undefined++-- | Stack of Int, an alias of @Vec Int@+type Stack = Vec Int++instance StackFamily ByteArrayInt Int where+  {-# SPECIALIZE INLINE newStack :: Int -> IO ByteArrayInt #-}+  newStack n = do s <- newVec (2 * n) 0+                  setNth s 0 (0::Int)+                  return s+  {-# SPECIALIZE INLINE pushTo :: ByteArrayInt -> Int -> IO () #-}+  pushTo (ByteArrayInt v) x = do i <- (+ 1) <$> (BA.readByteArray v 0 :: IO Int)+                                 BA.writeByteArray v i x+                                 BA.writeByteArray v 0 i+  {-# SPECIALIZE INLINE popFrom :: ByteArrayInt -> IO () #-}+  popFrom (ByteArrayInt v) = BA.writeByteArray v 0 . subtract 1 =<< (BA.readByteArray v 0 :: IO Int)+  {-# SPECIALIZE INLINE lastOf :: ByteArrayInt -> IO Int #-}+  lastOf (ByteArrayInt v) = BA.readByteArray v =<< BA.readByteArray v 0+  {-# SPECIALIZE INLINE shrinkBy :: ByteArrayInt -> Int -> IO () #-}+  shrinkBy (ByteArrayInt v) k = BA.writeByteArray v 0 . subtract k =<< (BA.readByteArray v 0 :: IO Int)++-- | returns a new 'Stack' from @[Int]@.+{-# INLINABLE newStackFromList #-}+newStackFromList :: [Int] -> IO Stack+newStackFromList l = do+  v <- BA.newByteArray (8 * (length l + 1))+  let loop :: [Int] -> Int -> IO Stack+      loop [] _ = return $ ByteArrayInt v+      loop (x:l') i = BA.writeByteArray v i x >> loop l' (i + 1)+  loop (length l : l) 0++-- | returns the number of allocated slots+{-# INLINE realLengthOfStack #-}+realLengthOfStack :: Stack -> Int+realLengthOfStack (ByteArrayInt v) = div (BA.sizeofMutableByteArray v) 8++-- | sort the content of a stack, in small-to-large order.+{-# INLINABLE sortStack #-}+sortStack :: Stack -> IO ()+sortStack vec = do+  n <- get' vec+  let sortOnRange :: Int -> Int -> IO ()+      sortOnRange left right+        | n < left = return ()+        | right < 1 = return ()+        | left >= right = return ()+        | left + 1 == right = do+            a <- getNth vec left+            b <- getNth vec right+            if a < b then return () else swapBetween vec left right+        | otherwise = do+            let p = div (left + right) 2+            pivot <- getNth vec p+            swapBetween vec p left -- set a sentinel for r'+            let nextL :: Int -> IO Int+                nextL i+                  | i <= right = do v <- getNth vec i; if v < pivot then nextL (i + 1) else return i+                  | otherwise = return i+                nextR :: Int -> IO Int+                nextR i = do v <- getNth vec i; if pivot < v then nextR (i - 1) else return i+                divide :: Int -> Int -> IO Int+                divide l r = do+                  l' <- nextL l+                  r' <- nextR r+                  if l' < r' then swapBetween vec l' r' >> divide (l' + 1) (r' - 1) else return r'+            m <- divide (left + 1) right+            swapBetween vec left m+            sortOnRange left (m - 1)+            sortOnRange (m + 1) right+  sortOnRange 1 n
+ utils/cnf-stat.hs view
@@ -0,0 +1,54 @@+-- | Prints+--   - the CNF filename,+--   - the number of literals /n/,+--   - the number of clauses /m/,+--   - the number of literal occurences in the file /o/,+--   - the average number of literals in a clause /k/+{-# LANGUAGE+    MultiWayIf+  #-}+module Main+       (+         main+       )+       where++import Control.Monad (when)+import qualified Data.ByteString.Char8 as B+import Data.List+import Numeric (showFFloat)+import SAT.Mios+import System.IO++-- version id+vid :: String+vid = "cnf-stats version 0.2"++usage :: String+usage = miosUsage $ vid ++ "\n" ++ "Usage: cnf-stats cnf+"++-- | main+main :: IO ()+main = do opts <- miosParseOptionsFromArgs vid+          if | _displayVersion opts -> putStrLn vid+             | _displayHelp opts    -> putStrLn usage+             | null (_targets opts) -> putStrLn usage+             | otherwise            -> mapM_ (countLiterals opts) (_targets opts)++countLiterals :: MiosProgramOption -> FilePath -> IO ()+countLiterals opts cnfFile = do+  (desc, cls) <- parseCNF (Just cnfFile)+  let n = _numberOfVariables desc+  let m = _numberOfClauses desc+  when (n /= 0) $ do+    let o = length . filter ("0" /=) . words $ B.unpack cls+    putStrLn $ intercalate ","+      [ cnfFile+      , show n+      , show m+      , show o+      , showf $ fromIntegral o / fromIntegral m+      ]++showf :: Double -> String+showf x = showFFloat (Just 2) x ""