{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE ViewPatterns #-}
module Language.Fixpoint.Solver.Simplify (applyBooleanFolding, applyConstantFolding, applySetFolding, isSetPred) where
import Language.Fixpoint.Types hiding (simplify)
import Language.Fixpoint.Smt.Theories
import Data.Hashable
import qualified Data.HashSet as S
import qualified Data.Maybe as Mb
applyBooleanFolding :: Brel -> Expr -> Expr -> Expr
applyBooleanFolding :: Brel -> Expr -> Expr -> Expr
applyBooleanFolding Brel
brel' Expr
e1 Expr
e2 =
case (Expr
e1, Expr
e2) of
(ECon (R Double
left), ECon (R Double
right)) ->
Expr -> Maybe Expr -> Expr
forall a. a -> Maybe a -> a
Mb.fromMaybe Expr
e (Brel -> Double -> Double -> Maybe Expr
bfR Brel
brel' Double
left Double
right)
(ECon (R Double
left), ECon (I Integer
right)) ->
Expr -> Maybe Expr -> Expr
forall a. a -> Maybe a -> a
Mb.fromMaybe Expr
e (Brel -> Double -> Double -> Maybe Expr
bfR Brel
brel' Double
left (Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
right))
(ECon (I Integer
left), ECon (R Double
right)) ->
Expr -> Maybe Expr -> Expr
forall a. a -> Maybe a -> a
Mb.fromMaybe Expr
e (Brel -> Double -> Double -> Maybe Expr
bfR Brel
brel' (Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
left) Double
right)
(ECon (I Integer
left), ECon (I Integer
right)) ->
Expr -> Maybe Expr -> Expr
forall a. a -> Maybe a -> a
Mb.fromMaybe Expr
e (Brel -> Integer -> Integer -> Maybe Expr
bfI Brel
brel' Integer
left Integer
right)
(Expr, Expr)
_ -> if Expr -> Bool
forall v. Eq v => ExprV v -> Bool
isTautoPred Expr
e then Expr
forall v. ExprV v
PTrue else
if Expr -> Bool
forall v. Eq v => ExprV v -> Bool
isContraPred Expr
e then Expr
forall v. ExprV v
PFalse else Expr
e
where
e :: Expr
e = Brel -> Expr -> Expr -> Expr
forall v. Brel -> ExprV v -> ExprV v -> ExprV v
PAtom Brel
brel' Expr
e1 Expr
e2
getOp :: Ord a => Brel -> (a -> a -> Bool)
getOp :: forall a. Ord a => Brel -> a -> a -> Bool
getOp Brel
Gt = a -> a -> Bool
forall a. Ord a => a -> a -> Bool
(>)
getOp Brel
Ge = a -> a -> Bool
forall a. Ord a => a -> a -> Bool
(>=)
getOp Brel
Lt = a -> a -> Bool
forall a. Ord a => a -> a -> Bool
(<)
getOp Brel
Le = a -> a -> Bool
forall a. Ord a => a -> a -> Bool
(<=)
getOp Brel
Eq = a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(==)
getOp Brel
Ne = a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(/=)
getOp Brel
Ueq = a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(==)
getOp Brel
Une = a -> a -> Bool
forall a. Eq a => a -> a -> Bool
(/=)
bfR :: Brel -> Double -> Double -> Maybe Expr
bfR :: Brel -> Double -> Double -> Maybe Expr
bfR Brel
brel Double
left Double
right = if Brel -> Double -> Double -> Bool
forall a. Ord a => Brel -> a -> a -> Bool
getOp Brel
brel Double
left Double
right then Expr -> Maybe Expr
forall a. a -> Maybe a
Just Expr
forall v. ExprV v
PTrue else Expr -> Maybe Expr
forall a. a -> Maybe a
Just Expr
forall v. ExprV v
PFalse
bfI :: Brel -> Integer -> Integer -> Maybe Expr
bfI :: Brel -> Integer -> Integer -> Maybe Expr
bfI Brel
brel Integer
left Integer
right = if Brel -> Integer -> Integer -> Bool
forall a. Ord a => Brel -> a -> a -> Bool
getOp Brel
brel Integer
left Integer
right then Expr -> Maybe Expr
forall a. a -> Maybe a
Just Expr
forall v. ExprV v
PTrue else Expr -> Maybe Expr
forall a. a -> Maybe a
Just Expr
forall v. ExprV v
PFalse
applyConstantFolding :: Bop -> Expr -> Expr -> Expr
applyConstantFolding :: Bop -> Expr -> Expr -> Expr
applyConstantFolding Bop
bop' Expr
e1 Expr
e2 =
case (Expr -> Expr
dropECst Expr
e1, Expr -> Expr
dropECst Expr
e2) of
(ECon (R Double
left), ECon (R Double
right)) ->
Expr -> Maybe Expr -> Expr
forall a. a -> Maybe a -> a
Mb.fromMaybe Expr
e (Bop -> Double -> Double -> Maybe Expr
cfR Bop
bop' Double
left Double
right)
(ECon (R Double
left), ECon (I Integer
right)) ->
Expr -> Maybe Expr -> Expr
forall a. a -> Maybe a -> a
Mb.fromMaybe Expr
e (Bop -> Double -> Double -> Maybe Expr
cfR Bop
bop' Double
left (Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
right))
(ECon (I Integer
left), ECon (R Double
right)) ->
Expr -> Maybe Expr -> Expr
forall a. a -> Maybe a -> a
Mb.fromMaybe Expr
e (Bop -> Double -> Double -> Maybe Expr
cfR Bop
bop' (Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
left) Double
right)
(ECon (I Integer
left), ECon (I Integer
right)) ->
Expr -> Maybe Expr -> Expr
forall a. a -> Maybe a -> a
Mb.fromMaybe Expr
e (Bop -> Integer -> Integer -> Maybe Expr
cfI Bop
bop' Integer
left Integer
right)
(EBin Bop
Mod Expr
_ Expr
_ , Expr
_) -> Expr
e
(EBin Bop
bop1 Expr
e11 (Expr -> Expr
dropECst -> ECon (R Double
left)), ECon (R Double
right))
| Bop
bop' Bop -> Bop -> Bool
forall a. Eq a => a -> a -> Bool
== Bop
bop1 -> Expr -> (Expr -> Expr) -> Maybe Expr -> Expr
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Expr
e (Bop -> Expr -> Expr -> Expr
forall v. Bop -> ExprV v -> ExprV v -> ExprV v
EBin Bop
bop' Expr
e11) (Bop -> Double -> Double -> Maybe Expr
cfR (Bop -> Bop
rop Bop
bop') Double
left Double
right)
| Bool
otherwise -> Expr
e
(EBin Bop
bop1 Expr
e11 (Expr -> Expr
dropECst -> ECon (R Double
left)), ECon (I Integer
right))
| Bop
bop' Bop -> Bop -> Bool
forall a. Eq a => a -> a -> Bool
== Bop
bop1 -> Expr -> (Expr -> Expr) -> Maybe Expr -> Expr
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Expr
e (Bop -> Expr -> Expr -> Expr
forall v. Bop -> ExprV v -> ExprV v -> ExprV v
EBin Bop
bop' Expr
e11) (Bop -> Double -> Double -> Maybe Expr
cfR (Bop -> Bop
rop Bop
bop') Double
left (Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
right))
| Bool
otherwise -> Expr
e
(EBin Bop
bop1 Expr
e11 (Expr -> Expr
dropECst -> ECon (I Integer
left)), ECon (R Double
right))
| Bop
bop' Bop -> Bop -> Bool
forall a. Eq a => a -> a -> Bool
== Bop
bop1 -> Expr -> (Expr -> Expr) -> Maybe Expr -> Expr
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Expr
e (Bop -> Expr -> Expr -> Expr
forall v. Bop -> ExprV v -> ExprV v -> ExprV v
EBin Bop
bop' Expr
e11) (Bop -> Double -> Double -> Maybe Expr
cfR (Bop -> Bop
rop Bop
bop') (Integer -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
left) Double
right)
| Bool
otherwise -> Expr
e
(EBin Bop
bop1 Expr
e11 (Expr -> Expr
dropECst -> ECon (I Integer
left)), ECon (I Integer
right))
| Bop
bop' Bop -> Bop -> Bool
forall a. Eq a => a -> a -> Bool
== Bop
bop1 -> Expr -> (Expr -> Expr) -> Maybe Expr -> Expr
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Expr
e (Bop -> Expr -> Expr -> Expr
forall v. Bop -> ExprV v -> ExprV v -> ExprV v
EBin Bop
bop' Expr
e11) (Bop -> Integer -> Integer -> Maybe Expr
cfI (Bop -> Bop
rop Bop
bop') Integer
left Integer
right)
| Bool
otherwise -> Expr
e
(Expr, Expr)
_ -> Expr
e
where
rop :: Bop -> Bop
rop :: Bop -> Bop
rop Bop
Plus = Bop
Plus
rop Bop
Minus = Bop
Plus
rop Bop
Times = Bop
Times
rop Bop
Div = Bop
Times
rop Bop
RTimes = Bop
RTimes
rop Bop
RDiv = Bop
RTimes
rop Bop
Mod = Bop
Mod
e :: Expr
e = Bop -> Expr -> Expr -> Expr
forall v. Bop -> ExprV v -> ExprV v -> ExprV v
EBin Bop
bop' Expr
e1 Expr
e2
getOp :: Num a => Bop -> Maybe (a -> a -> a)
getOp :: forall a. Num a => Bop -> Maybe (a -> a -> a)
getOp Bop
Minus = (a -> a -> a) -> Maybe (a -> a -> a)
forall a. a -> Maybe a
Just (-)
getOp Bop
Plus = (a -> a -> a) -> Maybe (a -> a -> a)
forall a. a -> Maybe a
Just a -> a -> a
forall a. Num a => a -> a -> a
(+)
getOp Bop
Times = (a -> a -> a) -> Maybe (a -> a -> a)
forall a. a -> Maybe a
Just a -> a -> a
forall a. Num a => a -> a -> a
(*)
getOp Bop
RTimes = (a -> a -> a) -> Maybe (a -> a -> a)
forall a. a -> Maybe a
Just a -> a -> a
forall a. Num a => a -> a -> a
(*)
getOp Bop
_ = Maybe (a -> a -> a)
forall a. Maybe a
Nothing
cfR :: Bop -> Double -> Double -> Maybe Expr
cfR :: Bop -> Double -> Double -> Maybe Expr
cfR Bop
bop Double
left Double
right = Maybe (Double -> Double -> Double) -> Maybe Expr
forall {v}. Maybe (Double -> Double -> Double) -> Maybe (ExprV v)
go (Bop -> Maybe (Double -> Double -> Double)
forall {a}. Fractional a => Bop -> Maybe (a -> a -> a)
getOp' Bop
bop)
where
go :: Maybe (Double -> Double -> Double) -> Maybe (ExprV v)
go (Just Double -> Double -> Double
f) =
let x :: Double
x = Double -> Double -> Double
f Double
left Double
right
in if Double -> Bool
forall a. RealFloat a => a -> Bool
isNaN Double
x Bool -> Bool -> Bool
|| Double -> Bool
forall a. RealFloat a => a -> Bool
isInfinite Double
x then ExprV v -> Maybe (ExprV v)
forall a. a -> Maybe a
Just (ExprV v -> Maybe (ExprV v)) -> ExprV v -> Maybe (ExprV v)
forall a b. (a -> b) -> a -> b
$ Constant -> ExprV v
forall v. Constant -> ExprV v
ECon (Double -> Constant
R Double
x)
else Maybe (ExprV v)
forall a. Maybe a
Nothing
go Maybe (Double -> Double -> Double)
Nothing = Maybe (ExprV v)
forall a. Maybe a
Nothing
getOp' :: Bop -> Maybe (a -> a -> a)
getOp' Bop
Div | Double
right Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
/= Double
0 = (a -> a -> a) -> Maybe (a -> a -> a)
forall a. a -> Maybe a
Just a -> a -> a
forall a. Fractional a => a -> a -> a
(/)
getOp' Bop
RDiv | Double
right Double -> Double -> Bool
forall a. Eq a => a -> a -> Bool
/= Double
0 = (a -> a -> a) -> Maybe (a -> a -> a)
forall a. a -> Maybe a
Just a -> a -> a
forall a. Fractional a => a -> a -> a
(/)
getOp' Bop
op = Bop -> Maybe (a -> a -> a)
forall a. Num a => Bop -> Maybe (a -> a -> a)
getOp Bop
op
cfI :: Bop -> Integer -> Integer -> Maybe Expr
cfI :: Bop -> Integer -> Integer -> Maybe Expr
cfI Bop
bop Integer
left Integer
right = ((Integer -> Integer -> Integer) -> Expr)
-> Maybe (Integer -> Integer -> Integer) -> Maybe Expr
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Integer -> Integer -> Integer) -> Expr
forall {v}. (Integer -> Integer -> Integer) -> ExprV v
go (Bop -> Maybe (Integer -> Integer -> Integer)
forall {a}. Integral a => Bop -> Maybe (a -> a -> a)
getOp' Bop
bop)
where
go :: (Integer -> Integer -> Integer) -> ExprV v
go Integer -> Integer -> Integer
f = Constant -> ExprV v
forall v. Constant -> ExprV v
ECon (Constant -> ExprV v) -> Constant -> ExprV v
forall a b. (a -> b) -> a -> b
$ Integer -> Constant
I (Integer -> Constant) -> Integer -> Constant
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Integer
f Integer
left Integer
right
getOp' :: Bop -> Maybe (a -> a -> a)
getOp' Bop
Mod | Integer
right Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
/= Integer
0 = (a -> a -> a) -> Maybe (a -> a -> a)
forall a. a -> Maybe a
Just a -> a -> a
forall a. Integral a => a -> a -> a
mod
getOp' Bop
op = Bop -> Maybe (a -> a -> a)
forall a. Num a => Bop -> Maybe (a -> a -> a)
getOp Bop
op
isSetPred :: Expr -> Bool
isSetPred :: Expr -> Bool
isSetPred (EVar Symbol
s) | Symbol
s Symbol -> Symbol -> Bool
forall a. Eq a => a -> a -> Bool
== Symbol
forall a. IsString a => a
setEmp = Bool
True
isSetPred (EApp Expr
e1 Expr
_) = case Expr
e1 of
(EVar Symbol
s) | Symbol
s Symbol -> Symbol -> Bool
forall a. Eq a => a -> a -> Bool
== Symbol
forall a. IsString a => a
setMem Bool -> Bool -> Bool
|| Symbol
s Symbol -> Symbol -> Bool
forall a. Eq a => a -> a -> Bool
== Symbol
forall a. IsString a => a
setSub -> Bool
True
Expr
_ -> Bool
False
isSetPred Expr
_ = Bool
False
applySetFolding :: Expr -> Expr -> Expr
applySetFolding :: Expr -> Expr -> Expr
applySetFolding Expr
expr1 Expr
expr2 = case Expr
expr1 of
(EVar Symbol
s) | Symbol
s Symbol -> Symbol -> Bool
forall a. Eq a => a -> a -> Bool
== Symbol
forall a. IsString a => a
setEmp
-> Expr
-> (HashSet Integer -> Expr) -> Maybe (HashSet Integer) -> Expr
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Expr
e (Bool -> Expr
forall {v}. Bool -> ExprV v
fromBool (Bool -> Expr)
-> (HashSet Integer -> Bool) -> HashSet Integer -> Expr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashSet Integer -> Bool
forall a. HashSet a -> Bool
S.null) (Expr -> Maybe (HashSet Integer)
evalSetI Expr
expr2)
(EApp (EVar Symbol
s) Expr
e1') | Symbol
s Symbol -> Symbol -> Bool
forall a. Eq a => a -> a -> Bool
== Symbol
forall a. IsString a => a
setMem
-> Expr -> (Bool -> Expr) -> Maybe Bool -> Expr
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Expr
e Bool -> Expr
forall {v}. Bool -> ExprV v
fromBool (Integer -> HashSet Integer -> Bool
forall a. (Eq a, Hashable a) => a -> HashSet a -> Bool
S.member (Integer -> HashSet Integer -> Bool)
-> Maybe Integer -> Maybe (HashSet Integer -> Bool)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Expr -> Maybe Integer
getInt Expr
e1' Maybe (HashSet Integer -> Bool)
-> Maybe (HashSet Integer) -> Maybe Bool
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Expr -> Maybe (HashSet Integer)
evalSetI Expr
expr2)
| Symbol
s Symbol -> Symbol -> Bool
forall a. Eq a => a -> a -> Bool
== Symbol
forall a. IsString a => a
setEmp
-> Expr
-> (HashSet Integer -> Expr) -> Maybe (HashSet Integer) -> Expr
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Expr
e (Bool -> Expr
forall {v}. Bool -> ExprV v
fromBool (Bool -> Expr)
-> (HashSet Integer -> Bool) -> HashSet Integer -> Expr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HashSet Integer -> Bool
forall a. HashSet a -> Bool
S.null) (HashSet Integer -> HashSet Integer -> HashSet Integer
forall a. (Eq a, Hashable a) => HashSet a -> HashSet a -> HashSet a
S.difference (HashSet Integer -> HashSet Integer -> HashSet Integer)
-> Maybe (HashSet Integer)
-> Maybe (HashSet Integer -> HashSet Integer)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Expr -> Maybe (HashSet Integer)
evalSetI Expr
e1' Maybe (HashSet Integer -> HashSet Integer)
-> Maybe (HashSet Integer) -> Maybe (HashSet Integer)
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Expr -> Maybe (HashSet Integer)
evalSetI Expr
expr2)
| Bool
otherwise
-> Expr
e
Expr
_ -> Expr
e
where
e :: Expr
e = Expr -> Expr -> Expr
forall v. ExprV v -> ExprV v -> ExprV v
EApp Expr
expr1 Expr
expr2
fromBool :: Bool -> ExprV v
fromBool Bool
True = ExprV v
forall v. ExprV v
PTrue
fromBool Bool
False = ExprV v
forall v. ExprV v
PFalse
getInt :: Expr -> Maybe Integer
getInt :: Expr -> Maybe Integer
getInt (ECon (I Integer
n)) = Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
n
getInt Expr
_ = Maybe Integer
forall a. Maybe a
Nothing
getOp :: (Eq a, Hashable a) => Symbol -> Maybe (S.HashSet a -> S.HashSet a -> S.HashSet a)
getOp :: forall a.
(Eq a, Hashable a) =>
Symbol -> Maybe (HashSet a -> HashSet a -> HashSet a)
getOp Symbol
s | Symbol
s Symbol -> Symbol -> Bool
forall a. Eq a => a -> a -> Bool
== Symbol
forall a. IsString a => a
setCup = (HashSet a -> HashSet a -> HashSet a)
-> Maybe (HashSet a -> HashSet a -> HashSet a)
forall a. a -> Maybe a
Just HashSet a -> HashSet a -> HashSet a
forall a. Eq a => HashSet a -> HashSet a -> HashSet a
S.union
| Symbol
s Symbol -> Symbol -> Bool
forall a. Eq a => a -> a -> Bool
== Symbol
forall a. IsString a => a
setCap = (HashSet a -> HashSet a -> HashSet a)
-> Maybe (HashSet a -> HashSet a -> HashSet a)
forall a. a -> Maybe a
Just HashSet a -> HashSet a -> HashSet a
forall a. Eq a => HashSet a -> HashSet a -> HashSet a
S.intersection
| Symbol
s Symbol -> Symbol -> Bool
forall a. Eq a => a -> a -> Bool
== Symbol
forall a. IsString a => a
setDif = (HashSet a -> HashSet a -> HashSet a)
-> Maybe (HashSet a -> HashSet a -> HashSet a)
forall a. a -> Maybe a
Just HashSet a -> HashSet a -> HashSet a
forall a. (Eq a, Hashable a) => HashSet a -> HashSet a -> HashSet a
S.difference
| Bool
otherwise = Maybe (HashSet a -> HashSet a -> HashSet a)
forall a. Maybe a
Nothing
evalSetI :: Expr -> Maybe (S.HashSet Integer)
evalSetI :: Expr -> Maybe (HashSet Integer)
evalSetI (EApp Expr
e1 Expr
e2) = case Expr
e1 of
(EVar Symbol
s) | Symbol
s Symbol -> Symbol -> Bool
forall a. Eq a => a -> a -> Bool
== Symbol
forall a. IsString a => a
setEmpty -> HashSet Integer -> Maybe (HashSet Integer)
forall a. a -> Maybe a
Just HashSet Integer
forall a. HashSet a
S.empty
| Symbol
s Symbol -> Symbol -> Bool
forall a. Eq a => a -> a -> Bool
== Symbol
forall a. IsString a => a
setSng -> case Expr
e2 of
(ECon (I Integer
n)) -> HashSet Integer -> Maybe (HashSet Integer)
forall a. a -> Maybe a
Just (HashSet Integer -> Maybe (HashSet Integer))
-> HashSet Integer -> Maybe (HashSet Integer)
forall a b. (a -> b) -> a -> b
$ Integer -> HashSet Integer
forall a. Hashable a => a -> HashSet a
S.singleton Integer
n
Expr
_ -> Maybe (HashSet Integer)
forall a. Maybe a
Nothing
(EApp (EVar Symbol
f) Expr
e1') -> Symbol
-> Maybe (HashSet Integer -> HashSet Integer -> HashSet Integer)
forall a.
(Eq a, Hashable a) =>
Symbol -> Maybe (HashSet a -> HashSet a -> HashSet a)
getOp Symbol
f Maybe (HashSet Integer -> HashSet Integer -> HashSet Integer)
-> Maybe (HashSet Integer)
-> Maybe (HashSet Integer -> HashSet Integer)
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Expr -> Maybe (HashSet Integer)
evalSetI Expr
e1' Maybe (HashSet Integer -> HashSet Integer)
-> Maybe (HashSet Integer) -> Maybe (HashSet Integer)
forall a b. Maybe (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Expr -> Maybe (HashSet Integer)
evalSetI Expr
e2
Expr
_ -> Maybe (HashSet Integer)
forall a. Maybe a
Nothing
evalSetI Expr
_ = Maybe (HashSet Integer)
forall a. Maybe a
Nothing