module Logic where
import Control.Monad ( liftM
, liftM2)
import Data.List ( union
, subsequences)
import Test.QuickCheck ( Arbitrary
, arbitrary
, oneof
, elements
, sized
, quickCheck)
import qualified Data.Set as S
type VarProp = String
data FProp = T
| F
| Atom VarProp
| Neg FProp
| Conj FProp FProp
| Disj FProp FProp
| Impl FProp FProp
| Equi FProp FProp
deriving (Eq,Ord)
instance Show FProp where
show (T) = "⊤"
show (F) = "⊥"
show (Atom x) = x
show (Neg x) = "¬" ++ show x
show (Conj x y) = "(" ++ show x ++ " ∧ " ++ show y ++ ")"
show (Disj x y) = "(" ++ show x ++ " ∨ " ++ show y ++ ")"
show (Impl x y) = "(" ++ show x ++ " → " ++ show y ++ ")"
show (Equi x y) = "(" ++ show x ++ " ↔ " ++ show y ++ ")"
p, q, r :: FProp
p = Atom "p"
q = Atom "q"
r = Atom "r"
no :: FProp -> FProp
no = Neg
(∨) :: FProp -> FProp -> FProp
(∨) = Disj
infixr 5 ∨
(∧) :: FProp -> FProp -> FProp
(∧) = Conj
infixr 4 ∧
(→) :: FProp -> FProp -> FProp
(→) = Impl
infixr 3 →
(↔) :: FProp -> FProp -> FProp
(↔) = Equi
infixr 2 ↔
instance Arbitrary FProp where
arbitrary = sized prop
where
prop n | n <= 0 = atom
| otherwise = oneof [
atom
, liftM Neg subform
, liftM2 Conj subform subform
, liftM2 Disj subform subform
, liftM2 Impl subform subform
, liftM2 Equi subform' subform' ]
where
atom = oneof [liftM Atom (elements ["p","q","r","s"]),
elements [F,T]]
subform = prop ( n `div` 2)
subform' = prop ( n `div` 4)
substitute :: FProp -> VarProp -> FProp -> FProp
substitute T _ _ = T
substitute F _ _ = F
substitute (Atom f) p g | f == p = g
| otherwise = Atom f
substitute (Neg f) p g = Neg (substitute f p g)
substitute (Conj f1 f2) p g = Conj (substitute f1 p g) (substitute f2 p g)
substitute (Disj f1 f2) p g = Disj (substitute f1 p g) (substitute f2 p g)
substitute (Impl f1 f2) p g = Impl (substitute f1 p g) (substitute f2 p g)
substitute (Equi f1 f2) p g = Equi (substitute f1 p g) (substitute f2 p g)
type Interpretation = [FProp]
signify :: FProp -> Interpretation -> Bool
signify T _ = True
signify F _ = False
signify (Atom f) i = (Atom f) `elem` i
signify (Neg f) i = not (signify f i)
signify (Conj f g) i = (signify f i) && (signify g i)
signify (Disj f g) i = (signify f i) || (signify g i)
signify (Impl f g) i = signify (Disj (Neg f) g) i
signify (Equi f g) i = signify (Conj (Impl f g) (Impl g f)) i
isModelForm :: Interpretation -> FProp -> Bool
isModelForm i f = signify f i
propSymbolsForm :: FProp -> [FProp]
propSymbolsForm T = []
propSymbolsForm F = []
propSymbolsForm (Atom f) = [(Atom f)]
propSymbolsForm (Neg f) = propSymbolsForm f
propSymbolsForm (Conj f g) = propSymbolsForm f `union` propSymbolsForm g
propSymbolsForm (Disj f g) = propSymbolsForm f `union` propSymbolsForm g
propSymbolsForm (Impl f g) = propSymbolsForm f `union` propSymbolsForm g
propSymbolsForm (Equi f g) = propSymbolsForm f `union` propSymbolsForm g
interpretationsForm :: FProp -> [Interpretation]
interpretationsForm = subsequences . propSymbolsForm
modelsForm :: FProp -> [Interpretation]
modelsForm f = [i | i <- interpretationsForm f, isModelForm i f]
isValid :: FProp -> Bool
isValid f = modelsForm f == interpretationsForm f
isUnsatisfiable :: FProp -> Bool
isUnsatisfiable = null . modelsForm
isSatisfiable :: FProp -> Bool
isSatisfiable = not . null . modelsForm
type KB = S.Set FProp
propSymbolsKB :: KB -> [FProp]
propSymbolsKB = foldl (\acc f -> union acc (propSymbolsForm f)) []
interpretationsKB :: KB -> [Interpretation]
interpretationsKB = subsequences . propSymbolsKB
isModelKB :: Interpretation -> KB -> Bool
isModelKB i = all (isModelForm i)
modelsKB :: KB -> [Interpretation]
modelsKB s = [i | i <- interpretationsKB s, isModelKB i s]
isConsistent :: KB -> Bool
isConsistent = not . null . modelsKB
isInconsistent :: KB -> Bool
isInconsistent = null . modelsKB
isConsequence :: KB -> FProp -> Bool
isConsequence k f =
null [i | i <- interpretationsKB (S.insert f k)
, isModelKB i k
, not (isModelForm i f)]
prop_isValid :: FProp -> Bool
prop_isValid f =
isValid f == isConsequence S.empty f
prop_isConsequence :: KB -> FProp -> Bool
prop_isConsequence k f =
isConsequence k f == isInconsistent (S.insert (Neg f) k)
isConsequenceKB :: KB -> KB -> Bool
isConsequenceKB k = all (isConsequence k)
equivalent :: FProp -> FProp -> Bool
equivalent f g = isValid (f ↔ g)
equivalentKB :: KB -> KB -> Bool
equivalentKB k k' = isConsequenceKB k k' && isConsequenceKB k' k
prop_equivalent :: FProp -> FProp -> Bool
prop_equivalent f g =
equivalent f g == equivalentKB (S.singleton f) (S.singleton g)