module ToySolver.FourierMotzkin.FOL
( solveFormula
, eliminateQuantifiers
, eliminateQuantifiers'
)
where
import Control.Monad
import qualified Data.IntSet as IS
import Data.Maybe
import ToySolver.Data.ArithRel
import ToySolver.Data.Boolean
import ToySolver.Data.DNF
import qualified ToySolver.Data.FOL.Arith as FOL
import qualified ToySolver.Data.LA.FOL as LAFOL
import ToySolver.Data.Var
import ToySolver.FourierMotzkin.Core
solveFormula :: [Var] -> FOL.Formula (FOL.Atom Rational) -> FOL.SatResult Rational
solveFormula vs formula =
case eliminateQuantifiers' formula of
Nothing -> FOL.Unknown
Just dnf ->
case msum [solve' (IS.fromList vs) xs | xs <- unDNF dnf] of
Nothing -> FOL.Unsat
Just m -> FOL.Sat m
eliminateQuantifiers :: FOL.Formula (FOL.Atom Rational) -> Maybe (FOL.Formula (FOL.Atom Rational))
eliminateQuantifiers phi = do
dnf <- eliminateQuantifiers' phi
return $ orB $ map (andB . map (LAFOL.toFOLFormula . toLAAtom)) $ unDNF dnf
eliminateQuantifiers' :: FOL.Formula (FOL.Atom Rational) -> Maybe (DNF Lit)
eliminateQuantifiers' = f
where
f FOL.T = return true
f FOL.F = return false
f (FOL.Atom (Rel a op b)) = do
a' <- LAFOL.fromFOLExpr a
b' <- LAFOL.fromFOLExpr b
return $ fromLAAtom $ Rel 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) = f (FOL.pushNot a)
f (FOL.Imply a b) = f (FOL.Or (FOL.Not a) b)
f (FOL.Equiv a b) = f (FOL.And (FOL.Imply a b) (FOL.Imply b a))
f (FOL.Forall v a) = do
dnf <- f (FOL.Exists v (FOL.pushNot a))
return (notB dnf)
f (FOL.Exists v a) = do
dnf <- f a
return $ orB [DNF $ maybeToList $ fmap fst $ project' v xs | xs <- unDNF dnf]