packages feed

mios 1.6.0 → 1.6.2

raw patch · 15 files changed

+768/−611 lines, 15 filesdep +gitrevdep +hspecnew-component:exe:mios162PVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: gitrev, hspec

API changes (from Hackage documentation)

- SAT.Mios: executeSolverOn :: FilePath -> IO ()
- SAT.Mios: executeValidatorOn :: FilePath -> IO ()
- SAT.Mios: injectClausesFromCNF :: Solver -> CNFDescription -> ByteString -> IO ()
- SAT.Mios: parseCNF :: Maybe FilePath -> IO (CNFDescription, ByteString)
- SAT.Mios: solve :: (Foldable t) => Solver -> t Lit -> IO SolverResult
- SAT.Mios.Main: dumpSolver :: DumpMode -> Solver -> IO ()
- SAT.Mios.OptionParser: [_confMaxSize] :: MiosProgramOption -> !Int
- SAT.Mios.OptionParser: [dumpStat] :: MiosConfiguration -> !Int
- SAT.Mios.Solver: [restartMode] :: Solver -> Int'
- SAT.Mios.Solver: dumpSolver :: DumpMode -> Solver -> IO ()
- SAT.Mios.Types: [dumpStat] :: MiosConfiguration -> !Int
- SAT.Mios.Types: select :: VarOrder o => o -> IO Var
- SAT.Mios.Types: undo :: VarOrder o => o -> Var -> IO ()
- SAT.Mios.Types: update :: VarOrder o => o -> Var -> IO ()
- SAT.Mios.Vec: instance SAT.Mios.Vec.VecFamily (SAT.Mios.Vec.Vec [GHC.Types.Int]) GHC.Types.Int
- SAT.Mios.Vec: realLengthOfStack :: Stack -> Int
+ SAT.Mios: buildDescription :: FilePath -> Solver -> IO CNFDescription
+ SAT.Mios: buildOption :: Either FilePath String -> MiosProgramOption
+ SAT.Mios: buildSolver :: MiosProgramOption -> IO Solver
+ SAT.Mios: showAnswerFromString :: String -> IO String
+ SAT.Mios.Clause: getRank :: Clause -> IO Int
+ SAT.Mios.Clause: setRank :: Clause -> Int -> IO ()
+ SAT.Mios.Criteria: dumpStats :: DumpMode -> Solver -> IO ()
+ SAT.Mios.Criteria: nddOf :: Solver -> Stack -> IO Int
+ SAT.Mios.Criteria: updateNDD :: Solver -> IO ()
+ SAT.Mios.Main: dumpStats :: DumpMode -> Solver -> IO ()
+ SAT.Mios.OptionParser: [_confRestartE] :: MiosProgramOption -> Double
+ SAT.Mios.OptionParser: [_confRestartS] :: MiosProgramOption -> Double
+ SAT.Mios.OptionParser: [dumpSolverStatMode] :: MiosConfiguration -> !Int
+ SAT.Mios.OptionParser: [emaCoeffs] :: MiosConfiguration -> !(Int, Int)
+ SAT.Mios.OptionParser: [restartExpansion] :: MiosConfiguration -> !Double
+ SAT.Mios.OptionParser: [restartStep] :: MiosConfiguration -> !Double
+ SAT.Mios.Solver: [emaBDLvl] :: Solver -> !EMA
+ SAT.Mios.Solver: [emaCDLvl] :: Solver -> !EMA
+ SAT.Mios.Solver: [emaRstBias] :: Solver -> !EMA
+ SAT.Mios.Solver: [ndd] :: Solver -> !(Vec Int)
+ SAT.Mios.Solver: [restartExp] :: Solver -> !Double'
+ SAT.Mios.Types: [dumpSolverStatMode] :: MiosConfiguration -> !Int
+ SAT.Mios.Types: [emaCoeffs] :: MiosConfiguration -> !(Int, Int)
+ SAT.Mios.Types: [restartExpansion] :: MiosConfiguration -> !Double
+ SAT.Mios.Types: [restartStep] :: MiosConfiguration -> !Double
+ SAT.Mios.Types: getEMA :: EMA -> IO Double
+ SAT.Mios.Types: newEMA :: Bool -> Int -> IO EMA
+ SAT.Mios.Types: selectVO :: VarOrder o => o -> IO Var
+ SAT.Mios.Types: type EMA = (Double', Maybe Double', Double)
+ SAT.Mios.Types: undoVO :: VarOrder o => o -> Var -> IO ()
+ SAT.Mios.Types: updateEMA :: EMA -> Double -> IO Double
+ SAT.Mios.Types: updateVO :: VarOrder o => o -> Var -> IO ()
+ SAT.Mios.Vec: realLength :: Vec Int -> Int
- SAT.Mios: CNFDescription :: !Int -> !Int -> Maybe FilePath -> CNFDescription
+ SAT.Mios: CNFDescription :: !Int -> !Int -> !FilePath -> CNFDescription
- SAT.Mios: [_pathname] :: CNFDescription -> Maybe FilePath
+ SAT.Mios: [_pathname] :: CNFDescription -> !FilePath
- SAT.Mios: dumpAssigmentAsCNF :: Maybe FilePath -> Certificate -> IO ()
+ SAT.Mios: dumpAssigmentAsCNF :: MiosProgramOption -> Certificate -> IO String
- SAT.Mios: executeSolver :: MiosProgramOption -> IO ()
+ SAT.Mios: executeSolver :: MiosProgramOption -> Solver -> IO ()
- SAT.Mios: executeValidator :: MiosProgramOption -> IO ()
+ SAT.Mios: executeValidator :: MiosProgramOption -> Solver -> IO ()
- SAT.Mios.Clause: Clause :: !Int' -> !Double' -> !Stack -> Clause
+ SAT.Mios.Clause: Clause :: !Stack -> !Int' -> !Double' -> Clause
- SAT.Mios.ClauseManager: getKeyVector :: ClauseExtManager -> IO (Vec [Int])
+ SAT.Mios.ClauseManager: getKeyVector :: ClauseExtManager -> IO (Vec Int)
- SAT.Mios.Criteria: checkRestartCondition :: Solver -> Int -> IO Bool
+ SAT.Mios.Criteria: checkRestartCondition :: Solver -> Int -> Int -> IO Bool
- SAT.Mios.OptionParser: MiosConfiguration :: !Double -> !Double -> !Int -> MiosConfiguration
+ SAT.Mios.OptionParser: MiosConfiguration :: !Double -> !Double -> !Int -> !(Int, Int) -> !Double -> !Double -> MiosConfiguration
- SAT.Mios.OptionParser: MiosProgramOption :: Maybe String -> [String] -> Maybe String -> !Double -> Double -> !Int -> !Bool -> !Bool -> Integer -> !Int -> !Bool -> !Int -> !Bool -> !Bool -> !Bool -> MiosProgramOption
+ SAT.Mios.OptionParser: MiosProgramOption :: Either String String -> [String] -> Maybe String -> Double -> Double -> Double -> Double -> Bool -> Bool -> Integer -> Int -> Bool -> Int -> Bool -> Bool -> Bool -> MiosProgramOption
- SAT.Mios.OptionParser: [_confBenchSeq] :: MiosProgramOption -> !Int
+ SAT.Mios.OptionParser: [_confBenchSeq] :: MiosProgramOption -> Int
- SAT.Mios.OptionParser: [_confCheckAnswer] :: MiosProgramOption -> !Bool
+ SAT.Mios.OptionParser: [_confCheckAnswer] :: MiosProgramOption -> Bool
- SAT.Mios.OptionParser: [_confDumpStat] :: MiosProgramOption -> !Int
+ SAT.Mios.OptionParser: [_confDumpStat] :: MiosProgramOption -> Int
- SAT.Mios.OptionParser: [_confNoAnswer] :: MiosProgramOption -> !Bool
+ SAT.Mios.OptionParser: [_confNoAnswer] :: MiosProgramOption -> Bool
- SAT.Mios.OptionParser: [_confVariableDecayRate] :: MiosProgramOption -> !Double
+ SAT.Mios.OptionParser: [_confVariableDecayRate] :: MiosProgramOption -> Double
- SAT.Mios.OptionParser: [_confVerbose] :: MiosProgramOption -> !Bool
+ SAT.Mios.OptionParser: [_confVerbose] :: MiosProgramOption -> Bool
- SAT.Mios.OptionParser: [_displayHelp] :: MiosProgramOption -> !Bool
+ SAT.Mios.OptionParser: [_displayHelp] :: MiosProgramOption -> Bool
- SAT.Mios.OptionParser: [_displayVersion] :: MiosProgramOption -> !Bool
+ SAT.Mios.OptionParser: [_displayVersion] :: MiosProgramOption -> Bool
- SAT.Mios.OptionParser: [_targetFile] :: MiosProgramOption -> Maybe String
+ SAT.Mios.OptionParser: [_targetFile] :: MiosProgramOption -> Either String String
- SAT.Mios.OptionParser: [_validateAssignment] :: MiosProgramOption -> !Bool
+ SAT.Mios.OptionParser: [_validateAssignment] :: MiosProgramOption -> Bool
- 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: Solver :: !ClauseExtManager -> !ClauseExtManager -> !WatcherList -> !(Vec Int) -> !(Vec Int) -> !Stack -> !Stack -> !Int' -> !ClauseVector -> !(Vec Int) -> !(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' -> !EMA -> !EMA -> !EMA -> !EMA -> !EMA -> !EMA -> !Int' -> !Double' -> !EMA -> Solver
- SAT.Mios.Solver: [emaAFast] :: Solver -> !Double'
+ SAT.Mios.Solver: [emaAFast] :: Solver -> !EMA
- SAT.Mios.Solver: [emaASlow] :: Solver -> !Double'
+ SAT.Mios.Solver: [emaASlow] :: Solver -> !EMA
- SAT.Mios.Solver: [emaDFast] :: Solver -> !Double'
+ SAT.Mios.Solver: [emaDFast] :: Solver -> !EMA
- SAT.Mios.Solver: [emaDSlow] :: Solver -> !Double'
+ SAT.Mios.Solver: [emaDSlow] :: Solver -> !EMA
- SAT.Mios.Solver: [stats] :: Solver -> !(Vec [Int])
+ SAT.Mios.Solver: [stats] :: Solver -> !(Vec Int)
- SAT.Mios.Types: CNFDescription :: !Int -> !Int -> Maybe FilePath -> CNFDescription
+ SAT.Mios.Types: CNFDescription :: !Int -> !Int -> !FilePath -> CNFDescription
- SAT.Mios.Types: MiosConfiguration :: !Double -> !Double -> !Int -> MiosConfiguration
+ SAT.Mios.Types: MiosConfiguration :: !Double -> !Double -> !Int -> !(Int, Int) -> !Double -> !Double -> MiosConfiguration
- SAT.Mios.Types: [_pathname] :: CNFDescription -> Maybe FilePath
+ SAT.Mios.Types: [_pathname] :: CNFDescription -> !FilePath
- SAT.Mios.Types: data Int :: *
+ SAT.Mios.Types: data Int

Files

+ app/DiscordSecret.hs view
@@ -0,0 +1,6 @@+-- join to a server:+-- https://discordapp.com/oauth2/authorize?&client_id=431666856785346560&scope=bot&permissions=0+module DiscordSecret (token) where++token :: String+token = "NDQ4ODM2NDM0MjkyNjM3NzA2.Deb7VA.v1mtGLLwG0GK9kbqNko7D_R14Bc"
app/mios.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE-   MultiWayIf+    MultiWayIf+  , TemplateHaskell   #-} -- | Executable of 'Minisat Implementation and Optimization Study' module Main@@ -9,16 +10,20 @@        where  import SAT.Mios+import Development.GitRev +gitId :: String+gitId = "mios " ++ versionId ++ "/commit/" ++ $(gitHash)+ usage :: String-usage = miosUsage $ versionId ++ "\nUsage: mios [OPTIONS] target.cnf"+usage = miosUsage $ gitId ++ "\nUsage: mios [OPTIONS] target.cnf"  -- | main main :: IO () main = do opts <- miosParseOptionsFromArgs versionId-          if | _displayVersion opts        -> putStrLn versionId+          if | _displayVersion opts        -> putStrLn gitId              | _displayHelp opts           -> putStrLn usage-             | _targetFile opts == Nothing -> putStrLn usage-             | _validateAssignment opts    -> executeValidator opts-             | otherwise                   -> executeSolver opts+             | _targetFile opts == Left "" -> putStrLn usage+             | _validateAssignment opts    -> executeValidator opts =<< buildSolver opts+             | otherwise                   -> executeSolver opts =<< buildSolver opts 
mios.cabal view
@@ -1,11 +1,11 @@--- This file has been generated from package.yaml by hpack version 0.20.0.+-- This file has been generated from package.yaml by hpack version 0.28.2. -- -- see: https://github.com/sol/hpack ----- hash: 1a93fd2f2b1b1d0ba5e203ac6b48c5ca8abd31384c1955776cfb00969c311cbb+-- hash: 5cd432e14ff114a77b46f65cd54a00907c68da1bb380706bdbeb682bf43ff46d  name:           mios-version:        1.6.0+version:        1.6.2 synopsis:       A Minisat-based CDCL SAT solver in Haskell description:    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'. category:       Artificial Intelligence, Constraints@@ -18,7 +18,6 @@ license-file:   LICENSE build-type:     Simple cabal-version:  >= 1.10- extra-source-files:     app/sample.hs @@ -37,21 +36,6 @@   default: False  library-  hs-source-dirs:-      src-  default-extensions: Strict-  build-depends:-      base >=4.7 && <5-    , bytestring >=0.10-    , ghc-prim >=0.5-    , primitive >=0.6-    , vector >=0.12-  if flag(llvm)-    ghc-options: -O2 -funbox-strict-fields -fllvm -optlo-O3 -optlc-O3 -fwarn-missing-signatures-    ghc-prof-options: -O2 -funbox-strict-fields -fllvm -optlo-O3 -fprof-auto-  else-    ghc-options: -O2 -funbox-strict-fields -msse2 -fwarn-missing-signatures-    ghc-prof-options: -O2 -funbox-strict-fields -fprof-auto   exposed-modules:       SAT.Mios       SAT.Mios.Clause@@ -71,10 +55,27 @@       SAT.Mios.Vec   other-modules:       Paths_mios+  hs-source-dirs:+      src+  default-extensions: Strict+  build-depends:+      base >=4.7 && <5+    , bytestring >=0.10+    , ghc-prim >=0.5+    , primitive >=0.6+    , vector >=0.12+  if flag(llvm)+    ghc-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fllvm -optlo-O3 -optlc-O3+    ghc-prof-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fllvm -optlo-O3 -fprof-auto+  else+    ghc-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -msse2+    ghc-prof-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fprof-auto   default-language: Haskell2010  executable cnf-stat   main-is: cnf-stat.hs+  other-modules:+      Paths_mios   hs-source-dirs:       utils   default-extensions: Strict@@ -86,21 +87,22 @@     , primitive >=0.6     , vector >=0.12   if flag(llvm)-    ghc-options: -O2 -funbox-strict-fields -fllvm -optlo-O3 -optlc-O3 -fwarn-missing-signatures-    ghc-prof-options: -O2 -funbox-strict-fields -fllvm -optlo-O3 -fprof-auto+    ghc-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fllvm -optlo-O3 -optlc-O3+    ghc-prof-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fllvm -optlo-O3 -fprof-auto   else-    ghc-options: -O2 -funbox-strict-fields -msse2 -fwarn-missing-signatures-    ghc-prof-options: -O2 -funbox-strict-fields -fprof-auto+    ghc-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -msse2+    ghc-prof-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fprof-auto   if flag(utils)     buildable: True   else     buildable: False-  other-modules:-      Paths_mios   default-language: Haskell2010 -executable mios-1.6.0+executable mios162   main-is: mios.hs+  other-modules:+      DiscordSecret+      Paths_mios   hs-source-dirs:       app   default-extensions: Strict@@ -108,19 +110,46 @@       base >=4.7 && <5     , bytestring >=0.10     , ghc-prim >=0.5+    , gitrev     , mios     , primitive >=0.6     , vector >=0.12   if flag(llvm)-    ghc-options: -O2 -funbox-strict-fields -fllvm -optlo-O3 -optlc-O3 -fwarn-missing-signatures-    ghc-prof-options: -O2 -funbox-strict-fields -fllvm -optlo-O3 -fprof-auto+    ghc-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fllvm -optlo-O3 -optlc-O3+    ghc-prof-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fllvm -optlo-O3 -fprof-auto   else-    ghc-options: -O2 -funbox-strict-fields -msse2 -fwarn-missing-signatures-    ghc-prof-options: -O2 -funbox-strict-fields -fprof-auto+    ghc-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -msse2+    ghc-prof-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fprof-auto   if flag(llvm)-    ghc-prof-options: -O2 -funbox-strict-fields -fllvm -optlo-O3 -fprof-auto -rtsopts+    ghc-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fllvm -optlo-O3 -optlc-O3 -rtsopts -with-rtsopts=-M7g+    ghc-prof-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fllvm -optlo-O3 -fprof-auto -rtsopts   else-    ghc-prof-options: -O2 -funbox-strict-fields -fprof-auto -rtsopts+    ghc-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -msse2 -rtsopts -with-rtsopts=-M7g+    ghc-prof-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fprof-auto -rtsopts+  default-language: Haskell2010++test-suite mios-test+  type: exitcode-stdio-1.0+  main-is: Spec.hs   other-modules:+      MiosSpec       Paths_mios+  hs-source-dirs:+      test+  default-extensions: Strict+  ghc-options: -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      base >=4.7 && <5+    , bytestring >=0.10+    , ghc-prim >=0.5+    , hspec+    , mios+    , primitive >=0.6+    , vector >=0.12+  if flag(llvm)+    ghc-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fllvm -optlo-O3 -optlc-O3+    ghc-prof-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fllvm -optlo-O3 -fprof-auto+  else+    ghc-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -msse2+    ghc-prof-options: -j -fwarn-missing-signatures -funbox-strict-fields -O2 -fprof-auto   default-language: Haskell2010
src/SAT/Mios.hs view
@@ -13,29 +13,29 @@          versionId        , CNFDescription (..)        , module SAT.Mios.OptionParser+        -- * Main Interace+       , SolverResult+       , Certificate (..)+       , buildOption+       , buildSolver+       , buildDescription+       , executeSolver+       , executeValidator+         -- * Simple Interface        , runSolver        , solveSAT        , solveSATWithConfiguration-       , solve-       , SolverResult-       , Certificate (..)+       , showAnswerFromString          -- * Assignment Validator-       , validateAssignment        , validate-         -- * For standalone programs-       , executeSolverOn-       , executeSolver-       , executeValidatorOn-       , executeValidator+       , validateAssignment          -- * File IO-       , parseCNF-       , injectClausesFromCNF        , dumpAssigmentAsCNF        )        where -import Control.Concurrent (forkIO, killThread, myThreadId, threadDelay-                          , newEmptyMVar, putMVar, readMVar)+import Control.Concurrent ( newEmptyMVar, putMVar, readMVar, takeMVar+                          , ThreadId, forkIO, killThread, myThreadId, threadDelay) import Control.Exception import Control.Monad ((<=<), unless, void, when) import Data.Char@@ -46,13 +46,14 @@ 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.6.0 -- https://github.com/shnarazk/mios"+versionId = "1.6.2 https://gitlab.com/satisfiability01/mios"  reportElapsedTime :: Bool -> String -> Integer -> IO Integer reportElapsedTime False _ 0 = return 0@@ -64,93 +65,139 @@   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 })+-- | returns a MiosProgramOption for the target+buildOption :: Either FilePath String -> MiosProgramOption+buildOption target = (miosDefaultOption { _targetFile = target }) +-- | returns a new solver injected a problem+buildSolver :: MiosProgramOption -> IO Solver+buildSolver opts = do+  token <- newEmptyMVar --  :: IO (MVar (Maybe Solver))+  (desc, cls) <- parseCNF (_targetFile opts)+  t0 <- reportElapsedTime False "" $ if _confVerbose opts || 0 <= _confBenchmark opts then -1 else 0+  readerId <- forkIO $ do+    s <- newSolver (toMiosConf opts) desc+    when (_numberOfVariables desc == 0) . error $ "couldn't load " ++ (take 100 . show . _targetFile) opts+    injectClausesFromCNF s desc cls+    putMVar token s+  when (0 < _confBenchmark opts) $+    void $ forkIO $ do let -- getCPUTime returns a pico sec. :: Integer, 1000 * 1000 * 1000 * 1000+                           -- threadDelay requires a micro sec. :: Int,  1000 * 1000+                           req = 1000000000000 * fromIntegral (_confBenchmark opts) :: Integer+                           waiting = do+                             elp <- getCPUTime+                             when (elp < req) $ do+                               threadDelay . max 1000000 $ fromIntegral (req - elp) `div` 1000000+                               waiting+                       waiting+                       killThread readerId+                       s' <- newSolver defaultConfiguration (CNFDescription 0 0 "")+                       set' (ok s') LiftedF+                       putMVar token s'+  void $ reportElapsedTime (_confVerbose opts) ("## [" ++ showPathFixed opts ++ "] Parse: ") t0+  takeMVar token++-- | returns the data on a given CNF file. Only solver knows it.+buildDescription :: FilePath -> Solver -> IO CNFDescription+buildDescription target s = CNFDescription (nVars s) <$> nClauses s <*> return target+ -- | 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))+executeSolver :: MiosProgramOption -> Solver -> IO ()+executeSolver opts s = do   solverId <- myThreadId+  token <- newEmptyMVar --  :: IO (MVar (Maybe Solver))+  t0 <- reportElapsedTime False "" $ if _confVerbose opts || 0 <= _confBenchmark opts then -1 else 0   handle (\case-             UserInterrupt -> putStrLn "User interrupt recieved."+             UserInterrupt -> if -1 == _confBenchmark opts+                              then putStrLn "User interrupt (SIGINT) recieved."+                              else reportResult opts t0 (Left TimeOut)              ThreadKilled  -> reportResult opts t0 =<< readMVar token-             e -> print e) $ do+             HeapOverflow  -> if -1 == _confBenchmark opts+                              then putStrLn "Abort: a too large problem or heap exhausted (use '+RTS -M16g' if you need)"+                              else reportResult opts t0 (Left OutOfMemory)+             e -> if -1 == _confBenchmark opts then print e else reportResult opts t0 (Left TimeOut)+         ) $ do     when (0 < _confBenchmark opts) $-      void $ forkIO $ do let fromMicro = 1000000 :: Int-                         threadDelay $ fromMicro * fromIntegral (_confBenchmark opts)+      void $ forkIO $ do let -- getCPUTime returns a pico sec. :: Integer, 1000 * 1000 * 1000 * 1000+                             -- threadDelay requires a micro sec. :: Int,  1000 * 1000+                             req = 1000000000000 * fromIntegral (_confBenchmark opts) :: Integer+                             waiting = do elp <- getCPUTime+                                          when (elp < req) $ do+                                            threadDelay . max 1000000 $ fromIntegral (req - elp) `div` 1000000+                                            waiting+                         waiting                          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+    when (0 < _confDumpStat opts) $ dumpStats 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.+-- TODO: this function shuld return @IO String@ in someday. 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))+reportResult opts t0 (Left OutOfMemory) = do+  t2 <- reportElapsedTime (_confVerbose opts) ("## [" ++ showPathFixed opts ++ "] Total: ") t0+  when (0 <= _confBenchmark opts) $ do+    let fromPico = 1000000000000 :: Double+    putStrLn ("\"" ++ takeWhile (' ' /=) versionId ++ "\","+              ++ show (_confBenchSeq opts) ++ ","+              ++ "\"" ++ showPath opts ++ "\","+              ++ show (_confBenchmark opts) ++ "," ++ show (fromEnum OutOfMemory)+             ) +reportResult opts t0 (Left TimeOut) = do+  t2 <- reportElapsedTime (_confVerbose opts) ("## [" ++ showPathFixed opts ++ "] Total: ") t0+  when (0 <= _confBenchmark opts) $ do+    let fromPico = 1000000000000 :: Double+    putStrLn ("\"" ++ takeWhile (' ' /=) versionId ++ "\","+              ++ show (_confBenchSeq opts) ++ ","+              ++ "\"" ++ showPath opts ++ "\","+              ++ showFFloat (Just 3) (fromIntegral t2 / fromPico) ","+              ++ show (fromEnum TimeOut)+             )+ -- solver terminated normally-reportResult opts@(_targetFile -> Just cnfFile) t0 (Right result) = do-  t2 <- reportElapsedTime (_confVerbose opts) ("## [" ++ showPath cnfFile ++ "] Total: ") t0-  case result of+reportResult opts t0 (Right result) = do+  t2 <- reportElapsedTime (_confVerbose opts) ("## [" ++ showPathFixed opts ++ "] Total: ") t0+  dumpName <- if _confNoAnswer opts then return Nothing else (Just <$> dumpAssigmentAsCNF opts result)+  case (result, dumpName) 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+    (_, Just "")    -> return ()+    (SAT _, Just o)    -> hPutStrLn stderr $ "SATISFIABLE, saved to " ++ o ++ " for " ++ showPathBaseName opts+    (SAT _, Nothing)   -> hPutStrLn stderr $ "SATISFIABLE, " ++ showPathBaseName opts+    (UNSAT _, Just o)  -> hPutStrLn stderr $ "UNSATISFIABLE, saved to " ++ o ++ " for " ++ showPathBaseName opts+    (UNSAT _, Nothing) -> hPutStrLn stderr $ "UNSATISFIABLE, " ++ showPathBaseName opts+  valid <- if _confCheckAnswer opts                     -- or 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+                  SAT asg -> flip validate asg =<< buildSolver opts                   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+    void $ reportElapsedTime (_confVerbose opts) ("## [" ++ showPathFixed opts ++ "] 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)+    putStrLn ("\"" ++ takeWhile (' ' /=) versionId ++ "\","+              ++ show (_confBenchSeq opts) ++ ","+              ++ "\"" ++ showPath opts ++ "\","+              ++ if valid+               then showFFloat (Just 3) (fromIntegral t2 / fromPico) "," ++ show phase+               else show (_confBenchmark opts) ++ "," ++ show (fromEnum InternalInconsistent))  reportResult _ _ _ = return () --- | new top-level interface that returns:+-- | NOT MAINTAINED NOW+-- new top-level interface that returns: -- -- * conflicting literal set :: Left [Int] -- * satisfiable assignment :: Right [Int]@@ -181,7 +228,6 @@ 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@@ -191,21 +237,10 @@               _             -> 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)+executeValidator :: MiosProgramOption -> Solver -> IO ()+executeValidator opts@(_targetFile -> target@(Left cnfFile)) s = do   asg <- read <$> getContents   unless (_confNoAnswer opts) $ print asg   result <- s `validate` (asg :: [Int])@@ -213,7 +248,7 @@     then putStrLn ("It's a valid assignment for " ++ cnfFile ++ ".") >> exitSuccess     else putStrLn ("It's an invalid assignment for " ++ cnfFile ++ ".") >> exitFailure -executeValidator _  = return ()+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@,@@ -233,103 +268,153 @@ -- -- >>> do y <- solve s ... ; dumpAssigmentAsCNF (Just "result.cnf") y <$> model s ---dumpAssigmentAsCNF :: Maybe FilePath -> Certificate -> IO ()-dumpAssigmentAsCNF Nothing _ = return ()+dumpAssigmentAsCNF :: MiosProgramOption -> Certificate -> IO String -- | 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+dumpAssigmentAsCNF opt (UNSAT _) = do+  if _outputFile opt == Just "--"+    then print "[]" >> return ""+    else do let fname = case _outputFile opt of+                  Just x -> x+                  Nothing -> case _targetFile opt of+                               Left f -> ".ans_" ++ (reverse . takeWhile (/= '/') . reverse) f+                               Right _ -> ".ans_mios"+            writeFile fname "s UNSAT\n0\n"+            return fname+dumpAssigmentAsCNF opt (SAT l) = do+  if _outputFile opt == Just "--"+    then print l >> return ""+    else do let fname = case _outputFile opt of+                  Just x -> x+                  Nothing -> case _targetFile opt of+                               Left f -> ".ans_" ++ (reverse . takeWhile (/= '/') . reverse) f+                               Right _ -> ".ans_mios"+            withFile fname WriteMode $ \h -> do+              hPutStrLn h "s SAT"+              hPutStrLn h . (++ " 0") . unwords $ map show l+            return fname +showPath :: MiosProgramOption -> String+showPath (_targetFile -> Left str) = str+showPath _ = "{a cnf embedded}"++showPathBaseName :: MiosProgramOption -> String+showPathBaseName (_targetFile -> Left str) = (reverse . takeWhile (/= '/') . reverse) str+showPathBaseName _ = "aCNF"++showPathFixed :: MiosProgramOption -> String+showPathFixed (_targetFile -> Left str) = replicate (len - length basename) ' ' ++ if elem '/' str then basename else basename'+  where+    len = 50+    basename = reverse . takeWhile (/= '/') . reverse $ str+    basename' = take len str++showPathFixed (_targetFile -> Right _) = replicate (len - length basename) ' ' ++ basename+  where+    len = 50+    basename = "embedded data"+ -------------------------------------------------------------------------------- -- DIMACS CNF Reader --------------------------------------------------------------------------------  -- | parses the header of a CNF file-parseCNF :: Maybe FilePath -> IO (CNFDescription, B.ByteString)-parseCNF target@(Just cnfFile) = do+parseCNF :: Either FilePath String -> IO (CNFDescription, B.ByteString)+parseCNF pathOrData = do   let -- format: p cnf n m, length "p cnf" == 5+      target = case pathOrData of+                 Left str -> str+                 Right _  -> ""       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+      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+  case pathOrData of+    Left cnfFile -> seek =<< B.readFile cnfFile+    Right bdata  -> seek $ B.pack bdata  -- | parses ByteString then injects the clauses in it into a solver+{-# INLINABLE injectClausesFromCNF #-} 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+  buffer <- newVec (maxLit + 1) 0 :: IO (Vec Int)+  let skipComments :: B.ByteString -> B.ByteString+      skipComments !s = case B.uncons s of -- __Pre-condition:__ we are on the benngining of a line+                          Just ('c', b') -> skipComments . B.tail . B.dropWhile (/= '\n') $ b'+                          _ -> s+      readClause :: Int -> B.ByteString -> IO ()+      readClause ((< nc) -> False) _ = return ()+      readClause !i !stream = do+        let loop :: Int -> B.ByteString -> IO ()+            loop !j !b = case parseInt $ skipWhitespace b of+                           (k, b') -> if k == 0+                                      then do setNth buffer 0 $ j - 1+                                              res <- addClause s buffer+                                              unless res $ set' (ok s) LiftedF+                                              readClause (i + 1) b'+                                      else do setNth buffer j (int2lit k)+                                              loop (j + 1) b'+        loop 1 . skipComments . B.dropWhile (`elem` " \t\n") $ stream+  readClause 0 bs  {-# 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+skipWhitespace !s = B.dropWhile (== ' ') {- (`elem` " \t") -} s -{-# INLINABLE parseInt #-}+{-# INLINE 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"+      loop :: (Int, B.ByteString) -> (Int, B.ByteString)+      loop (val, s) = case B.uncons s of+        Just (c, s') -> if '0' <= c && c <= '9' then loop (val * 10 + ord c - zero, s') else (val, s')+        -- _ -> error (">>>>" ++ take 80 (B.unpack s))+  case B.uncons st of+    Just ('-', st') -> let (k, x) = loop (0, st') in (negate k, x)+    Just ('0', st') -> (0, st')+    _ -> loop (0, st) -{-# 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+-- | executes a solver on the given 'arg :: MiosConfiguration'.+-- This is another entry point for standalone programs.+showAnswerFromString :: String -> IO String+showAnswerFromString str = do+  let opts = miosDefaultOption { _targetFile = Right str }+  solverId <- myThreadId+  desc <- fst <$> parseCNF (_targetFile opts)+  token <- newEmptyMVar --  :: IO (MVar (Maybe Solver))+  t0 <- reportElapsedTime False "" 0+  s <- buildSolver opts+  handle (\case+             UserInterrupt -> return "User interrupt recieved."+             ThreadKilled  -> makeReport opts t0 =<< readMVar token+             HeapOverflow  -> if -1 == _confBenchmark opts+                              then return "Abort: a too large problem or heap exhausted"+                              else makeReport opts t0 (Left OutOfMemory)+             e -> if -1 == _confBenchmark opts then return "unhandled iterrupt" else makeReport opts t0 (Left TimeOut)+         ) $ do+    when (0 < _confBenchmark opts) $+      void $ forkIO $ do let req = 1000000000000 * fromIntegral (_confBenchmark opts) :: Integer+                             waiting = do elp <- getCPUTime+                                          when (elp < req) $ do+                                            threadDelay $ fromIntegral (req - elp) `div` 1000000+                                            waiting+                         waiting+                         putMVar token (Left TimeOut)+                         killThread solverId+    result <- solve s []+    putMVar token result+    killThread solverId+    return $ show desc++makeReport :: MiosProgramOption -> Integer -> SolverResult -> IO String+makeReport opts t0 (Left OutOfMemory) = return "out of memory"+makeReport opts t0 (Left TimeOut) = return "time out"+makeReport opts t0 (Right (SAT asg)) = return $ show asg+makeReport opts t0 (Right (UNSAT _)) = return "UNSAT"+makeReport _ _ _ = return ""
src/SAT/Mios/Clause.hs view
@@ -13,6 +13,10 @@        (          Clause (..)        , newClauseFromStack+       , getRank+       , setRank+       -- , getActivity+       -- , setActivity          -- * Vector of Clause        , ClauseVector        , newClauseVector@@ -30,10 +34,10 @@ -- This matches both of @Clause@ and @GClause@ in MiniSat. data Clause = Clause               {-                rank       :: !Int'     -- ^ goodness like LBD; computed in 'Ranking'+                lits       :: !Stack    -- ^ literals and rank+              , rank       :: !Int'     -- ^ another metrics of this clause               , activity   :: !Double'  -- ^ activity of this clause---              , protected  :: !Bool'    -- ^ protected from reduce-              , lits       :: !Stack    -- ^ which this clause consists of+--            , protected  :: !Bool'    -- ^ protected from reduce               }   | NullClause                              -- as null pointer --  | BinaryClause Lit                        -- binary clause consists of only a propagating literal@@ -93,12 +97,31 @@ 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)+  v <- newStack (n + 1)+  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 v <$> new' (if l then 1 else 0) <*> new' 0.0++-- | returns the rank, a goodness, of a given clause+{-# INLINE getRank #-}+getRank :: Clause -> IO Int+getRank Clause{..} = get' rank++-- | sets the rank of a given clause+{-# INLINE setRank #-}+setRank :: Clause -> Int -> IO ()+setRank Clause{..} k = set' rank k++{-+{-# INLINE getActivity #-}+getActivity :: Clause -> IO Int+getActivity Clause{..} = do n <- get' lits; getNth lits (n + 2)++{-# INLINE setActivity #-}+setActivity :: Clause -> Int -> IO ()+setActivity Clause{..} k = do n <- get' lits; setNth lits (n + 2) k+-}  -------------------------------------------------------------------------------- Clause Vector 
src/SAT/Mios/ClauseManager.hs view
@@ -20,6 +20,7 @@        , pushClauseWithKey        , getKeyVector        , markClause+--       , allocateKeyVectorSize          -- * WatcherList        , WatcherList        , newWatcherList@@ -29,6 +30,7 @@  import Control.Monad (unless, when) import qualified Data.IORef as IORef+import qualified Data.Primitive.ByteArray as BA import qualified Data.Vector as V import qualified Data.Vector.Mutable as MV import SAT.Mios.Types@@ -99,7 +101,7 @@     _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+  , _keyVector    :: IORef.IORef (Vec Int)         -- Int list   }  -- | 'ClauseExtManager' is a 'SingleStorage` on the number of clauses in it.@@ -120,7 +122,7 @@     !b <- IORef.readIORef _keyVector     if MV.length v - 1 <= n       then do-          let len = max 8 $ MV.length v+          let len = max 8 $ div (MV.length v) 2           v' <- MV.unsafeGrow v len           b' <- growBy b len           MV.unsafeWrite v' n c@@ -228,7 +230,7 @@  -- | returns the associated Int vector, which holds /blocking literals/. {-# INLINE getKeyVector #-}-getKeyVector :: ClauseExtManager -> IO (Vec [Int])+getKeyVector :: ClauseExtManager -> IO (Vec Int) getKeyVector ClauseExtManager{..} = IORef.readIORef _keyVector  -- | O(1) inserter@@ -241,7 +243,7 @@   !b <- IORef.readIORef _keyVector   if MV.length v - 1 <= n     then do-        let len = max 8 $ MV.length v+        let len = max 8 $ div (MV.length v) 2         v' <- MV.unsafeGrow v len         b' <- growBy b len         MV.unsafeWrite v' n c@@ -277,7 +279,10 @@ -- | 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)+newWatcherList n m = do let n' = int2lit (negate n) + 2+                        v <- MV.unsafeNew n'+                        mapM_  (\i -> MV.unsafeWrite v i =<< newManager m) [0 .. n' - 1]+                        V.unsafeFreeze v  -- | returns the watcher List for "Literal" /l/. {-# INLINE getNthWatcher #-}@@ -291,3 +296,20 @@   {-# 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]++--------------------------------------------------------------------------------++-- | returns the associated Int vector, which holds /blocking literals/.+{-# INLINE setKeyVector #-}+setKeyVector :: ClauseExtManager -> Vec Int -> IO ()+setKeyVector ClauseExtManager{..} v = IORef.writeIORef _keyVector v++{-# INLINABLE allocateKeyVectorSize #-}+allocateKeyVectorSize :: ClauseExtManager -> Int -> IO (Vec Int)+allocateKeyVectorSize  ClauseExtManager{..} n' = do+  v <- IORef.readIORef _keyVector+  if realLength v < n'          -- never shrink it+    then do v' <- newVec n' 0+            IORef.writeIORef _keyVector v'+            return v'+    else return v
src/SAT/Mios/ClausePool.hs view
@@ -47,29 +47,23 @@         let mgr = getManager pool i         nn <- get' mgr         if 0 < nn-          then do c <- lastOf mgr-                  popFrom mgr-                  return c+          then do c <- lastOf mgr; popFrom mgr; return c           else pickup $ i + 1   n <- get' v-  c <- pickup (n - 2)+  c <- pickup (n - 2)           -- mapping the number of literals for the smallest clauses to zero   if c == NullClause     then newClauseFromStack True v     else do let lstack = lits c                 loop :: Int -> IO ()-                loop ((<= n) -> False) = return ()+                loop ((<= n) -> False) = set' (activity c) 0.0 -- setActivity c 1                 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+            return c    -- the caller (newLearntClause) should set rank and protected by himself  -- | 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+  n <- subtract 2 <$> get' c    -- the number of literals in a clause >= 2+  l <- getRank c+  when (0 /= l && n <= storeLimit) $ pushTo (getManager pool n) c
src/SAT/Mios/Criteria.hs view
@@ -1,7 +1,8 @@ -- | (This is a part of MIOS.) -- Advanced heuristics library for 'SAT.Mios.Main' {-# LANGUAGE-    MultiWayIf+    BangPatterns+  , MultiWayIf   , RecordWildCards   , ViewPatterns   #-}@@ -16,14 +17,21 @@        , varDecayActivity          -- * Clause        , addClause-         -- * Literal Block Distance+         -- * Clause Metrics        , lbdOf+       , updateNDD+       , nddOf          -- * Restart        , checkRestartCondition+         -- * Reporting+       , dumpStats        )         where -import Control.Monad (when)+import Control.Monad (void, when)+import Data.Bits+import Data.List (intercalate)+import Numeric (showFFloat) import SAT.Mios.Types import SAT.Mios.Clause import SAT.Mios.ClauseManager@@ -37,16 +45,18 @@ -- | __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+varBumpActivity s@Solver{..} v = do+  x <- getNth activities v+  y <- fromIntegral <$> getStat s NumOfBackjump+  let a = (x + y) / 2+  setNth activities v a   when (varActivityThreshold < a) $ varRescaleActivity s-  update s x                    -- update the position in heap+  updateVO s v                    -- update the position in heap  -- | __Fig. 14 (p.19)__ {-# INLINABLE varDecayActivity #-} varDecayActivity :: Solver -> IO ()-varDecayActivity Solver{..} = modify' varInc (/ variableDecayRate config)+varDecayActivity Solver{..} = return () -- modify' varInc (/ variableDecayRate config)  -- | __Fig. 14 (p.19)__ {-# INLINABLE varRescaleActivity #-}@@ -129,104 +139,44 @@ -- * @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+clauseNew :: Solver -> Stack -> IO (Either Bool Clause)+clauseNew s@Solver{..} ps = do+  n <- get' ps+  sortStack ps+  let loop :: Int -> Int -> Lit -> IO Bool+      loop ((<= n) -> False) j _ = setNth ps 0 (j - 1) >> return False+      loop !i !j !l' = do l <- getNth ps i -- check the i-th literal's satisfiability+                          sat <- valueLit s l+                          if | sat == LiftedT || negateLit l == l' -> reset ps >> return True+                             | sat /= LiftedF && l /= l' -> setNth ps j l >> loop (i + 1) (j + 1) l+                             | otherwise -> loop (i + 1) j l'+  exit <- loop 1 1 LBottom   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)+   1 -> do l <- getNth ps 1+           Left <$> enqueue s l NullClause+   _ -> do c <- newClauseFromStack False ps+           let lstack = lits c+           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.+-- This function is called only before the solving phase to register the given clauses (not learnt). {-# INLINABLE addClause #-} addClause :: Solver -> Stack -> IO Bool addClause s@Solver{..} vecLits = do-  result <- clauseNew s vecLits False+  result <- clauseNew s vecLits   case result of-   Left b  -> return b   -- No new clause was returned becaues a confilct occured or the clause is a literal+   Left b  -> return b -- No clause is returned becaues a confilct occured or the clause is a literal    Right c -> pushTo clauses c >> return True --------------------------------------------------------------------------------- LBD+-------------------------------------------------------------------------------- Clause Metrics --- | returns a POSIVITE value+-- | returns a POSIVITE value of Literal Block Distance {-# INLINABLE lbdOf #-} lbdOf :: Solver -> Stack -> IO Int lbdOf Solver{..} vec = do@@ -262,66 +212,138 @@     _ -> return () -} --------------------------------------------------------------------------------- restart+-- | returns a vector index of NDD for the nth bit of a var+{-# INLINE varBit2vIndex #-}+varBit2vIndex :: Int -> Int -> Int+varBit2vIndex v ((`mod` 124) -> b)+  | 62 <= b   = 2 * v + 1+  | otherwise = 2 * v -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 |+-- | returns a bit index of NDD for the nth bit of a var+{-# INLINE varBit2bIndex #-}+varBit2bIndex :: Int -> Int -> Int+varBit2bIndex v b = mod b 62 -ema0 :: Int-ema0 = 2 ^ (14 :: Int)          -- = floor $ 1 / ema2+-- | updates a /var/'s ndl, which is assigned by a 'reason' /clause/+{-# INLINE updateNddOf #-}+updateNddOf :: Solver -> Var -> Clause -> IO ()+updateNddOf Solver{..} v NullClause = do+  l <- getNth level v+  setNth ndd (varBit2vIndex v l) $ if l == 0 then 0 else setBit 0 (varBit2bIndex v l) --- | #62-checkRestartCondition :: Solver -> Int -> IO Bool-checkRestartCondition s@Solver{..} (fromIntegral -> lbd) = do-  k <- getStat s NumOfRestart-  let step = 100+updateNddOf Solver{..} v Clause{..} = do+  n <- get' lits+  let iv = varBit2vIndex v 0+  setNth ndd iv 0+  setNth ndd (iv + 1) 0+  let loop :: Int -> Int -> Int -> IO ()+      loop ((<= n) -> False) low high = do setNth ndd iv low+                                           setNth ndd (iv + 1) high+      loop i low high = do v' <- lit2var <$> getNth lits i+                           let jv = varBit2vIndex v' 0+                           low' <- (low .|.) <$> getNth ndd jv+                           high' <- (high .|.) <$> getNth ndd (jv + 1)+                           loop (i + 1) low' high'+  loop 1 0 0++-- | updates all assigned vars' ndl+{-# INLINABLE updateNDD #-}+updateNDD :: Solver -> IO ()+updateNDD s@Solver{..} = do+  n <- get' trail+  let -- thr = if ns == 0 then 0 else floor . logBase 2 $ lv / ns :: Int+      update :: Int -> IO ()+      update ((<= n) -> False) = return ()+      update i = do v <- lit2var <$> getNth trail i+                    updateNddOf s v =<< getNth reason v+                    update (i + 1)+  update 1++-- | returns the NDL+{-# INLINABLE nddOf #-}+nddOf :: Solver -> Stack -> IO Int+nddOf Solver{..} stack = do+  n <- get' stack+  let loop :: Int -> Int -> Int -> IO Int -- var -> #lowbits -> #highbits+      loop ((<= n) -> False) low high = return $ popCount low + popCount high+      loop i low high = do v <- lit2var <$> getNth stack i+                           let iv = varBit2vIndex v 0+                           l <- getNth ndd iv+                           h <- getNth ndd (iv + 1)+                           loop (i + 1) (low .|. l) (high .|. h)+  max 1 <$> loop 1 0 0++-------------------------------------------------------------------------------- restart++-- | #62, #74, #91+checkRestartCondition :: Solver -> Int -> Int -> IO Bool+checkRestartCondition s@Solver{..} (fromIntegral -> lbd) (fromIntegral -> cLv) = do   next <- get' nextRestart-  count <- getStat s NumOfBackjump+  count <- getStat s NumOfBackjump -- it should be > 0   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+  bLv <- fromIntegral <$> decisionLevel s+  df  <- updateEMA emaDFast lbd+  ds  <- updateEMA emaDSlow lbd+  af  <- updateEMA emaAFast nas+  as  <- updateEMA emaASlow nas+  void $ updateEMA emaCDLvl cLv+  nb <- getStat s NumOfBlockRestart+  nf <- getStat s NumOfRestart+  let bias = if | nb <= 10  -> 0+                | nb <= nf  -> 0.1 * (fromIntegral nf / fromIntegral nb) ** 2+                | otherwise -> 0.1 * negate ((fromIntegral nb / fromIntegral nf) ** 2)+      block = 1.25 * as < af+      force = (1.25 + bias) * ds < df+      updateParams ki = do+        gef <- (max 0) . (+ ki) <$> get' restartExp+        set' nextRestart $ count + 100 + ceiling (50 * gef)+        set' restartExp gef+      updateBDL = updateEMA emaBDLvl bLv >> return False+      restartBDL = do+        updateEMA emaBDLvl 0+        -- do z <- get' restartExp; when (0.4 < z) $ print (nb, nf, bias, z)+        when (3 == dumpSolverStatMode config) $ dumpStats DumpCSV s+        return True+  if | count < next -> updateBDL+     | block        -> 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+         updateParams 1.0   >> updateBDL+     | force        -> do          incrementStat s NumOfRestart 1-         set' nextRestart (count + step)-         when (3 == dumpStat config) $ dumpSolver DumpCSV s-         return True-     | otherwise      -> return False+         updateParams (-0.1) >> restartBDL+     | otherwise    -> do+         updateParams (-0.9) >> updateBDL -{--{-# 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)--}+-------------------------------------------------------------------------------- dump++emaLabels :: [(String, Solver -> EMA)]+emaLabels = [ ("emaAFast", emaAFast)+            , ("emaASlow", emaASlow)+            , ("emaBDLvl", emaBDLvl)+            , ("emaCDLvl", emaCDLvl)+            , ("emaDFast", emaDFast)+            , ("emaDSlow", emaDSlow)+            ]++{-# INLINABLE dumpStats #-}+-- | print statatistic data to stdio. This should be called after each restart.+dumpStats :: DumpMode -> Solver -> IO ()+dumpStats NoDump _ = return ()+dumpStats DumpCSVHeader s@Solver{..} = do+  sts <- init <$> getStats s+  putStrLn . intercalate "," $ map (show . fst) sts ++ map fst emaLabels+dumpStats DumpCSV s@Solver{..} = do+  -- update the stat data before dump+  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+  sts <- init <$> getStats s+  let fs :: (Solver -> EMA) -> IO String+      fs e = do x <- getEMA (e s)+                return $ showFFloat (Just 3) x ""+  vals <- mapM (fs . snd) emaLabels+  putStrLn . intercalate "," $ map (show . snd) sts ++ vals+-- | FIXME: use Util/Stat+dumpStats DumpJSON _ = return ()                -- mode 2: JSON
src/SAT/Mios/Main.hs view
@@ -16,7 +16,7 @@        , newSolver        , setAssign        , addClause-       , dumpSolver+       , dumpStats          -- * Main function        , simplifyDB        , solve@@ -64,14 +64,13 @@            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+               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 -- get the index of the literal with highest level            -- Bump, enqueue, store clause:            claBumpActivity s c            -- Add clause to all managers@@ -84,7 +83,7 @@            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+           setRank c lbd            -- assert (0 < rank c)            -- set' (protected c) True            return lbd@@ -142,7 +141,7 @@   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)+        d <- getRank c         when (0 /= d) $ claBumpActivity s c         -- update LBD like #Glucose4.0         when (2 < d) $ do@@ -150,7 +149,7 @@           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+            setRank c nblevels     --  Update it         sc <- get' c         let lstack = lits c             loopOnLiterals :: Int -> Int -> Int -> IO (Int, Int)@@ -169,7 +168,7 @@                           -- UPDATEVARACTIVITY: glucose heuristics                           r <- getNth reason v                           when (r /= NullClause) $ do-                            ra <- get' (rank r)+                            ra <- getRank r                             when (0 /= ra) $ pushTo an'lastDL q                           -- end of glucose heuristics                           loopOnLiterals (j + 1) b (pc + 1)@@ -198,7 +197,7 @@       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+                      -- restrict the search depth (range) to [0 .. 63]                       merger (i + 1) . setBit b . (63 .&.) =<< getNth level (lit2var l)   levels <- merger 2 0   let loopOnLits :: Int -> Int -> IO ()@@ -439,6 +438,7 @@ reduceDB s@Solver{..} = do   n <- nLearnts s   cvec <- getClauseVector learnts+  n' <- get' trail   let loop :: Int -> IO ()       loop ((< n) -> False) = return ()       loop i = do@@ -464,17 +464,13 @@  -- constants for sort key layout rankWidth :: Int-rankWidth = 10+rankWidth = 11 activityWidth :: Int-activityWidth = 50              -- note: the maximum clause activity is 1e20.-indexWidth :: Int-indexWidth = 32                 -- 4G+activityWidth = 51              -- note: the maximum clause activity is 1e20. 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.@@ -483,23 +479,23 @@ -- 2. smaller LBD -- 3. larger activity defined as MiniSat ----- they are encoded into two "Int64"s as the following (10+52+32 layout):+-- They are encoded into an "Int64" as the following (11+51 layout): ----- * 10 bits for rank (LBD): 'rankWidth'--- * 50 bits for converted activity: 'activityWidth'--- * 32 bits for clauseVector index: 'indexWidth'+-- * 11 bits for rank (LBD): 'rankWidth'+-- * 51 bits for converted activity: 'activityWidth' -- 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)+  kvec <- getKeyVector cm   at <- (0.1 *) . (/ fromIntegral n) <$> get' (claInc s) -- activity threshold   -- 1: assign keys+  updateNDD s+  cl <- getEMA (emaCDLvl s)+  surface <- if cl == 0 then return 0 else (/ cl) <$> getEMA (emaBDLvl s)  -- 0 <=backjumped level / coflict level < 1.0   let shiftLBD = activityWidth-      shiftIndex = shiftL 1 indexWidth       am = fromIntegral activityMax :: Double       scaleAct :: Double -> Int       scaleAct x@@ -508,78 +504,60 @@       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+          then do setNth kvec i 0                   assignKey (i + 1) (t + 1)-          else do a <- get' (activity c)               -- Second one... based on LBD-                  r <- get' (rank c)+          else do a <- get' (activity c)                       -- Second one... based on LBD+                  rLBD <- fromIntegral <$> getRank c           -- above the level+                  rNDD <- fromIntegral <$> nddOf s (lits c)    -- under the level+                  let r = if rNDD == 1                         -- this implies rLBD == 1.+                          then 1+                          else ceiling $ rLBD ** surface * rNDD ** (1 - surface)                   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+                  setNth kvec 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 ()+  let sortOnRange :: Int -> Int -> IO ()       sortOnRange left right-        | limit2 < left = return ()+        | limit < 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)+        | left + 1 == right = do+            a <- getNth kvec left+            b <- getNth kvec right+            unless (a < b) $ do setNth kvec left b+                                setNth kvec right a+                                swapBetween vec left right         | 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 p = div (left + right) 2+            pivot <- getNth kvec p+            swapBetween kvec p left -- set a sentinel for r'+            swapBetween vec p left             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+                nextL i = do v <- getNth kvec 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 - 2) else return i+                nextR i = do v <- getNth kvec 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 do swapBetween keys l' r'-                            swapBetween keys (l' + 1) (r' + 1)-                            divide (l' + 2) (r' - 2)+                    then do swapBetween kvec l' r'+                            swapBetween vec l' r'+                            divide (l' + 1) (r' - 1)                     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+            m <- divide (left + 1) right+            swapBetween kvec left m+            swapBetween vec left m+            sortOnRange left (m - 1)+            sortOnRange (m + 1) right+  sortOnRange 0 (n - 1)   return limit  -- | #M22@@ -637,6 +615,7 @@ search :: Solver -> IO Bool search s@Solver{..} = do   -- clear model+  let delta = (sqrt . fromIntegral) nVars   let loop :: Bool -> IO Bool       loop restart = do         confl <- propagate s@@ -662,16 +641,15 @@                               t' <- (* 1.5) <$> get' learntSAdj                               set' learntSAdj t'                               set' learntSCnt $ floor t'-                              -- modify' maxLearnts (* 1.1)-                              modify' maxLearnts (+ 300)-                            loop =<< checkRestartCondition s lbd'+                              modify' maxLearnts (+ delta)+                            loop =<< checkRestartCondition s lbd' d           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+                    when (2 == dumpSolverStatMode config) $ dumpStats DumpCSV s                   if | k2 == nVars -> return True     -- Model found                      | restart -> do                  -- Reached bound on number of conflicts                          (s `cancelUntil`) =<< get' rootLevel -- force a restart@@ -690,7 +668,7 @@ -}                          loop False                      | otherwise -> do                -- New variable decision-                         v <- select s+                         v <- selectVO s                          -- #phasesaving <<<<  many have heuristic for polarity here                          oldVal <- getNth phases v                          unsafeAssume s $ var2lit v (0 < oldVal) -- cannot return @False@@@ -723,8 +701,9 @@                             cancelUntil s 0                             return False                     else return True+  check_given <- get' ok   good <- simplifyDB s-  x <- if good then foldrM inject True assumps else return False+  x <- if check_given /= LiftedF && good then foldrM inject True assumps else return False   if x     then do set' rootLevel =<< decisionLevel s             status <- search s@@ -733,7 +712,7 @@                 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+            when (0 < dumpSolverStatMode config) $ dumpStats DumpCSV s             cancelUntil s 0     -- reset solver             flag <- get' ok             if | status && flag == LiftedT     -> return $ Right (SAT asg1)
src/SAT/Mios/OptionParser.hs view
@@ -23,41 +23,43 @@ -- | configuration swithces data MiosProgramOption = MiosProgramOption                      {-                       _targetFile :: Maybe String-                     , _targets :: [String]-                     , _outputFile :: Maybe String-                     , _confVariableDecayRate :: !Double-                     , _confClauseDecayRate :: Double+                       _targetFile            :: Either String String -- path or data+                     , _targets               :: [String]+                     , _outputFile            :: Maybe String+                     , _confVariableDecayRate :: Double+                     , _confClauseDecayRate   :: Double+                     , _confRestartE          :: Double+                     , _confRestartS          :: Double --                     , _confRandomDecisionRate :: Int-                     , _confMaxSize :: !Int-                     , _confCheckAnswer :: !Bool-                     , _confVerbose :: !Bool-                     , _confBenchmark :: Integer-                     , _confBenchSeq :: !Int-                     , _confNoAnswer :: !Bool-                     , _confDumpStat :: !Int-                     , _validateAssignment :: !Bool-                     , _displayHelp :: !Bool-                     , _displayVersion :: !Bool+                     , _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+    _targetFile = Left ""   , _targets = []   , _outputFile = Nothing   , _confVariableDecayRate = variableDecayRate defaultConfiguration   , _confClauseDecayRate = clauseDecayRate defaultConfiguration---  , _confRandomDecisionRate = randomDecisionRate defaultConfiguration-  , _confMaxSize = 4000000    -- 4,000,000 = 4M+  , _confRestartE = restartExpansion defaultConfiguration+  , _confRestartS = restartStep defaultConfiguration+  --, _confRandomDecisionRate = randomDecisionRate defaultConfiguration   , _confCheckAnswer = False   , _confVerbose = False   , _confBenchmark = -1   , _confBenchSeq = 0   , _confNoAnswer = False-  , _confDumpStat = dumpStat defaultConfiguration+  , _confDumpStat = dumpSolverStatMode defaultConfiguration   , _validateAssignment = False   , _displayHelp = False   , _displayVersion = False@@ -73,12 +75,15 @@   , 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 [] ["Re"]+    (ReqArg (\v c -> c { _confRestartE = read v }) (show (_confRestartE miosDefaultOption)))+    "[solver] expansion rate for blocking/forcing restart (>= 1.0)"+  , Option [] ["Rs"]+    (ReqArg (\v c -> c { _confRestartS = read v }) (show (_confRestartS miosDefaultOption)))+    "[solver] a fixed number of conflicts between restarts" --  , 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"@@ -87,7 +92,7 @@     "[solver] self-check (satisfiable) assignment"   , Option ['o'] ["output"]     (ReqArg (\v c -> c { _outputFile = Just v }) "file")-    "[option] filename to store result"+    "[option] filename to store result, '--' for stdout" {-   , Option [] ["stdin"]     (NoArg (\c -> c { _targetFile = Nothing }))@@ -106,7 +111,7 @@     (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)))+    (ReqArg (\v c -> c { _confDumpStat = read v }) (show (dumpSolverStatMode defaultConfiguration)))     "[devel] dump level; 1:solved, 2:reduction, 3:restart"   , Option ['h'] ["help"]     (NoArg (\c -> c { _displayHelp = True }))@@ -127,7 +132,7 @@       (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 }+        return $ conf { _targetFile = Left (head l), _targets = l }       (_, _, errs) -> ioError (userError (concat errs ++ miosUsage mes))  -- | builds "MiosProgramOption" from a String@@ -141,5 +146,8 @@                    variableDecayRate = _confVariableDecayRate opts                  , clauseDecayRate = _confClauseDecayRate opts --                 , randomDecisionRate = _confRandomDecisionRate opts-                 , dumpStat = _confDumpStat opts+                 , dumpSolverStatMode = _confDumpStat opts+                 , emaCoeffs = emaCoeffs defaultConfiguration+                 , restartExpansion = _confRestartE opts+                 , restartStep      = _confRestartS opts                  }
src/SAT/Mios/Solver.hs view
@@ -33,7 +33,6 @@        , setStat        , incrementStat        , getStats-       , dumpSolver        )         where @@ -60,6 +59,7 @@               , 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+              , ndd        :: !(Vec Int)         -- ^ For each variable, the number of depending decisions               , conflicts  :: !Stack             -- ^ Set of literals in the case of conflicts                 -------- Variable Order               , activities :: !(Vec Double)      -- ^ Heuristic measurement of the activity of a variable@@ -82,16 +82,19 @@               , 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+              , 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+                -------- restart heuristics #62, clause evaluation criteria #74+              , emaAFast    :: !EMA              -- ^ Number of Assignments Fast+              , emaASlow    :: !EMA              -- ^ Number of Assignments Slow+              , emaBDLvl    :: !EMA              -- ^ Backjumped and Restart Dicision Level+              , emaCDLvl    :: !EMA              -- ^ Conflicting Level+              , emaDFast    :: !EMA              -- ^ (Literal Block) Distance Fast+              , emaDSlow    :: !EMA              -- ^ (Literal Block) Distance Slow               , nextRestart :: !Int'             -- ^ next restart in number of conflict-              , restartMode :: Int'              -- ^ mode of restart+              , restartExp  :: !Double'          -- ^ incremented by blocking+              , emaRstBias  :: !EMA              -- ^ average phase of restart               }  -- | returns an everything-is-initialized solver from the arguments.@@ -101,7 +104,7 @@     -- Clause Database     <$> newManager dummy_nc                -- clauses     <*> newManager 2000                    -- learnts-    <*> newWatcherList nv 2                -- watches+    <*> newWatcherList nv 1                -- watches     -- Assignment Management     <*> newVec nv LBottom                  -- assigns     <*> newVec nv LBottom                  -- phases@@ -110,6 +113,7 @@     <*> new' 0                             -- qHead     <*> newClauseVector (nv + 1)           -- reason     <*> newVec nv (-1)                     -- level+    <*> newVec (2 * (nv + 1)) 0            -- ndd     <*> newStack nv                        -- conflicts     -- Variable Order     <*> newVec nv 0                        -- activities@@ -136,12 +140,17 @@     <*> 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+    <*> newEMA False ef                    -- emaAFast+    <*> newEMA True es                     -- emaASlow+    <*> newEMA True 2                      -- emaBDLvl+    <*> newEMA True 2                      -- emaCDLvl+    <*> newEMA False ef                    -- emaDFast+    <*> newEMA True es                     -- emaDSlow     <*> new' 100                           -- nextRestart-    <*> new' 1                             -- restartMode+    <*> new' 0.0                           -- restartExp+    <*> newEMA False 100                   -- emaRstBias+  where+    (ef, es) = emaCoeffs conf  -------------------------------------------------------------------------------- -- Accessors@@ -267,7 +276,7 @@         -- 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+        undoVO s x         -- insertHeap s x              -- insertVerOrder         loopOnTrail $ c - 1     loopOnTrail ts@@ -295,12 +304,12 @@     -- 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+  {-# SPECIALIZE INLINE updateVO :: Solver -> Var -> IO () #-}+  updateVO = increaseHeap+  {-# SPECIALIZE INLINE undoVO :: Solver -> Var -> IO () #-}+  undoVO s v = inHeap s v >>= (`unless` insertHeap s v)+  {-# SPECIALIZE INLINE selectVO :: Solver -> IO Var #-}+  selectVO s = do     let       asg = assigns s       -- | returns the most active var (heap-based implementation)@@ -418,37 +427,3 @@   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
@@ -37,6 +37,11 @@        , Int (LiftedF, LiftedT, LBottom, Conflict)        -- a heap        , VarOrder (..)+       -- Exponential Moving Average, EMA+       , EMA+       , newEMA+       , getEMA+       , updateEMA          -- * statistics        , StatIndex (..)        , DumpMode (..)@@ -250,36 +255,72 @@   newVar = error "newVar undefined" -}   -- | should be called when a variable has increased in activity.-  update :: o -> Var -> IO ()-  update _  = error "update undefined"+  updateVO :: o -> Var -> IO ()+  updateVO _  = 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"+  undoVO :: o -> Var -> IO ()+  undoVO _ _  = error "undo undefined"    -- | returns a new, unassigned var as the next decision.-  select :: o -> IO Var-  select    = error "select undefined"+  selectVO :: o -> IO Var+  selectVO    = error "select undefined" +-------------------------------------------------------------------------------- EMA++-- | Exponential Moving Average, EMA+type EMA = (Double', Maybe Double', Double)++-- | returns a new EMA from a flag (slow or fast) and a window size+{-# INLINE newEMA #-}+newEMA :: Bool -> Int -> IO EMA+newEMA True s = do v <- new' 0.0+                   c <- new' 0.0+                   return (v, Just c, 1 / fromIntegral s)+newEMA False s = do v <- new' 0.0; return (v, Nothing, 1 / fromIntegral s)++-- | returns an EMA value+{-# INLINE getEMA #-}+getEMA :: EMA -> IO Double+getEMA (ema, Just cal, _) = do x <- get' ema+                               c <- get' cal+                               return $ if c == 0 then 0 else x / c+getEMA (ema, Nothing, _)  = get' ema++-- | updates an EMA+{-# INLINE updateEMA #-}+updateEMA :: EMA -> Double -> IO Double+updateEMA (ema, Just cal, cof) x = do e <- ((cof * x) +) . ((1 - cof) *) <$> get' ema+                                      set' ema e+                                      c <- ((cof * 1) +) . ((1 - cof) *) <$> get' cal+                                      set' cal c+                                      return $ e / c+updateEMA (ema, Nothing, cof) x = do e <- ((cof * x) +) . ((1 - cof) *) <$> get' ema; set' ema e; return e++-------------------------------------------------------------------------------- CNF+ -- | 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+  , _pathname :: !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+                           variableDecayRate  :: !Double     -- ^ decay rate for variable activity+                         , clauseDecayRate    :: !Double     -- ^ decay rate for clause activity+                         , dumpSolverStatMode :: !Int        -- ^ dump stats data during solving+                         , emaCoeffs          :: !(Int, Int) -- ^ the coefficients for restarts+                         , restartExpansion   :: !Double     -- ^ restart expansion factor+                         , restartStep        :: !Double     -- ^ static Steps between restarts                          }   deriving (Eq, Ord, Read, Show) @@ -291,7 +332,9 @@ -- * Mios-1.2     uses @(0.95, 0.999, 0)@. -- defaultConfiguration :: MiosConfiguration-defaultConfiguration = MiosConfiguration 0.95 0.999 0+defaultConfiguration = MiosConfiguration 0.95 0.999 0 (ef, es) 1.15 100+  where ef = (2 :: Int) ^ ( 5 :: Int)+        es = (2 :: Int) ^ (14 :: Int)  -------------------------------------------------------------------------------- Statistics 
src/SAT/Mios/Vec.hs view
@@ -24,7 +24,7 @@        , StackFamily (..)        , Stack        , newStackFromList-       , realLengthOfStack+       , realLength        , sortStack        )        where@@ -98,67 +98,6 @@   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)@@ -181,10 +120,14 @@                                         BA.writeByteArray v j (x :: Int)   {-# SPECIALIZE INLINE reset :: ByteArrayInt -> IO () #-}   reset (ByteArrayInt v) = BA.writeByteArray v 0 (0 :: Int)+  {-# SPECIALIZE INLINE newVec :: Int -> Int -> IO ByteArrayInt #-}   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+  growBy (ByteArrayInt v) n = do v' <- BA.newByteArray (BA.sizeofMutableByteArray v + 8 * n)+                                 BA.copyMutableByteArray v' 0 v 0 (BA.sizeofMutableByteArray v)+                                 return (ByteArrayInt v')   asList (ByteArrayInt v) = mapM (BA.readByteArray v) [0 .. div (BA.sizeofMutableByteArray v) 8 - 1]  instance VecFamily ByteArrayDouble Double where@@ -201,12 +144,18 @@                                            BA.writeByteArray v j (x :: Int)   {-# SPECIALIZE INLINE reset :: ByteArrayDouble -> IO () #-}   reset (ByteArrayDouble v) = BA.writeByteArray v 0 (0 :: Double)+  {-# SPECIALIZE INLINE newVec :: Int -> Double -> IO ByteArrayDouble #-}   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] +-- | returns the number of allocated slots+{-# INLINE realLength #-}+realLength :: Vec Int -> Int+realLength (ByteArrayInt v) = div (BA.sizeofMutableByteArray v) 8+ -------------------------------------------------------------------------------- SingleStorage  -- | Interface for single (one-length vector) mutable data@@ -318,37 +267,32 @@       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+      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+            if a < b then return () else setNth vec left b >> setNth vec right a         | 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+                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+                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+                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'
+ test/MiosSpec.hs view
@@ -0,0 +1,14 @@+module MiosSpec (spec) where++import System.IO.Unsafe+import Test.Hspec+import SAT.Mios++testRun :: Spec+testRun = do+  describe "SAT problems" $ do+    let res = unsafePerformIO $ solveSAT (CNFDescription 4 5 Nothing) [[1,2,-3], [-1, -4], [2,4], [1,-3,4], [-3,4]]+    it "a simple SAT" $ res `shouldBe` [-1,2,-3,-4]++spec :: Spec+spec = testRun
+ test/Spec.hs view
@@ -0,0 +1,8 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}+-- main :: IO ()+-- main = putStrLn "Test suite not yet implemented"++--import SAT.Mios+--main :: IO ()+--main = do+--  print =<< solveSAT (CNFDescription 4 5 "") [[1,2,-3], [-1, -4], [2,4], [1,-3,4], [-3,4]]