toysolver-0.6.0: test/Test/SAT/Types.hs
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, FlexibleContexts #-}
module Test.SAT.Types (satTypesTestGroup) where
import Control.Monad
import Data.Array.IArray
import Data.List
import Test.Tasty
import Test.Tasty.QuickCheck
import Test.Tasty.HUnit
import Test.Tasty.TH
import qualified ToySolver.SAT.Types as SAT
import Test.SAT.Utils
------------------------------------------------------------------------
-- -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_1 :: Assertion
case_normalizePBLinSum_1 = do
sort e @?= sort [(7,x1),(10,-x2)]
c @?= -4
where
x1 = 1
x2 = 2
(e,c) = SAT.normalizePBLinSum ([(-4,-x1),(3,x1),(10,-x2)], 0)
prop_normalizePBLinSum :: Property
prop_normalizePBLinSum = forAll g $ \(nv, (s,n)) ->
let (s2,n2) = SAT.normalizePBLinSum (s,n)
in flip all (allAssignments nv) $ \m ->
SAT.evalPBLinSum m s + n == SAT.evalPBLinSum m s2 + n2
where
g :: Gen (Int, (SAT.PBLinSum, Integer))
g = do
nv <- choose (0, 10)
s <- forM [1..nv] $ \x -> do
c <- arbitrary
p <- arbitrary
return (c, SAT.literal x p)
n <- arbitrary
return (nv, (s,n))
-- -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_1 :: Assertion
case_normalizePBLinAtLeast_1 = (sort lhs, rhs) @?= (sort [(1,x1),(1,-x2)], 1)
where
x1 = 1
x2 = 2
(lhs,rhs) = SAT.normalizePBLinAtLeast ([(-4,-x1),(3,x1),(10,-x2)], 3)
prop_normalizePBLinAtLeast :: Property
prop_normalizePBLinAtLeast = forAll g $ \(nv, c) ->
let c2 = SAT.normalizePBLinAtLeast c
in flip all (allAssignments nv) $ \m ->
SAT.evalPBLinAtLeast m c == SAT.evalPBLinAtLeast m c2
where
g :: Gen (Int, SAT.PBLinAtLeast)
g = do
nv <- choose (0, 10)
lhs <- forM [1..nv] $ \x -> do
c <- arbitrary
p <- arbitrary
return (c, SAT.literal x p)
rhs <- arbitrary
return (nv, (lhs,rhs))
case_normalizePBLinExactly_1 :: Assertion
case_normalizePBLinExactly_1 = (sort lhs, rhs) @?= ([], 1)
where
x1 = 1
x2 = 2
(lhs,rhs) = SAT.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) = SAT.normalizePBLinExactly ([(2,x1),(2,x2),(2,x3)], 3)
prop_normalizePBLinExactly :: Property
prop_normalizePBLinExactly = forAll g $ \(nv, c) ->
let c2 = SAT.normalizePBLinExactly c
in flip all (allAssignments nv) $ \m ->
SAT.evalPBLinExactly m c == SAT.evalPBLinExactly m c2
where
g :: Gen (Int, SAT.PBLinExactly)
g = do
nv <- choose (0, 10)
lhs <- forM [1..nv] $ \x -> do
c <- arbitrary
p <- arbitrary
return (c, SAT.literal x p)
rhs <- arbitrary
return (nv, (lhs,rhs))
prop_cutResolve :: Property
prop_cutResolve =
forAll (choose (1, 10)) $ \nv ->
forAll (g nv True) $ \c1 ->
forAll (g nv False) $ \c2 ->
let c3 = SAT.cutResolve c1 c2 1
in flip all (allAssignments nv) $ \m ->
not (SAT.evalPBLinExactly m c1 && SAT.evalPBLinExactly m c2) || SAT.evalPBLinExactly m c3
where
g :: Int -> Bool -> Gen SAT.PBLinExactly
g nv b = do
lhs <- forM [1..nv] $ \x -> do
if x==1 then do
c <- liftM ((1+) . abs) arbitrary
return (c, SAT.literal x b)
else do
c <- arbitrary
p <- arbitrary
return (c, SAT.literal x p)
rhs <- arbitrary
return (lhs, rhs)
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) = SAT.cutResolve pb1 pb2 x1
case_cutResolve_2 :: Assertion
case_cutResolve_2 = (sort lhs, rhs) @?= (sort lhs2, rhs2)
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) = SAT.cutResolve pb1 pb2 x3
(lhs2,rhs2) = ([(2,x1),(1,-x2),(1,x4)],2) -- ([(3,x1),(2,-x2),(2,x4)], 3)
case_cardinalityReduction :: Assertion
case_cardinalityReduction = (sort lhs, rhs) @?= ([1,2,3,4,5],4)
where
(lhs, rhs) = SAT.cardinalityReduction ([(6,1),(5,2),(4,3),(3,4),(2,5),(1,6)], 17)
prop_pbLinUpperBound :: Property
prop_pbLinUpperBound =
forAll (choose (0,10)) $ \nv ->
forAll (arbitraryPBLinSum nv) $ \s ->
forAll (arbitraryAssignment nv) $ \m ->
let ub = SAT.pbLinUpperBound s
in counterexample (show ub) $ SAT.evalPBLinSum m s <= ub
prop_pbLinLowerBound :: Property
prop_pbLinLowerBound =
forAll (choose (0,10)) $ \nv ->
forAll (arbitraryPBLinSum nv) $ \s ->
forAll (arbitraryAssignment nv) $ \m ->
let lb = SAT.pbLinLowerBound s
in counterexample (show lb) $ lb <= SAT.evalPBLinSum m s
case_pbLinSubsume_clause :: Assertion
case_pbLinSubsume_clause = SAT.pbLinSubsume ([(1,1),(1,-3)],1) ([(1,1),(1,2),(1,-3),(1,4)],1) @?= True
case_pbLinSubsume_1 :: Assertion
case_pbLinSubsume_1 = SAT.pbLinSubsume ([(1,1),(1,2),(1,-3)],2) ([(1,1),(2,2),(1,-3),(1,4)],1) @?= True
case_pbLinSubsume_2 :: Assertion
case_pbLinSubsume_2 = SAT.pbLinSubsume ([(1,1),(1,2),(1,-3)],2) ([(1,1),(2,2),(1,-3),(1,4)],3) @?= False
prop_removeNegationFromPBSum :: Property
prop_removeNegationFromPBSum =
forAll (choose (0,10)) $ \nv ->
forAll (arbitraryPBSum nv) $ \s ->
let s' = SAT.removeNegationFromPBSum s
in counterexample (show s') $
forAll (arbitraryAssignment nv) $ \m -> SAT.evalPBSum m s === SAT.evalPBSum m s'
prop_pbUpperBound :: Property
prop_pbUpperBound =
forAll (choose (0,10)) $ \nv ->
forAll (arbitraryPBSum nv) $ \s ->
forAll (arbitraryAssignment nv) $ \m ->
let ub = SAT.pbUpperBound s
in counterexample (show ub) $ SAT.evalPBSum m s <= ub
prop_pbLowerBound :: Property
prop_pbLowerBound =
forAll (choose (0,10)) $ \nv ->
forAll (arbitraryPBSum nv) $ \s ->
forAll (arbitraryAssignment nv) $ \m ->
let lb = SAT.pbLowerBound s
in counterexample (show lb) $ lb <= SAT.evalPBSum m s
------------------------------------------------------------------------
case_normalizeXORClause_False :: Assertion
case_normalizeXORClause_False =
SAT.normalizeXORClause ([],True) @?= ([],True)
case_normalizeXORClause_True :: Assertion
case_normalizeXORClause_True =
SAT.normalizeXORClause ([],False) @?= ([],False)
-- x ⊕ y ⊕ x = y
case_normalizeXORClause_case1 :: Assertion
case_normalizeXORClause_case1 =
SAT.normalizeXORClause ([1,2,1],True) @?= ([2],True)
-- x ⊕ ¬x = x ⊕ x ⊕ 1 = 1
case_normalizeXORClause_case2 :: Assertion
case_normalizeXORClause_case2 =
SAT.normalizeXORClause ([1,-1],True) @?= ([],False)
prop_normalizeXORClause :: Property
prop_normalizeXORClause = forAll g $ \(nv, c) ->
let c2 = SAT.normalizeXORClause c
in flip all (allAssignments nv) $ \m ->
SAT.evalXORClause m c == SAT.evalXORClause m c2
where
g :: Gen (Int, SAT.XORClause)
g = do
nv <- choose (0, 10)
len <- choose (0, nv)
lhs <- replicateM len $ choose (-nv, nv) `suchThat` (/= 0)
rhs <- arbitrary
return (nv, (lhs,rhs))
case_evalXORClause_case1 :: Assertion
case_evalXORClause_case1 =
SAT.evalXORClause (array (1,2) [(1,True),(2,True)] :: Array Int Bool) ([1,2], True) @?= False
case_evalXORClause_case2 :: Assertion
case_evalXORClause_case2 =
SAT.evalXORClause (array (1,2) [(1,False),(2,True)] :: Array Int Bool) ([1,2], True) @?= True
------------------------------------------------------------------------
satTypesTestGroup :: TestTree
satTypesTestGroup = $(testGroupGenerator)