module Data.Logic.ATP.FOL
( IsFirstOrder
, Interp
, holds
, holdsQuantified
, holdsAtom
, termval
, var
, fv, fva, fvt
, generalize
, subst, substq, asubst, tsubst, lsubst
, bool_interp
, mod_interp
, ApFormula, EqFormula
, testFOL
) where
import Data.Logic.ATP.Apply (ApAtom, HasApply(PredOf, TermOf, overterms, onterms), Predicate)
import Data.Logic.ATP.Equate ((.=.), EqAtom, foldEquate, HasEquate)
import Data.Logic.ATP.Formulas (fromBool, IsFormula(..))
import Data.Logic.ATP.Lib (setAny, tryApplyD, undefine, (|->))
import Data.Logic.ATP.Lit ((.~.), foldLiteral, JustLiteral)
import Data.Logic.ATP.Pretty (prettyShow)
import Data.Logic.ATP.Prop (BinOp(..), IsPropositional((.&.), (.|.), (.=>.), (.<=>.)))
import Data.Logic.ATP.Quantified (exists, foldQuantified, for_all, IsQuantified(VarOf), Quant((:!:), (:?:)), QFormula)
import Data.Logic.ATP.Term (FName, foldTerm, IsTerm(FunOf, TVarOf, vt, fApp), V, variant)
import Data.Map.Strict as Map (empty, fromList, insert, lookup, Map)
import Data.Maybe (fromMaybe)
import Data.Set as Set (difference, empty, fold, fromList, member, Set, singleton, union, unions)
import Data.String (IsString(fromString))
import Prelude hiding (pred)
import Test.HUnit
class (IsQuantified formula,
HasApply (AtomOf formula),
IsTerm (TermOf (AtomOf formula)),
VarOf formula ~ TVarOf (TermOf (AtomOf formula)))
=> IsFirstOrder formula
type ApFormula = QFormula V ApAtom
instance IsFirstOrder ApFormula
type EqFormula = QFormula V EqAtom
instance IsFirstOrder EqFormula
data Interp function predicate d
= Interp { domain :: [d]
, funcApply :: function -> [d] -> d
, predApply :: predicate -> [d] -> Bool
, eqApply :: d -> d -> Bool }
class FiniteInterpretation a function predicate v dom where
holds :: Interp function predicate dom -> Map v dom -> a -> Bool
holdsQuantified :: forall formula function predicate dom.
(IsQuantified formula,
FiniteInterpretation (AtomOf formula) function predicate (VarOf formula) dom,
FiniteInterpretation formula function predicate (VarOf formula) dom) =>
Interp function predicate dom -> Map (VarOf formula) dom -> formula -> Bool
holdsQuantified m v fm =
foldQuantified qu co ne tf at fm
where
qu (:!:) x p = and (map (\a -> holds m (Map.insert x a v) p) (domain m))
qu (:?:) x p = or (map (\a -> holds m (Map.insert x a v) p) (domain m))
ne p = not (holds m v p)
co p (:&:) q = (holds m v p) && (holds m v q)
co p (:|:) q = (holds m v p) || (holds m v q)
co p (:=>:) q = not (holds m v p) || (holds m v q)
co p (:<=>:) q = (holds m v p) == (holds m v q)
tf x = x
at = (holds m v :: AtomOf formula -> Bool)
holdsAtom :: (HasEquate atom, IsTerm term, Eq dom,
term ~ TermOf atom, v ~ TVarOf term, function ~ FunOf term, predicate ~ PredOf atom) =>
Interp function predicate dom -> Map v dom -> atom -> Bool
holdsAtom m v at = foldEquate (\t1 t2 -> eqApply m (termval m v t1) (termval m v t2))
(\r args -> predApply m r (map (termval m v) args)) at
termval :: (IsTerm term, v ~ TVarOf term, function ~ FunOf term) => Interp function predicate r -> Map v r -> term -> r
termval m v tm =
foldTerm (\x -> fromMaybe (error ("Undefined variable: " ++ show x)) (Map.lookup x v))
(\f args -> funcApply m f (map (termval m v) args)) tm
bool_interp :: Interp FName Predicate Bool
bool_interp =
Interp [False, True] func pred (==)
where
func f [] | f == fromString "False" = False
func f [] | f == fromString "True" = True
func f [x,y] | f == fromString "+" = x /= y
func f [x,y] | f == fromString "*" = x && y
func f _ = error ("bool_interp - uninterpreted function: " ++ show f)
pred p _ = error ("bool_interp - uninterpreted predicate: " ++ show p)
mod_interp :: Int -> Interp FName Predicate Int
mod_interp n =
Interp [0..(n1)] func pred (==)
where
func f [] | f == fromString "0" = 0
func f [] | f == fromString "1" = 1 `mod` n
func f [x,y] | f == fromString "+" = (x + y) `mod` n
func f [x,y] | f == fromString "*" = (x * y) `mod` n
func f _ = error ("mod_interp - uninterpreted function: " ++ show f)
pred p _ = error ("mod_interp - uninterpreted predicate: " ++ show p)
instance Eq dom => FiniteInterpretation EqFormula FName Predicate V dom where holds = holdsQuantified
instance Eq dom => FiniteInterpretation EqAtom FName Predicate V dom where holds = holdsAtom
test01 :: Test
test01 = TestCase $ assertEqual "holds bool test (p. 126)" expected input
where input = holds bool_interp (Map.empty :: Map V Bool) (for_all "x" ((vt "x") .=. (fApp "False" []) .|. (vt "x") .=. (fApp "True" [])) :: EqFormula)
expected = True
test02 :: Test
test02 = TestCase $ assertEqual "holds mod test 1 (p. 126)" expected input
where input = holds (mod_interp 2) (Map.empty :: Map V Int) (for_all "x" (vt "x" .=. (fApp "0" []) .|. vt "x" .=. (fApp "1" [])) :: EqFormula)
expected = True
test03 :: Test
test03 = TestCase $ assertEqual "holds mod test 2 (p. 126)" expected input
where input = holds (mod_interp 3) (Map.empty :: Map V Int) (for_all "x" (vt "x" .=. fApp "0" [] .|. vt "x" .=. fApp "1" []) :: EqFormula)
expected = False
test04 :: Test
test04 = TestCase $ assertEqual "holds mod test 3 (p. 126)" expected input
where input = filter (\ n -> holds (mod_interp n) (Map.empty :: Map V Int) fm) [1..45]
where fm = for_all "x" ((.~.) (vt "x" .=. fApp "0" []) .=>. exists "y" (fApp "*" [vt "x", vt "y"] .=. fApp "1" [])) :: EqFormula
expected = [1,2,3,5,7,11,13,17,19,23,29,31,37,41,43]
test05 :: Test
test05 = TestCase $ assertEqual "holds mod test 4 (p. 129)" expected input
where input = holds (mod_interp 3) (Map.empty :: Map V Int) ((for_all "x" (vt "x" .=. fApp "0" [])) .=>. fApp "1" [] .=. fApp "0" [] :: EqFormula)
expected = True
test06 :: Test
test06 = TestCase $ assertEqual "holds mod test 5 (p. 129)" expected input
where input = holds (mod_interp 3) (Map.empty :: Map V Int) (for_all "x" (vt "x" .=. fApp "0" [] .=>. fApp "1" [] .=. fApp "0" []) :: EqFormula)
expected = False
fv :: (IsFirstOrder formula, v ~ VarOf formula) => formula -> Set v
fv fm =
foldQuantified qu co ne tf at fm
where
qu _ x p = difference (fv p) (singleton x)
ne p = fv p
co p _ q = union (fv p) (fv q)
tf _ = Set.empty
at = fva
var :: (IsFormula formula, HasApply atom,
atom ~ AtomOf formula, term ~ TermOf atom, v ~ TVarOf term) =>
formula -> Set v
var fm = overatoms (\a s -> Set.union (fva a) s) fm mempty
fva :: (HasApply atom, IsTerm term, term ~ TermOf atom, v ~ TVarOf term) => atom -> Set v
fva = overterms (\t s -> Set.union (fvt t) s) mempty
fvt :: (IsTerm term, v ~ TVarOf term) => term -> Set v
fvt tm = foldTerm singleton (\_ args -> unions (map fvt args)) tm
generalize :: IsFirstOrder formula => formula -> formula
generalize fm = Set.fold for_all fm (fv fm)
test07 :: Test
test07 = TestCase $ assertEqual "variant 1 (p. 133)" expected input
where input = variant "x" (Set.fromList ["y", "z"]) :: V
expected = "x"
test08 :: Test
test08 = TestCase $ assertEqual "variant 2 (p. 133)" expected input
where input = variant "x" (Set.fromList ["x", "y"]) :: V
expected = "x'"
test09 :: Test
test09 = TestCase $ assertEqual "variant 3 (p. 133)" expected input
where input = variant "x" (Set.fromList ["x", "x'"]) :: V
expected = "x''"
subst :: (IsFirstOrder formula, term ~ TermOf (AtomOf formula), v ~ VarOf formula) => Map v term -> formula -> formula
subst subfn fm =
foldQuantified qu co ne tf at fm
where
qu (:!:) x p = substq subfn for_all x p
qu (:?:) x p = substq subfn exists x p
ne p = (.~.) (subst subfn p)
co p (:&:) q = (subst subfn p) .&. (subst subfn q)
co p (:|:) q = (subst subfn p) .|. (subst subfn q)
co p (:=>:) q = (subst subfn p) .=>. (subst subfn q)
co p (:<=>:) q = (subst subfn p) .<=>. (subst subfn q)
tf False = false
tf True = true
at = atomic . asubst subfn
tsubst :: (IsTerm term, v ~ TVarOf term) => Map v term -> term -> term
tsubst sfn tm =
foldTerm (\x -> fromMaybe tm (Map.lookup x sfn))
(\f args -> fApp f (map (tsubst sfn) args))
tm
lsubst :: (JustLiteral lit, HasApply atom, IsTerm term,
atom ~ AtomOf lit,
term ~ TermOf atom,
v ~ TVarOf term) =>
Map v term -> lit -> lit
lsubst subfn fm =
foldLiteral ne fromBool at fm
where
ne p = (.~.) (lsubst subfn p)
at = atomic . asubst subfn
asubst :: (HasApply atom, IsTerm term, term ~ TermOf atom, v ~ TVarOf term) => Map v term -> atom -> atom
asubst sfn a = onterms (tsubst sfn) a
substq :: (IsFirstOrder formula, v ~ VarOf formula, term ~ TermOf (AtomOf formula)) =>
Map v term -> (v -> formula -> formula) -> v -> formula -> formula
substq subfn qu x p =
let x' = if setAny (\y -> Set.member x (fvt(tryApplyD subfn y (vt y))))
(difference (fv p) (singleton x))
then variant x (fv (subst (undefine x subfn) p)) else x in
qu x' (subst ((x |-> vt x') subfn) p)
test10 :: Test
test10 =
let [x, x', y] = [vt "x", vt "x'", vt "y"]
fm = for_all "x" ((x .=. y)) :: EqFormula
expected = for_all "x'" (x' .=. x) :: EqFormula in
TestCase $ assertEqual ("subst (\"y\" |=> Var \"x\") " ++ prettyShow fm ++ " (p. 134)")
expected
(subst (Map.fromList [("y", x)]) fm)
test11 :: Test
test11 =
let [x, x', x'', y] = [vt "x", vt "x'", vt "x''", vt "y"]
fm = (for_all "x" (for_all "x'" ((x .=. y) .=>. (x .=. x')))) :: EqFormula
expected = for_all "x'" (for_all "x''" ((x' .=. x) .=>. ((x' .=. x'')))) :: EqFormula in
TestCase $ assertEqual ("subst (\"y\" |=> Var \"x\") " ++ prettyShow fm ++ " (p. 134)")
expected
(subst (Map.fromList [("y", x)]) fm)
testFOL :: Test
testFOL = TestLabel "FOL" (TestList [test01, test02, test03, test04,
test05, test06, test07, test08, test09,
test10, test11])