{-# LANGUAGE DeriveDataTypeable, FlexibleContexts, Rank2Types, GADTs, TypeOperators, ScopedTypeVariables, BangPatterns, PatternGuards, DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
module Jukebox.Form where
import Prelude hiding (sequence, mapM)
import qualified Data.Set as Set
import Data.Set(Set)
import qualified Data.Map.Strict as Map
import Data.Map(Map)
import Data.Ord
import Jukebox.Name
import Control.Monad
import Control.Monad.Trans.Class
import Control.Monad.Trans.State.Strict
import Data.List
import Jukebox.Utils
import Data.Typeable(Typeable)
import Data.Monoid
import qualified Data.DList as DList
import Data.DList(DList)
import Data.MemoUgly
debugging :: Bool
debugging = False
data Type =
O
| Type { tname :: !Name }
deriving Typeable
indType, intType, ratType, realType :: Type
indType = Type (name "$i")
intType = Type (name "$int")
ratType = Type (name "$rat")
realType = Type (name "$real")
data FunType = FunType { args :: [Type], res :: Type } deriving (Eq, Ord, Typeable)
typeMaybeName :: Type -> Maybe Name
typeMaybeName O = Nothing
typeMaybeName Type{tname = t} = Just t
instance Eq Type where
t1 == t2 = typeMaybeName t1 == typeMaybeName t2
instance Ord Type where
compare = comparing typeMaybeName
instance Named Type where
name O = name "$o"
name Type{tname = t} = t
class Typed a where
typ :: a -> Type
instance Typed Type where
typ = id
instance Typed FunType where
typ = res
instance Typed b => Typed (a ::: b) where
typ (_ ::: t) = typ t
type Variable = Name ::: Type
type Function = Name ::: FunType
data Term = Var Variable | Function :@: [Term] deriving (Eq, Ord)
instance Named Term where
name (Var x) = name x
name (f :@: _) = name f
instance Typed Term where
typ (Var x) = typ x
typ (f :@: _) = typ f
newSymbol :: Named a => a -> b -> NameM (Name ::: b)
newSymbol x ty = fmap (::: ty) (newName x)
newFunction :: Named a => a -> [Type] -> Type -> NameM Function
newFunction x args res = newSymbol x (FunType args res)
newType :: Named a => a -> NameM Type
newType x = Type <$> newName x
funArgs :: Function -> [Type]
funArgs (_ ::: ty) = args ty
arity :: Function -> Int
arity = length . funArgs
size :: Term -> Int
size Var{} = 1
size (_f :@: xs) = 1 + sum (map size xs)
infix 8 :=:
data Atomic = Term :=: Term | Tru Term
normAtomic :: Atomic -> Either (Term, Term) Term
normAtomic (t1 :=: t2) | t1 > t2 = Left (t2, t1)
| otherwise = Left (t1, t2)
normAtomic (Tru p) = Right p
instance Eq Atomic where
t1 == t2 = normAtomic t1 == normAtomic t2
instance Ord Atomic where
compare = comparing normAtomic
data Signed a = Pos a | Neg a
deriving (Show, Eq, Ord, Functor, Foldable, Traversable)
type Literal = Signed Atomic
neg :: Signed a -> Signed a
neg (Pos x) = Neg x
neg (Neg x) = Pos x
the :: Signed a -> a
the (Pos x) = x
the (Neg x) = x
pos :: Signed a -> Bool
pos (Pos _) = True
pos (Neg _) = False
signForm :: Signed a -> Form -> Form
signForm (Pos _) f = f
signForm (Neg _) f = Not f
data Form
= Literal Literal
| Not Form
| And [Form]
| Or [Form]
| Equiv Form Form
| ForAll {-# UNPACK #-} !(Bind Form)
| Exists {-# UNPACK #-} !(Bind Form)
| Connective Connective Form Form
deriving (Eq, Ord)
data Connective = Implies | Follows | Xor | Nor | Nand
deriving (Eq, Ord)
connective :: Connective -> Form -> Form -> Form
connective Implies t u = nt t \/ u
connective Follows t u = t \/ nt u
connective Xor t u = nt (t `Equiv` u)
connective Nor t u = nt (t \/ u)
connective Nand t u = nt (t /\ u)
data Bind a = Bind (Set Variable) a
deriving (Eq, Ord)
true, false :: Form
true = And []
false = Or []
isTrue, isFalse :: Form -> Bool
isTrue (And []) = True
isTrue _ = False
isFalse (Or []) = True
isFalse _ = False
nt :: Form -> Form
nt (Not a) = a
nt a = Not a
(.=>.) :: Form -> Form -> Form
(.=>.) = connective Implies
(.=.) :: Term -> Term -> Form
t .=. u | typ t == O = Literal (Pos (Tru t)) `Equiv` Literal (Pos (Tru u))
| otherwise = Literal (Pos (t :=: u))
(/\), (\/) :: Form -> Form -> Form
And as /\ And bs = And (as ++ bs)
a /\ b | isFalse a || isFalse b = false
And as /\ b = And (b:as)
a /\ And bs = And (a:bs)
a /\ b = And [a, b]
Or as \/ Or bs = Or (as ++ bs)
a \/ b | isTrue a || isTrue b = true
Or as \/ b = Or (b:as)
a \/ Or bs = Or (a:bs)
a \/ b = Or [a, b]
closeForm :: Form -> Form
closeForm f | Set.null vars = f
| otherwise = ForAll (Bind vars f)
where vars = free f
positive :: Form -> Form
positive (Not f) = notInwards f
positive (Connective c t u) = positive (connective c t u)
positive f = f
notInwards :: Form -> Form
notInwards (And as) = Or (fmap notInwards as)
notInwards (Or as) = And (fmap notInwards as)
notInwards (a `Equiv` b) = notInwards a `Equiv` b
notInwards (Not a) = positive a
notInwards (ForAll (Bind vs a)) = Exists (Bind vs (notInwards a))
notInwards (Exists (Bind vs a)) = ForAll (Bind vs (notInwards a))
notInwards (Literal l) = Literal (neg l)
notInwards (Connective c t u) = notInwards (connective c t u)
simple :: Form -> Form
simple (Or as) = Not (And (fmap nt as))
simple (Exists (Bind vs a)) = Not (ForAll (Bind vs (nt a)))
simple (Connective c t u) = simple (connective c t u)
simple a = a
simplify t@Literal{} = t
simplify (Connective c t u) = simplify (connective c t u)
simplify (Not t) = simplify (notInwards t)
simplify (And ts) = foldr (/\) true (fmap simplify ts)
simplify (Or ts) = foldr (\/) false (fmap simplify ts)
simplify (Equiv t u) = equiv (simplify t) (simplify u)
where equiv t u | isTrue t = u
| isTrue u = t
| isFalse t = nt u
| isFalse u = nt t
| otherwise = Equiv t u
simplify (ForAll (Bind vs t)) = forAll vs (simplify t)
where forAll vs t | Set.null vs = t
forAll vs (ForAll (Bind vs' t)) = ForAll (Bind (Set.union vs vs') t)
forAll vs t = ForAll (Bind vs t)
simplify (Exists (Bind vs t)) = exists vs (simplify t)
where exists vs t | Set.null vs = t
exists vs (Exists (Bind vs' t)) = Exists (Bind (Set.union vs vs') t)
exists vs t = Exists (Bind vs t)
data CNF =
CNF {
axioms :: [Input Clause],
conjectures :: [[Input Clause]],
satisfiable :: Maybe Model -> Answer,
unsatisfiable :: Maybe CNFRefutation -> Answer }
toCNF :: [Input Clause] -> [[Input Clause]] -> CNF
toCNF axioms [] = CNF axioms [[]] (Sat Satisfiable) (Unsat Unsatisfiable)
toCNF axioms [conjecture] = CNF axioms [conjecture] (Sat CounterSatisfiable) (Unsat Theorem)
toCNF axioms conjectures = CNF axioms conjectures (\_ -> NoAnswer GaveUp) (Unsat Theorem)
newtype Clause = Clause (Bind [Literal])
clause :: [Literal] -> Clause
clause xs = Clause (bind xs)
toForm :: Clause -> Form
toForm (Clause (Bind vs ls))
| Set.null vs = Or (map Literal ls)
| otherwise = ForAll (Bind vs (Or (map Literal ls)))
toLiterals :: Clause -> [Literal]
toLiterals (Clause (Bind _ ls)) = ls
toClause :: Form -> Maybe Clause
toClause (ForAll (Bind _ f)) = toClause f
toClause f = clause <$> cl f
where
cl (Or fs) = concat <$> mapM cl fs
cl (Literal l) = Just [l]
cl (Not (Literal l)) = Just [neg l]
cl _ = Nothing
type Tag = String
data Kind = Ax AxKind | Conj ConjKind deriving (Eq, Ord)
data AxKind =
Axiom | Hypothesis | Definition | Assumption | Lemma | TheoremKind |
NegatedConjecture deriving (Eq, Ord)
data ConjKind = Conjecture | Question deriving (Eq, Ord)
data Answer = Sat SatReason (Maybe Model) | Unsat UnsatReason (Maybe CNFRefutation) | NoAnswer NoAnswerReason
deriving (Eq, Ord)
data NoAnswerReason = GaveUp | Timeout deriving (Eq, Ord, Show)
data SatReason = Satisfiable | CounterSatisfiable deriving (Eq, Ord, Show)
data UnsatReason = Unsatisfiable | Theorem deriving (Eq, Ord, Show)
type Model = [String]
type CNFRefutation = [String]
instance Show Answer where
show (Sat reason _) = show reason
show (Unsat reason _) = show reason
show (NoAnswer x) = show x
explainAnswer :: Answer -> String
explainAnswer (Sat Satisfiable _) = "the axioms are consistent"
explainAnswer (Sat CounterSatisfiable _) = "the conjecture is false"
explainAnswer (Unsat Unsatisfiable _) = "the axioms are contradictory"
explainAnswer (Unsat Theorem _) = "the conjecture is true"
explainAnswer (NoAnswer GaveUp) = "couldn't solve the problem"
explainAnswer (NoAnswer Timeout) = "ran out of time while solving the problem"
answerSZS :: Answer -> [String]
answerSZS answer =
["% SZS status " ++ show answer] ++
case answerJustification answer of
Nothing -> []
Just strs -> [""] ++ strs
answerJustification :: Answer -> Maybe [String]
answerJustification (Sat _ (Just model)) =
Just $
["% SZS output start Model"] ++
model ++
["% SZS output end Model"]
answerJustification (Unsat _ (Just refutation)) =
Just $
["% SZS output start CNFRefutation"] ++
refutation ++
["% SZS output end CNFRefutation"]
answerJustification _ = Nothing
data Input a = Input
{ tag :: Tag,
kind :: Kind,
source :: InputSource,
what :: a }
deriving (Functor, Foldable, Traversable)
data InputSource =
Unknown
| FromFile String Int
| Inference String String [Input Form]
type Problem a = [Input a]
data TypeOf a where
Form :: TypeOf Form
Clause_ :: TypeOf Clause
Term :: TypeOf Term
Atomic :: TypeOf Atomic
Signed :: (Symbolic a, Symbolic (Signed a)) => TypeOf (Signed a)
Bind_ :: (Symbolic a, Symbolic (Bind a)) => TypeOf (Bind a)
List :: (Symbolic a, Symbolic [a]) => TypeOf [a]
Input_ :: (Symbolic a, Symbolic (Input a)) => TypeOf (Input a)
CNF_ :: TypeOf CNF
class Symbolic a where
typeOf :: a -> TypeOf a
instance Symbolic Form where typeOf _ = Form
instance Symbolic Clause where typeOf _ = Clause_
instance Symbolic Term where typeOf _ = Term
instance Symbolic Atomic where typeOf _ = Atomic
instance Symbolic a => Symbolic (Signed a) where typeOf _ = Signed
instance Symbolic a => Symbolic (Bind a) where typeOf _ = Bind_
instance Symbolic a => Symbolic [a] where typeOf _ = List
instance Symbolic a => Symbolic (Input a) where typeOf _ = Input_
instance Symbolic CNF where typeOf _ = CNF_
data Rep a where
Const :: !a -> Rep a
Unary :: Symbolic a => (a -> b) -> a -> Rep b
Binary :: (Symbolic a, Symbolic b) => (a -> b -> c) -> a -> b -> Rep c
{-# INLINE rep #-}
rep :: Symbolic a => a -> Rep a
rep x =
case typeOf x of
Form -> rep' x
Clause_ -> rep' x
Term -> rep' x
Atomic -> rep' x
Signed -> rep' x
Bind_ -> rep' x
List -> rep' x
Input_ -> rep' x
CNF_ -> rep' x
class Unpack a where
rep' :: a -> Rep a
instance Unpack Form where
rep' (Literal l) = Unary Literal l
rep' (Not t) = Unary Not t
rep' (And ts) = Unary And ts
rep' (Or ts) = Unary Or ts
rep' (Equiv t u) = Binary Equiv t u
rep' (ForAll b) = Unary ForAll b
rep' (Exists b) = Unary Exists b
rep' (Connective c t u) = Binary (Connective c) t u
instance Unpack Clause where
rep' (Clause ls) = Unary Clause ls
instance Unpack Term where
rep' t@Var{} = Const t
rep' (f :@: ts) = Unary (f :@:) ts
instance Unpack Atomic where
rep' (t :=: u) = Binary (:=:) t u
rep' (Tru p) = Unary Tru p
instance Symbolic a => Unpack (Signed a) where
rep' (Pos x) = Unary Pos x
rep' (Neg x) = Unary Neg x
instance Symbolic a => Unpack (Bind a) where
rep' (Bind vs x) = Unary (Bind vs) x
instance Symbolic a => Unpack [a] where
rep' [] = Const []
rep' (x:xs) = Binary (:) x xs
instance Symbolic a => Unpack (Input a) where
rep' (Input tag kind info what) = Unary (Input tag kind info) what
instance Unpack CNF where
rep' (CNF ax conj s1 s2) =
Binary (\ax' conj' -> CNF ax' conj' s1 s2) ax conj
{-# INLINE recursively #-}
recursively :: Symbolic a => (forall a. Symbolic a => a -> a) -> a -> a
recursively h t =
case rep t of
Const x -> x
Unary f x -> f (h x)
Binary f x y -> f (h x) (h y)
{-# INLINE recursivelyM #-}
recursivelyM :: (Monad m, Symbolic a) => (forall a. Symbolic a => a -> m a) -> a -> m a
recursivelyM h t =
case rep t of
Const x -> return x
Unary f x -> liftM f (h x)
Binary f x y -> liftM2 f (h x) (h y)
{-# INLINE collect #-}
collect :: (Symbolic a, Monoid b) => (forall a. Symbolic a => a -> b) -> a -> b
collect h t =
case rep t of
Const _x -> mempty
Unary _f x -> h x
Binary _f x y -> h x `mappend` h y
type Subst = Map Variable Term
ids :: Subst
ids = Map.empty
(|=>) :: Variable -> Term -> Subst
v |=> x = Map.singleton v x
(|+|) :: Subst -> Subst -> Subst
(|+|) = Map.union
subst :: Symbolic a => Subst -> a -> a
subst s t =
case typeOf t of
Term -> term t
Bind_ -> bind t
_ -> generic t
where
term (Var x)
| Just u <- Map.lookup x s = u
term t = generic t
bind :: Symbolic a => Bind a -> Bind a
bind (Bind vs t) =
Bind vs (subst (checkBinder vs (s Map.\\ vs')) t)
where
vs' = Map.fromSet (const ()) vs
generic :: Symbolic a => a -> a
generic t = recursively (subst s) t
free :: Symbolic a => a -> Set Variable
free t
| Term <- typeOf t,
Var x <- t = var x
| Bind_ <- typeOf t = bind t
| otherwise = collect free t
where
var :: Variable -> Set Variable
var x = Set.singleton x
bind :: Symbolic a => Bind a -> Set Variable
bind (Bind vs t) = free t Set.\\ vs
ground :: Symbolic a => a -> Bool
ground = Set.null . free
bind :: Symbolic a => a -> Bind a
bind x = Bind (free x) x
termsAndBinders :: forall a b.
Symbolic a =>
(Term -> DList b) ->
(forall a. Symbolic a => Bind a -> [b]) ->
a -> [b]
termsAndBinders term bind = DList.toList . aux where
aux :: Symbolic c => c -> DList b
aux t =
collect aux t `mplus`
case typeOf t of
Term -> term t
Bind_ -> DList.fromList (bind t)
_ -> mzero
names :: Symbolic a => a -> [Name]
names = usort . termsAndBinders term bind where
term t = DList.fromList (allNames t) `mappend` DList.fromList (allNames (typ t))
bind :: Symbolic a => Bind a -> [Name]
bind (Bind vs _) = map name (Set.toList vs)
run :: Symbolic a => a -> (a -> NameM b) -> b
run x f = runNameM (names x) (f x)
run_ :: Symbolic a => a -> NameM b -> b
run_ x mx = run x (const mx)
types :: Symbolic a => a -> [Type]
types = usort . termsAndBinders term bind where
term t = return (typ t)
bind :: Symbolic a => Bind a -> [Type]
bind (Bind vs _) = map typ (Set.toList vs)
types' :: Symbolic a => a -> [Type]
types' = filter (/= O) . types
terms :: Symbolic a => a -> [Term]
terms = usort . termsAndBinders term mempty where
term t = return t
vars :: Symbolic a => a -> [Variable]
vars = usort . termsAndBinders term bind where
term (Var x) = return x
term _ = mempty
bind :: Symbolic a => Bind a -> [Variable]
bind (Bind vs _) = Set.toList vs
functions :: Symbolic a => a -> [Function]
functions = usort . termsAndBinders term mempty where
term (f :@: _) = return f
term _ = mempty
funOcc :: Symbolic a => Function -> a -> Int
funOcc f x = getSum (occ x)
where
occ :: Symbolic a => a -> Sum Int
occ x = collect occ x `mappend` occ1 x
occ1 :: Symbolic a => a -> Sum Int
occ1 x
| Term <- typeOf x,
g :@: _ <- x,
f == g = Sum 1
| otherwise = mempty
funsOcc :: Symbolic a => a -> Map Function Int
funsOcc =
Map.fromList . map f . group . sort . termsAndBinders term mempty
where
term (f :@: _) = return f
term _ = mempty
f xs@(x:_) = (x, length xs)
isFof :: Symbolic a => a -> Bool
isFof f = length (types' f) <= 1
eraseTypes :: Symbolic a => a -> a
eraseTypes x =
mapType (\ty -> if ty == O then ty else indType) x
uniqueNames :: Symbolic a => a -> NameM a
uniqueNames t = evalStateT (aux Map.empty t) (Map.fromList [(x, t) | x ::: t <- Set.toList (free t)])
where aux :: Symbolic a => Subst -> a -> StateT (Map Name Type) NameM a
aux s t =
case typeOf t of
Term -> term s t
Bind_ -> bind s t
_ -> generic s t
term :: Subst -> Term -> StateT (Map Name Type) NameM Term
term s t@(Var x) = do
case Map.lookup x s of
Nothing -> return t
Just u -> return u
term s t = generic s t
bind :: Symbolic a => Subst -> Bind a -> StateT (Map Name Type) NameM (Bind a)
bind s (Bind vs x) = do
used <- get
let (stale, fresh) = partition ((`Map.member` used) . lhs) (Set.toList vs)
tuple (x ::: y) = (x, y)
stale' <- sequence [ lift (newSymbol x t) | x ::: t <- stale ]
put (used `Map.union` Map.fromList (map tuple (fresh ++ stale')))
case stale of
[] -> fmap (Bind vs) (aux s x)
_ ->
do
let s' = Map.fromList [(x, Var y) | (x, y) <- stale `zip` stale'] `Map.union` s
vs' = Set.fromList (stale' ++ fresh)
fmap (Bind vs') (aux s' x)
generic :: Symbolic a => Subst -> a -> StateT (Map Name Type) NameM a
generic s t = recursivelyM (aux s) t
force :: Symbolic a => a -> a
force x = rnf x `seq` x
where rnf :: Symbolic a => a -> ()
rnf x =
case rep x of
Const !_ -> ()
Unary _ x -> rnf x
Binary _ x y -> rnf x `seq` rnf y
check :: Symbolic a => a -> a
check x | not debugging = x
| check' (free x) x = x
| otherwise = error "Form.check: invariant broken"
where check' :: Symbolic a => Set Variable -> a -> Bool
check' vars t =
case typeOf t of
Term -> term vars t
Bind_ -> bind vars t
_ -> generic vars t
term :: Set Variable -> Term -> Bool
term vars (Var x) = x `Set.member` vars
term vars t = generic vars t
bind :: Symbolic a => Set Variable -> Bind a -> Bool
bind vars (Bind vs t) =
Set.null (vs `Set.intersection` vars) &&
check' (vs `Set.union` vars) t
generic :: Symbolic a => Set Variable -> a -> Bool
generic vars = getAll . collect (All . check' vars)
checkBinder :: Set Variable -> Subst -> Subst
checkBinder vs s | not debugging = s
| Set.null (free (Map.elems s) `Set.intersection` vs) = s
| otherwise = error "Form.checkBinder: capturing substitution"
mapName :: Symbolic a => (Name -> Name) -> a -> a
mapName f0 = rename
where
rename :: Symbolic a => a -> a
rename t =
case typeOf t of
Term -> term t
Bind_ -> bind t
_ -> recursively rename t
bind :: Symbolic a => Bind a -> Bind a
bind (Bind vs t) = Bind (Set.map var vs) (rename t)
term (f :@: ts) = fun f :@: map term ts
term (Var x) = Var (var x)
var = memo $ \(x ::: ty) -> f x ::: type_ ty
fun = memo $ \(x ::: FunType args res) ->
f x ::: FunType (map type_ args) (type_ res)
type_ =
memo $ \ty ->
case ty of
O -> O
Type name -> Type (f name)
f = memo f0
mapType :: Symbolic a => (Type -> Type) -> a -> a
mapType f0 = mapType'
where mapType' :: Symbolic a => a -> a
mapType' t =
case typeOf t of
Term -> term t
Bind_ -> bind t
_ -> recursively mapType' t
bind :: Symbolic a => Bind a -> Bind a
bind (Bind vs t) = Bind (Set.map var vs) (mapType' t)
term (f :@: ts) = fun f :@: map term ts
term (Var x) = Var (var x)
var = memo $ \(x ::: ty) -> x ::: f ty
fun = memo $ \(x ::: FunType args res) ->
x ::: FunType (map f args) (f res)
f = memo f0