module ToySolver.Arith.Cooper.FOL
( eliminateQuantifiers
, solveFormula
) where
import Control.Monad
import ToySolver.Data.ArithRel
import ToySolver.Data.Boolean
import qualified ToySolver.Data.FOL.Arith as FOL
import qualified ToySolver.Data.LA.FOL as LAFOL
import ToySolver.Data.Var
import ToySolver.Arith.Cooper.Base
eliminateQuantifiers :: FOL.Formula (FOL.Atom Rational) -> Maybe QFFormula
eliminateQuantifiers = f
where
f FOL.T = return true
f FOL.F = return false
f (FOL.Atom (ArithRel a op b)) = do
a' <- LAFOL.fromFOLExpr a
b' <- LAFOL.fromFOLExpr b
return $ fromLAAtom (ArithRel a' op b')
f (FOL.And a b) = liftM2 (.&&.) (f a) (f b)
f (FOL.Or a b) = liftM2 (.||.) (f a) (f b)
f (FOL.Not a) = liftM notB (f a)
f (FOL.Imply a b) = liftM2 (.=>.) (f a) (f b)
f (FOL.Equiv a b) = liftM2 (.<=>.) (f a) (f b)
f (FOL.Forall x body) = liftM notB $ f $ FOL.Exists x $ FOL.Not body
f (FOL.Exists x body) = liftM (fst . project x) (f body)
solveFormula :: VarSet -> FOL.Formula (FOL.Atom Rational) -> FOL.SatResult Integer
solveFormula vs formula =
case eliminateQuantifiers formula of
Nothing -> FOL.Unknown
Just formula' ->
case solveQFFormula vs formula' of
Nothing -> FOL.Unsat
Just m -> FOL.Sat m