toysolver-0.2.0: test/TestSAT.hs
{-# LANGUAGE TemplateHaskell #-}
module Main (main) where
import Control.Monad
import Data.Array.IArray
import Data.List
import Data.Set (Set)
import qualified Data.Set as Set
import Data.IntSet (IntSet)
import qualified Data.IntSet as IntSet
import Test.HUnit hiding (Test)
import Test.QuickCheck hiding ((.&&.), (.||.))
import qualified Test.QuickCheck.Monadic as QM
import Test.Framework (Test, defaultMain, testGroup)
import Test.Framework.TH
import Test.Framework.Providers.HUnit
import Test.Framework.Providers.QuickCheck2
import ToySolver.Data.LBool
import ToySolver.Data.BoolExpr
import ToySolver.Data.Boolean
import ToySolver.SAT
import ToySolver.SAT.Types
import qualified ToySolver.SAT.TseitinEncoder as Tseitin
import qualified ToySolver.SAT.MUS as MUS
import qualified ToySolver.SAT.MUS.CAMUS as CAMUS
import qualified ToySolver.SAT.MUS.DAA as DAA
import qualified ToySolver.SAT.PBO as PBO
prop_solveCNF :: Property
prop_solveCNF = QM.monadicIO $ do
cnf@(nv,_) <- QM.pick arbitraryCNF
ret <- QM.run $ solveCNF cnf
case ret of
Just m -> QM.assert $ evalCNF m cnf == True
Nothing -> do
forM_ [array (1,nv) (zip [1..nv] xs) | xs <- replicateM nv [True,False]] $ \m -> do
QM.assert $ evalCNF m cnf == False
solveCNF :: (Int,[Clause]) -> IO (Maybe Model)
solveCNF (nv,cs) = do
solver <- newSolver
setCheckModel solver True
newVars_ solver nv
forM_ cs $ \c -> addClause solver c
ret <- solve solver
if ret then do
m <- getModel solver
return (Just m)
else do
return Nothing
arbitraryCNF :: Gen (Int,[Clause])
arbitraryCNF = do
nv <- choose (0,10)
nc <- choose (0,50)
cs <- replicateM nc $ do
len <- choose (0,10)
if nv == 0 then
return []
else
replicateM len $ choose (-nv, nv) `suchThat` (/= 0)
return (nv, cs)
evalCNF :: Model -> (Int,[Clause]) -> Bool
evalCNF m (_,cs) = all (evalClause m) cs
prop_solvePB :: Property
prop_solvePB = QM.monadicIO $ do
prob@(nv,_) <- QM.pick arbitraryPB
ret <- QM.run $ solvePB prob
case ret of
Just m -> QM.assert $ evalPB m prob == True
Nothing -> do
forM_ [array (1,nv) (zip [1..nv] xs) | xs <- replicateM nv [True,False]] $ \m -> do
QM.assert $ evalPB m prob == False
solvePB :: (Int,[PBLinAtLeast]) -> IO (Maybe Model)
solvePB (nv,cs) = do
solver <- newSolver
setCheckModel solver True
newVars_ solver nv
forM_ cs $ \c -> addPBAtLeast solver (fst c) (snd c)
ret <- solve solver
if ret then do
m <- getModel solver
return (Just m)
else do
return Nothing
arbitraryPB :: Gen (Int,[PBLinAtLeast])
arbitraryPB = do
nv <- choose (0,10)
nc <- choose (0,50)
cs <- replicateM nc $ do
len <- choose (0,10)
lhs <-
if nv == 0 then
return []
else
replicateM len $ do
l <- choose (-nv, nv) `suchThat` (/= 0)
c <- arbitrary
return (c,l)
rhs <- arbitrary
return (lhs,rhs)
return (nv, cs)
evalPB :: Model -> (Int,[PBLinAtLeast]) -> Bool
evalPB m (_,cs) = all (evalPBLinAtLeast m) cs
prop_solveXOR :: Property
prop_solveXOR = QM.monadicIO $ do
prob@(nv,_) <- QM.pick arbitraryXOR
ret <- QM.run $ solveXOR prob
case ret of
Just m -> QM.assert $ evalXOR m prob == True
Nothing -> do
forM_ [array (1,nv) (zip [1..nv] xs) | xs <- replicateM nv [True,False]] $ \m -> do
QM.assert $ evalXOR m prob == False
solveXOR :: (Int,[XORClause]) -> IO (Maybe Model)
solveXOR (nv,cs) = do
solver <- newSolver
setCheckModel solver True
newVars_ solver nv
forM_ cs $ \c -> addXORClause solver (fst c) (snd c)
ret <- solve solver
if ret then do
m <- getModel solver
return (Just m)
else do
return Nothing
arbitraryXOR :: Gen (Int,[XORClause])
arbitraryXOR = do
nv <- choose (0,10)
nc <- choose (0,50)
cs <- replicateM nc $ do
len <- choose (0,10)
lhs <-
if nv == 0 then
return []
else
replicateM len $ choose (-nv, nv) `suchThat` (/= 0)
rhs <- arbitrary
return (lhs,rhs)
return (nv, cs)
evalXOR :: Model -> (Int,[XORClause]) -> Bool
evalXOR m (_,cs) = all (evalXORClause m) cs
-- should be SAT
case_solve_SAT :: IO ()
case_solve_SAT = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
addClause solver [literal x1 True, literal x2 True] -- x1 or x2
addClause solver [literal x1 True, literal x2 False] -- x1 or not x2
addClause solver [literal x1 False, literal x2 False] -- not x1 or not x2
ret <- solve solver
ret @?= True
-- shuld be UNSAT
case_solve_UNSAT :: IO ()
case_solve_UNSAT = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
addClause solver [literal x1 True, literal x2 True] -- x1 or x2
addClause solver [literal x1 False, literal x2 True] -- not x1 or x2
addClause solver [literal x1 True, literal x2 False] -- x1 or not x2
addClause solver [literal x1 False, literal x2 False] -- not x2 or not x2
ret <- solve solver
ret @?= False
-- top level でいきなり矛盾
case_root_inconsistent :: IO ()
case_root_inconsistent = do
solver <- newSolver
x1 <- newVar solver
addClause solver [literal x1 True]
addClause solver [literal x1 False]
ret <- solve solver -- unsat
ret @?= False
-- incremental に制約を追加
case_incremental_solving :: IO ()
case_incremental_solving = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
addClause solver [literal x1 True, literal x2 True] -- x1 or x2
addClause solver [literal x1 True, literal x2 False] -- x1 or not x2
addClause solver [literal x1 False, literal x2 False] -- not x1 or not x2
ret <- solve solver -- sat
ret @?= True
addClause solver [literal x1 False, literal x2 True] -- not x1 or x2
ret <- solve solver -- unsat
ret @?= False
-- 制約なし
case_empty_constraint :: IO ()
case_empty_constraint = do
solver <- newSolver
ret <- solve solver
ret @?= True
-- 空の節
case_empty_claue :: IO ()
case_empty_claue = do
solver <- newSolver
addClause solver []
ret <- solve solver
ret @?= False
-- 自明に真な節
case_excluded_middle_claue :: IO ()
case_excluded_middle_claue = do
solver <- newSolver
x1 <- newVar solver
addClause solver [x1, -x1] -- x1 or not x1
ret <- solve solver
ret @?= True
-- 冗長な節
case_redundant_clause :: IO ()
case_redundant_clause = do
solver <- newSolver
x1 <- newVar solver
addClause solver [x1,x1] -- x1 or x1
ret <- solve solver
ret @?= True
case_instantiateClause :: IO ()
case_instantiateClause = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
addClause solver [x1]
addClause solver [x1,x2]
addClause solver [-x1,x2]
ret <- solve solver
ret @?= True
case_instantiateAtLeast :: IO ()
case_instantiateAtLeast = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
x3 <- newVar solver
x4 <- newVar solver
addClause solver [x1]
addAtLeast solver [x1,x2,x3,x4] 2
ret <- solve solver
ret @?= True
addAtLeast solver [-x1,-x2,-x3,-x4] 2
ret <- solve solver
ret @?= True
case_inconsistent_AtLeast :: IO ()
case_inconsistent_AtLeast = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
addAtLeast solver [x1,x2] 3
ret <- solve solver -- unsat
ret @?= False
case_trivial_AtLeast :: IO ()
case_trivial_AtLeast = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
addAtLeast solver [x1,x2] 0
ret <- solve solver
ret @?= True
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
addAtLeast solver [x1,x2] (-1)
ret <- solve solver
ret @?= True
case_AtLeast_1 :: IO ()
case_AtLeast_1 = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
x3 <- newVar solver
addAtLeast solver [x1,x2,x3] 2
addAtLeast solver [-x1,-x2,-x3] 2
ret <- solve solver -- unsat
ret @?= False
case_AtLeast_2 :: IO ()
case_AtLeast_2 = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
x3 <- newVar solver
x4 <- newVar solver
addAtLeast solver [x1,x2,x3,x4] 2
addClause solver [-x1,-x2]
addClause solver [-x1,-x3]
ret <- solve solver
ret @?= True
case_AtLeast_3 :: IO ()
case_AtLeast_3 = do
forM_ [(-1) .. 3] $ \n -> do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
addAtLeast solver [x1,x2] n
ret <- solve solver
assertEqual ("case_AtLeast3_" ++ show n) (n <= 2) ret
-- from http://www.cril.univ-artois.fr/PB11/format.pdf
case_PB_sample1 :: IO ()
case_PB_sample1 = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
x3 <- newVar solver
x4 <- newVar solver
x5 <- newVar solver
addPBAtLeast solver [(1,x1),(4,x2),(-2,x5)] 2
addPBAtLeast solver [(-1,x1),(4,x2),(-2,x5)] 3
addPBAtLeast solver [(12345678901234567890,x4),(4,x3)] 10
addPBExactly solver [(2,x2),(3,x4),(2,x1),(3,x5)] 5
ret <- solve solver
ret @?= True
-- 一部の変数を否定に置き換えたもの
case_PB_sample1' :: IO ()
case_PB_sample1' = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
x3 <- newVar solver
x4 <- newVar solver
x5 <- newVar solver
addPBAtLeast solver [(1,x1),(4,-x2),(-2,x5)] 2
addPBAtLeast solver [(-1,x1),(4,-x2),(-2,x5)] 3
addPBAtLeast solver [(12345678901234567890,-x4),(4,x3)] 10
addPBExactly solver [(2,-x2),(3,-x4),(2,x1),(3,x5)] 5
ret <- solve solver
ret @?= True
-- いきなり矛盾したPB制約
case_root_inconsistent_PB :: IO ()
case_root_inconsistent_PB = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
addPBAtLeast solver [(2,x1),(3,x2)] 6
ret <- solve solver
ret @?= False
case_pb_propagate :: IO ()
case_pb_propagate = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
addPBAtLeast solver [(1,x1),(3,x2)] 3
addClause solver [-x1]
ret <- solve solver
ret @?= True
case_solveWith_1 :: IO ()
case_solveWith_1 = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
x3 <- newVar solver
addClause solver [x1, x2] -- x1 or x2
addClause solver [x1, -x2] -- x1 or not x2
addClause solver [-x1, -x2] -- not x1 or not x2
addClause solver [-x3, -x1, x2] -- not x3 or not x1 or x2
ret <- solve solver -- sat
ret @?= True
ret <- solveWith solver [x3] -- unsat
ret @?= False
ret <- solve solver -- sat
ret @?= True
case_solveWith_2 :: IO ()
case_solveWith_2 = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
addClause solver [-x1, x2] -- -x1 or x2
addClause solver [x1] -- x1
ret <- solveWith solver [x2]
ret @?= True
ret <- solveWith solver [-x2]
ret @?= False
case_getVarFixed :: IO ()
case_getVarFixed = do
solver <- newSolver
x1 <- newVar solver
x2 <- newVar solver
addClause solver [x1,x2]
ret <- getVarFixed solver x1
ret @?= lUndef
addClause solver [-x1]
ret <- getVarFixed solver x1
ret @?= lFalse
ret <- getLitFixed solver (-x1)
ret @?= lTrue
ret <- getLitFixed solver x2
ret @?= lTrue
------------------------------------------------------------------------
-- -4*(not x1) + 3*x1 + 10*(not x2)
-- = -4*(1 - x1) + 3*x1 + 10*(not x2)
-- = -4 + 4*x1 + 3*x1 + 10*(not x2)
-- = 7*x1 + 10*(not x2) - 4
case_normalizePBLinSum :: Assertion
case_normalizePBLinSum = do
sort e @?= sort [(7,x1),(10,-x2)]
c @?= -4
where
x1 = 1
x2 = 2
(e,c) = normalizePBLinSum ([(-4,-x1),(3,x1),(10,-x2)], 0)
-- -4*(not x1) + 3*x1 + 10*(not x2) >= 3
-- ⇔ -4*(1 - x1) + 3*x1 + 10*(not x2) >= 3
-- ⇔ -4 + 4*x1 + 3*x1 + 10*(not x2) >= 3
-- ⇔ 7*x1 + 10*(not x2) >= 7
-- ⇔ 7*x1 + 7*(not x2) >= 7
-- ⇔ x1 + (not x2) >= 1
case_normalizePBLinAtLeast :: Assertion
case_normalizePBLinAtLeast = (sort lhs, rhs) @?= (sort [(1,x1),(1,-x2)], 1)
where
x1 = 1
x2 = 2
(lhs,rhs) = normalizePBLinAtLeast ([(-4,-x1),(3,x1),(10,-x2)], 3)
case_normalizePBLinExactly_1 :: Assertion
case_normalizePBLinExactly_1 = (sort lhs, rhs) @?= (sort [(3,x1),(2,x2)], 1)
where
x1 = 1
x2 = 2
(lhs,rhs) = normalizePBLinExactly ([(6,x1),(4,x2)], 2)
case_normalizePBLinExactly_2 :: Assertion
case_normalizePBLinExactly_2 = (sort lhs, rhs) @?= ([], 1)
where
x1 = 1
x2 = 2
x3 = 3
(lhs,rhs) = normalizePBLinExactly ([(2,x1),(2,x2),(2,x3)], 3)
case_cutResolve_1 :: Assertion
case_cutResolve_1 = (sort lhs, rhs) @?= (sort [(1,x3),(1,x4)], 1)
where
x1 = 1
x2 = 2
x3 = 3
x4 = 4
pb1 = ([(1,x1), (1,x2), (1,x3)], 1)
pb2 = ([(2,-x1), (2,-x2), (1,x4)], 3)
(lhs,rhs) = cutResolve pb1 pb2 x1
case_cutResolve_2 :: Assertion
case_cutResolve_2 = (sort lhs, rhs) @?= (sort [(3,x1),(2,-x2),(2,x4)], 3)
where
x1 = 1
x2 = 2
x3 = 3
x4 = 4
pb1 = ([(3,x1), (2,-x2), (1,x3), (1,x4)], 3)
pb2 = ([(1,-x3), (1,x4)], 1)
(lhs,rhs) = cutResolve pb1 pb2 x3
case_cardinalityReduction :: Assertion
case_cardinalityReduction = (sort lhs, rhs) @?= ([1,2,3,4,5],4)
where
(lhs, rhs) = cardinalityReduction ([(6,1),(5,2),(4,3),(3,4),(2,5),(1,6)], 17)
case_pbSubsume_clause :: Assertion
case_pbSubsume_clause = pbSubsume ([(1,1),(1,-3)],1) ([(1,1),(1,2),(1,-3),(1,4)],1) @?= True
case_pbSubsume_1 :: Assertion
case_pbSubsume_1 = pbSubsume ([(1,1),(1,2),(1,-3)],2) ([(1,1),(2,2),(1,-3),(1,4)],1) @?= True
case_pbSubsume_2 :: Assertion
case_pbSubsume_2 = pbSubsume ([(1,1),(1,2),(1,-3)],2) ([(1,1),(2,2),(1,-3),(1,4)],3) @?= False
------------------------------------------------------------------------
case_normalizeXORClause_False =
normalizeXORClause ([],True) @?= ([],True)
case_normalizeXORClause_True =
normalizeXORClause ([],False) @?= ([],False)
-- x ⊕ y ⊕ x = y
case_normalizeXORClause_case1 =
normalizeXORClause ([1,2,1],True) @?= ([2],True)
-- x ⊕ ¬x = x ⊕ x ⊕ 1 = 1
case_normalizeXORClause_case2 =
normalizeXORClause ([1,-1],True) @?= ([],False)
case_evalXORClause_case1 =
evalXORClause (array (1,2) [(1,True),(2,True)] :: Array Int Bool) ([1,2], True) @?= False
case_evalXORClause_case2 =
evalXORClause (array (1,2) [(1,False),(2,True)] :: Array Int Bool) ([1,2], True) @?= True
case_xor_case1 = do
solver <- newSolver
setCheckModel solver True
x1 <- newVar solver
x2 <- newVar solver
x3 <- newVar solver
addXORClause solver [x1, x2] True -- x1 ⊕ x2 = True
addXORClause solver [x2, x3] True -- x2 ⊕ x3 = True
addXORClause solver [x3, x1] True -- x3 ⊕ x1 = True
ret <- solve solver
ret @?= False
case_xor_case2 = do
solver <- newSolver
setCheckModel solver True
x1 <- newVar solver
x2 <- newVar solver
x3 <- newVar solver
addXORClause solver [x1, x2] True -- x1 ⊕ x2 = True
addXORClause solver [x1, x3] True -- x1 ⊕ x3 = True
addClause solver [x2]
ret <- solve solver
ret @?= True
m <- getModel solver
m ! x1 @?= False
m ! x2 @?= True
m ! x3 @?= True
case_xor_case3 = do
solver <- newSolver
setCheckModel solver True
x1 <- newVar solver
x2 <- newVar solver
x3 <- newVar solver
x4 <- newVar solver
addXORClause solver [x1,x2,x3,x4] True
addAtLeast solver [x1,x2,x3,x4] 2
ret <- solve solver
ret @?= True
------------------------------------------------------------------------
-- from "Pueblo: A Hybrid Pseudo-Boolean SAT Solver"
-- clauseがunitになるレベルで、PB制約が違反状態のままという例。
case_hybridLearning_1 :: IO ()
case_hybridLearning_1 = do
solver <- newSolver
[x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11] <- replicateM 11 (newVar solver)
addClause solver [x11, x10, x9] -- C1
addClause solver [x8, x7, x6] -- C2
addClause solver [x5, x4, x3] -- C3
addAtLeast solver [-x2, -x5, -x8, -x11] 3 -- C4
addAtLeast solver [-x1, -x4, -x7, -x10] 3 -- C5
replicateM 3 (varBumpActivity solver x3)
setVarPolarity solver x3 False
replicateM 2 (varBumpActivity solver x6)
setVarPolarity solver x6 False
replicateM 1 (varBumpActivity solver x9)
setVarPolarity solver x9 False
setVarPolarity solver x1 True
setLearningStrategy solver LearningHybrid
ret <- solve solver
ret @?= True
-- from "Pueblo: A Hybrid Pseudo-Boolean SAT Solver"
-- clauseがunitになるレベルで、PB制約が違反状態のままという例。
-- さらに、学習したPB制約はunitにはならない。
case_hybridLearning_2 :: IO ()
case_hybridLearning_2 = do
solver <- newSolver
[x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12] <- replicateM 12 (newVar solver)
addClause solver [x11, x10, x9] -- C1
addClause solver [x8, x7, x6] -- C2
addClause solver [x5, x4, x3] -- C3
addAtLeast solver [-x2, -x5, -x8, -x11] 3 -- C4
addAtLeast solver [-x1, -x4, -x7, -x10] 3 -- C5
addClause solver [x12, -x3]
addClause solver [x12, -x6]
addClause solver [x12, -x9]
varBumpActivity solver x12
setVarPolarity solver x12 False
setLearningStrategy solver LearningHybrid
ret <- solve solver
ret @?= True
-- regression test for the bug triggered by normalized-blast-floppy1-8.ucl.opb.bz2
case_addPBAtLeast_regression :: IO ()
case_addPBAtLeast_regression = do
solver <- newSolver
[x1,x2,x3,x4] <- replicateM 4 (newVar solver)
addClause solver [-x1]
addClause solver [-x2, -x3]
addClause solver [-x2, -x4]
addPBAtLeast solver [(1,x1),(2,x2),(1,x3),(1,x4)] 3
ret <- solve solver
ret @?= False
------------------------------------------------------------------------
case_addFormula = do
solver <- newSolver
enc <- Tseitin.newEncoder solver
[x1,x2,x3,x4,x5] <- replicateM 5 $ liftM Atom $ newVar solver
Tseitin.addFormula enc $ orB [x1 .=>. x3 .&&. x4, x2 .=>. x3 .&&. x5]
-- x6 = x3 ∧ x4
-- x7 = x3 ∧ x5
Tseitin.addFormula enc $ x1 .||. x2
Tseitin.addFormula enc $ x4 .=>. notB x5
ret <- solve solver
ret @?= True
Tseitin.addFormula enc $ x2 .<=>. x4
ret <- solve solver
ret @?= True
Tseitin.addFormula enc $ x1 .<=>. x5
ret <- solve solver
ret @?= True
Tseitin.addFormula enc $ notB x1 .=>. x3 .&&. x5
ret <- solve solver
ret @?= True
Tseitin.addFormula enc $ notB x2 .=>. x3 .&&. x4
ret <- solve solver
ret @?= False
case_addFormula_Peirces_Law = do
solver <- newSolver
enc <- Tseitin.newEncoder solver
[x1,x2] <- replicateM 2 $ liftM Atom $ newVar solver
Tseitin.addFormula enc $ notB $ ((x1 .=>. x2) .=>. x1) .=>. x1
ret <- solve solver
ret @?= False
case_encodeConj = do
solver <- newSolver
enc <- Tseitin.newEncoder solver
x1 <- newVar solver
x2 <- newVar solver
x3 <- Tseitin.encodeConj enc [x1,x2]
ret <- solveWith solver [x3]
ret @?= True
m <- getModel solver
evalLit m x1 @?= True
evalLit m x2 @?= True
evalLit m x3 @?= True
ret <- solveWith solver [-x3]
ret @?= True
m <- getModel solver
(evalLit m x1 && evalLit m x2) @?= False
evalLit m x3 @?= False
case_encodeDisj = do
solver <- newSolver
enc <- Tseitin.newEncoder solver
x1 <- newVar solver
x2 <- newVar solver
x3 <- Tseitin.encodeDisj enc [x1,x2]
ret <- solveWith solver [x3]
ret @?= True
m <- getModel solver
(evalLit m x1 || evalLit m x2) @?= True
evalLit m x3 @?= True
ret <- solveWith solver [-x3]
ret @?= True
m <- getModel solver
evalLit m x1 @?= False
evalLit m x2 @?= False
evalLit m x3 @?= False
case_evalFormula = do
solver <- newSolver
xs <- newVars solver 5
let f = (x1 .=>. x3 .&&. x4) .||. (x2 .=>. x3 .&&. x5)
where
[x1,x2,x3,x4,x5] = map Atom xs
g m = (not x1 || (x3 && x4)) || (not x2 || (x3 && x5))
where
[x1,x2,x3,x4,x5] = elems m
let ms :: [Model]
ms = liftM (array (1,5)) $ sequence [[(x,val) | val <- [False,True]] | x <- xs]
forM_ ms $ \m -> do
Tseitin.evalFormula m f @?= g m
------------------------------------------------------------------------
case_MUS = do
solver <- newSolver
[x1,x2,x3] <- newVars solver 3
sels@[y1,y2,y3,y4,y5,y6] <- newVars solver 6
addClause solver [-y1, x1]
addClause solver [-y2, -x1]
addClause solver [-y3, -x1, x2]
addClause solver [-y4, -x2]
addClause solver [-y5, -x1, x3]
addClause solver [-y6, -x3]
ret <- solveWith solver sels
ret @?= False
actual <- MUS.findMUSAssumptions solver MUS.defaultOptions
let actual' = IntSet.map (\x -> x-3) actual
expected = map IntSet.fromList [[1, 2], [1, 3, 4], [1, 5, 6]]
actual' `elem` expected @?= True
------------------------------------------------------------------------
{-
c http://sun.iwu.edu/~mliffito/publications/jar_liffiton_CAMUS.pdf
c φ= (x1) ∧ (¬x1) ∧ (¬x1∨x2) ∧ (¬x2) ∧ (¬x1∨x3) ∧ (¬x3)
c MUSes(φ) = {{C1, C2}, {C1, C3, C4}, {C1, C5, C6}}
c MCSes(φ) = {{C1}, {C2, C3, C5}, {C2, C3, C6}, {C2, C4, C5}, {C2, C4, C6}}
p cnf 3 6
1 0
-1 0
-1 2 0
-2 0
-1 3 0
-3 0
-}
case_camus_allMCSAssumptions = do
solver <- newSolver
[x1,x2,x3] <- newVars solver 3
sels@[y1,y2,y3,y4,y5,y6] <- newVars solver 6
addClause solver [-y1, x1]
addClause solver [-y2, -x1]
addClause solver [-y3, -x1, x2]
addClause solver [-y4, -x2]
addClause solver [-y5, -x1, x3]
addClause solver [-y6, -x3]
actual <- CAMUS.allMCSAssumptions solver sels CAMUS.defaultOptions
let actual' = Set.fromList actual
expected = map (IntSet.fromList . map (+3)) [[1], [2,3,5], [2,3,6], [2,4,5], [2,4,6]]
expected' = Set.fromList expected
actual' @?= expected'
case_DAA_allMCSAssumptions = do
solver <- newSolver
[x1,x2,x3] <- newVars solver 3
sels@[y1,y2,y3,y4,y5,y6] <- newVars solver 6
addClause solver [-y1, x1]
addClause solver [-y2, -x1]
addClause solver [-y3, -x1, x2]
addClause solver [-y4, -x2]
addClause solver [-y5, -x1, x3]
addClause solver [-y6, -x3]
actual <- DAA.allMCSAssumptions solver sels DAA.defaultOptions
let actual' = Set.fromList $ actual
expected = map (IntSet.fromList . map (+3)) [[1], [2,3,5], [2,3,6], [2,4,5], [2,4,6]]
expected' = Set.fromList $ expected
actual' @?= expected'
case_camus_allMUSAssumptions = do
solver <- newSolver
[x1,x2,x3] <- newVars solver 3
sels@[y1,y2,y3,y4,y5,y6] <- newVars solver 6
addClause solver [-y1, x1]
addClause solver [-y2, -x1]
addClause solver [-y3, -x1, x2]
addClause solver [-y4, -x2]
addClause solver [-y5, -x1, x3]
addClause solver [-y6, -x3]
actual <- CAMUS.allMUSAssumptions solver sels CAMUS.defaultOptions
let actual' = Set.fromList $ actual
expected = map (IntSet.fromList . map (+3)) [[1,2], [1,3,4], [1,5,6]]
expected' = Set.fromList $ expected
actual' @?= expected'
case_DAA_allMUSAssumptions = do
solver <- newSolver
[x1,x2,x3] <- newVars solver 3
sels@[y1,y2,y3,y4,y5,y6] <- newVars solver 6
addClause solver [-y1, x1]
addClause solver [-y2, -x1]
addClause solver [-y3, -x1, x2]
addClause solver [-y4, -x2]
addClause solver [-y5, -x1, x3]
addClause solver [-y6, -x3]
actual <- DAA.allMUSAssumptions solver sels DAA.defaultOptions
let actual' = Set.fromList $ actual
expected = map (IntSet.fromList . map (+3)) [[1,2], [1,3,4], [1,5,6]]
expected' = Set.fromList $ expected
actual' @?= expected'
{-
Boosting a Complete Technique to Find MSS and MUS thanks to a Local Search Oracle
http://www.cril.univ-artois.fr/~piette/IJCAI07_HYCAM.pdf
Example 3.
C0 : (d)
C1 : (b ∨ c)
C2 : (a ∨ b)
C3 : (a ∨ ¬c)
C4 : (¬b ∨ ¬e)
C5 : (¬a ∨ ¬b)
C6 : (a ∨ e)
C7 : (¬a ∨ ¬e)
C8 : (b ∨ e)
C9 : (¬a ∨ b ∨ ¬c)
C10 : (¬a ∨ b ∨ ¬d)
C11 : (a ∨ ¬b ∨ c)
C12 : (a ∨ ¬b ∨ ¬d)
-}
case_camus_allMUSAssumptions_2 = do
solver <- newSolver
[a,b,c,d,e] <- newVars solver 5
sels@[y0,y1,y2,y3,y4,y5,y6,y7,y8,y9,y10,y11,y12] <- newVars solver 13
addClause solver [-y0, d]
addClause solver [-y1, b, c]
addClause solver [-y2, a, b]
addClause solver [-y3, a, -c]
addClause solver [-y4, -b, -e]
addClause solver [-y5, -a, -b]
addClause solver [-y6, a, e]
addClause solver [-y7, -a, -e]
addClause solver [-y8, b, e]
addClause solver [-y9, -a, b, -c]
addClause solver [-y10, -a, b, -d]
addClause solver [-y11, a, -b, c]
addClause solver [-y12, a, -b, -d]
-- Only three of the MUSes (marked with asterisks) are on the paper.
let cores =
[ [y0,y1,y2,y5,y9,y12]
, [y0,y1,y3,y4,y5,y6,y10]
, [y0,y1,y3,y5,y7,y8,y12]
, [y0,y1,y3,y5,y9,y12]
, [y0,y1,y3,y5,y10,y11]
, [y0,y1,y3,y5,y10,y12]
, [y0,y2,y3,y5,y10,y11]
, [y0,y2,y4,y5,y6,y10]
, [y0,y2,y5,y7,y8,y12]
, [y0,y2,y5,y10,y12] -- (*)
, [y1,y2,y4,y5,y6,y9]
, [y1,y3,y4,y5,y6,y7,y8]
, [y1,y3,y4,y5,y6,y9]
, [y1,y3,y5,y7,y8,y11]
, [y1,y3,y5,y9,y11] -- (*)
, [y2,y3,y5,y7,y8,y11]
, [y2,y4,y5,y6,y7,y8] -- (*)
]
let remove1 :: [a] -> [[a]]
remove1 [] = []
remove1 (x:xs) = xs : [x : ys | ys <- remove1 xs]
forM_ cores $ \core -> do
ret <- solveWith solver core
assertBool (show core ++ " should be a core") (not ret)
forM (remove1 core) $ \xs -> do
ret <- solveWith solver xs
assertBool (show core ++ " should be satisfiable") ret
actual <- CAMUS.allMUSAssumptions solver sels CAMUS.defaultOptions
let actual' = Set.fromList actual
expected' = Set.fromList $ map IntSet.fromList $ cores
actual' @?= expected'
case_HYCAM_allMUSAssumptions = do
solver <- newSolver
[a,b,c,d,e] <- newVars solver 5
sels@[y0,y1,y2,y3,y4,y5,y6,y7,y8,y9,y10,y11,y12] <- newVars solver 13
addClause solver [-y0, d]
addClause solver [-y1, b, c]
addClause solver [-y2, a, b]
addClause solver [-y3, a, -c]
addClause solver [-y4, -b, -e]
addClause solver [-y5, -a, -b]
addClause solver [-y6, a, e]
addClause solver [-y7, -a, -e]
addClause solver [-y8, b, e]
addClause solver [-y9, -a, b, -c]
addClause solver [-y10, -a, b, -d]
addClause solver [-y11, a, -b, c]
addClause solver [-y12, a, -b, -d]
-- Only three of the MUSes (marked with asterisks) are on the paper.
let cores =
[ [y0,y1,y2,y5,y9,y12]
, [y0,y1,y3,y4,y5,y6,y10]
, [y0,y1,y3,y5,y7,y8,y12]
, [y0,y1,y3,y5,y9,y12]
, [y0,y1,y3,y5,y10,y11]
, [y0,y1,y3,y5,y10,y12]
, [y0,y2,y3,y5,y10,y11]
, [y0,y2,y4,y5,y6,y10]
, [y0,y2,y5,y7,y8,y12]
, [y0,y2,y5,y10,y12] -- (*)
, [y1,y2,y4,y5,y6,y9]
, [y1,y3,y4,y5,y6,y7,y8]
, [y1,y3,y4,y5,y6,y9]
, [y1,y3,y5,y7,y8,y11]
, [y1,y3,y5,y9,y11] -- (*)
, [y2,y3,y5,y7,y8,y11]
, [y2,y4,y5,y6,y7,y8] -- (*)
]
mcses =
[ [y0,y1,y7]
, [y0,y1,y8]
, [y0,y3,y4]
, [y0,y3,y6]
, [y0,y4,y11]
, [y0,y6,y11]
, [y0,y7,y9]
, [y0,y8,y9]
, [y1,y2]
, [y1,y7,y10]
, [y1,y8,y10]
, [y2,y3]
, [y3,y4,y12]
, [y3,y6,y12]
, [y4,y11,y12]
, [y5]
, [y6,y11,y12]
, [y7,y9,y10]
, [y8,y9,y10]
]
-- HYCAM paper wrongly treated {C3,C8,C10} as a candidate MCS (CoMSS).
-- Its complement {C0,C1,C2,C4,C5,C6,C7,C9,C11,C12} is unsatisfiable
-- and hence not MSS.
ret <- solveWith solver [y0,y1,y2,y4,y5,y6,y7,y9,y11,y12]
assertBool "failed to prove the bug of HYCAM paper" (not ret)
let cand = map IntSet.fromList [[y5], [y3,y2], [y0,y1,y2]]
actual <- CAMUS.allMUSAssumptions solver sels CAMUS.defaultOptions{ CAMUS.optKnownCSes = cand }
let actual' = Set.fromList $ actual
expected' = Set.fromList $ map IntSet.fromList cores
actual' @?= expected'
case_DAA_allMUSAssumptions_2 = do
solver <- newSolver
[a,b,c,d,e] <- newVars solver 5
sels@[y0,y1,y2,y3,y4,y5,y6,y7,y8,y9,y10,y11,y12] <- newVars solver 13
addClause solver [-y0, d]
addClause solver [-y1, b, c]
addClause solver [-y2, a, b]
addClause solver [-y3, a, -c]
addClause solver [-y4, -b, -e]
addClause solver [-y5, -a, -b]
addClause solver [-y6, a, e]
addClause solver [-y7, -a, -e]
addClause solver [-y8, b, e]
addClause solver [-y9, -a, b, -c]
addClause solver [-y10, -a, b, -d]
addClause solver [-y11, a, -b, c]
addClause solver [-y12, a, -b, -d]
-- Only three of the MUSes (marked with asterisks) are on the paper.
let cores =
[ [y0,y1,y2,y5,y9,y12]
, [y0,y1,y3,y4,y5,y6,y10]
, [y0,y1,y3,y5,y7,y8,y12]
, [y0,y1,y3,y5,y9,y12]
, [y0,y1,y3,y5,y10,y11]
, [y0,y1,y3,y5,y10,y12]
, [y0,y2,y3,y5,y10,y11]
, [y0,y2,y4,y5,y6,y10]
, [y0,y2,y5,y7,y8,y12]
, [y0,y2,y5,y10,y12] -- (*)
, [y1,y2,y4,y5,y6,y9]
, [y1,y3,y4,y5,y6,y7,y8]
, [y1,y3,y4,y5,y6,y9]
, [y1,y3,y5,y7,y8,y11]
, [y1,y3,y5,y9,y11] -- (*)
, [y2,y3,y5,y7,y8,y11]
, [y2,y4,y5,y6,y7,y8] -- (*)
]
let remove1 :: [a] -> [[a]]
remove1 [] = []
remove1 (x:xs) = xs : [x : ys | ys <- remove1 xs]
forM_ cores $ \core -> do
ret <- solveWith solver core
assertBool (show core ++ " should be a core") (not ret)
forM (remove1 core) $ \xs -> do
ret <- solveWith solver xs
assertBool (show core ++ " should be satisfiable") ret
actual <- DAA.allMUSAssumptions solver sels DAA.defaultOptions
let actual' = Set.fromList actual
expected' = Set.fromList $ map IntSet.fromList cores
actual' @?= expected'
------------------------------------------------------------------------
-- Test harness
main :: IO ()
main = $(defaultMainGenerator)