---------------------------------------------------- -- Propositional formulae, satisfiable, tautologous. -- A test module for SmallCheck. -- Colin Runciman, August 2006. ---------------------------------------------------- module PropLogic where import Test.SmallCheck import Test.SmallCheck.Series import List (nub) data Prop = Var Name | Not Prop | And Prop Prop | Or Prop Prop | Imp Prop Prop instance Show Prop where show p = case p of Var n -> show n Not q -> "~"++show' q And q r -> show' q++"&"++show' r Or q r -> show' q++"|"++show' r Imp q r -> show' q++"=>"++show' r where show' x = if priority p > priority x then "("++show x++")" else show x priority (Var _) = 5 priority (Not _) = 4 priority (And _ _) = 3 priority (Or _ _) = 2 priority (Imp _ _) = 1 data Name = P | Q | R deriving (Eq,Show) type Env = Name -> Bool eval :: Prop -> Env -> Bool eval (Var v) env = env v eval (Not p) env = not (eval p env) eval (And p q) env = eval p env && eval q env eval (Or p q) env = eval p env || eval q env eval (Imp p q) env = eval p env <= eval q env envsFor :: Prop -> [Env] envsFor p = foldr bind [const False] (nub (varsOf p)) where bind v es = concat [ [\x -> x==v || e x, e] | e <- es ] varsOf :: Prop -> [Name] varsOf (Var v) = [v] varsOf (Not p) = varsOf p varsOf (And p q) = varsOf p ++ varsOf q varsOf (Or p q) = varsOf p ++ varsOf q varsOf (Imp p q) = varsOf p ++ varsOf q tautologous :: Prop -> Bool tautologous p = all (eval p) (envsFor p) satisfiable :: Prop -> Bool satisfiable p = any (eval p) (envsFor p) instance Serial Name where series = cons0 P \/ cons0 Q \/ cons0 R coseries rs d = [ \n -> case n of P -> x ; Q -> y ; R -> z | x <- alts0 rs d, y <- alts0 rs d, z <- alts0 rs d ] instance Serial Prop where series = cons1 Var \/ cons1 Not \/ cons2 And \/ cons2 Or \/ cons2 Imp ---------------------- --------------------- prop_taut1 :: Prop -> Property prop_taut1 p = tautologous p ==> \e -> eval p e prop_taut2 :: Prop -> Property prop_taut2 p = not (tautologous p) ==> exists (\e -> not $ eval p e) prop_sat1 :: Prop -> Env -> Property prop_sat1 p e = eval p e ==> satisfiable p prop_sat2 :: Prop -> Property prop_sat2 p = satisfiable p ==> exists (\e -> eval p e) prop_tautSat1 :: Prop -> Property prop_tautSat1 p = not (tautologous p) ==> satisfiable (Not p) prop_tautSat2 :: Prop -> Property prop_tautSat2 p = not (satisfiable p) ==> tautologous (Not p) main :: IO () main = do test1 "\\p -> tautologous p ==> \\e -> eval p e ?" prop_taut1 test1 "\\p -> not (tautologous p) ==>\n\ \ exists (\\e -> not $ eval p e) ?" prop_taut2 test1 "\\p e -> eval p e ==> satisfiable p ?" prop_sat1 test1 "\\p -> satisfiable p ==> exists (\\e -> eval p e) ?" prop_sat2 test1 "\\p -> not (tautologous p) ==> satisfiable (Not p) ?" prop_tautSat1 test1 "\\p -> not (satisfiable p) ==> tautologous (Not p) ?" prop_tautSat2 test1 :: Testable a => String -> a -> IO () test1 s t = do rule putStrLn s rule smallCheck 3 t where rule = putStrLn "----------------------------------------------------"