hasmtlib-1.0.0: src/Language/Hasmtlib/Internal/Expr.hs
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE NoStarIsType #-}
{-# LANGUAGE RoleAnnotations #-}
{-# LANGUAGE TemplateHaskell #-}
module Language.Hasmtlib.Internal.Expr where
import Language.Hasmtlib.Internal.Bitvec
import Language.Hasmtlib.Internal.Render
import Language.Hasmtlib.Boolean
import Data.Kind
import Data.Proxy
import Data.Coerce
import Data.ByteString.Builder
import Control.Lens
import GHC.TypeLits
-- | Sorts in SMTLib2 - used as promoted type (data-kind).
data SMTSort = IntSort | RealSort | BoolSort | BvSort Nat
-- | An internal SMT variable with a phantom-type which holds an 'Int' as it's identifier.
type role SMTVar phantom
newtype SMTVar (t :: SMTSort) = SMTVar { _varId :: Int } deriving (Show, Eq, Ord)
$(makeLenses ''SMTVar)
-- | Injective type-family that computes the Haskell 'Type' of a 'SMTSort'.
type family HaskellType (t :: SMTSort) = (r :: Type) | r -> t where
HaskellType IntSort = Integer
HaskellType RealSort = Double
HaskellType BoolSort = Bool
HaskellType (BvSort n) = Bitvec n
-- | A wrapper for values of 'SMTSort's.
data Value (t :: SMTSort) where
IntValue :: HaskellType IntSort -> Value IntSort
RealValue :: HaskellType RealSort -> Value RealSort
BoolValue :: HaskellType BoolSort -> Value BoolSort
BvValue :: HaskellType (BvSort n) -> Value (BvSort n)
-- | Unwrap a value.
unwrapValue :: Value t -> HaskellType t
unwrapValue (IntValue v) = v
unwrapValue (RealValue v) = v
unwrapValue (BoolValue v) = v
unwrapValue (BvValue v) = v
{-# INLINEABLE unwrapValue #-}
-- | Wrap a value.
wrapValue :: forall t. KnownSMTSort t => HaskellType t -> Value t
wrapValue = case sortSing @t of
SIntSort -> IntValue
SRealSort -> RealValue
SBoolSort -> BoolValue
SBvSort _ -> BvValue
{-# INLINEABLE wrapValue #-}
deriving instance Show (Value t)
deriving instance Eq (Value t)
deriving instance Ord (Value t)
-- | Singleton for 'SMTSort'.
data SSMTSort (t :: SMTSort) where
SIntSort :: SSMTSort IntSort
SRealSort :: SSMTSort RealSort
SBoolSort :: SSMTSort BoolSort
SBvSort :: KnownNat n => Proxy n -> SSMTSort (BvSort n)
deriving instance Show (SSMTSort t)
deriving instance Eq (SSMTSort t)
deriving instance Ord (SSMTSort t)
-- | Compute singleton 'SSMTSort' from it's promoted type 'SMTSort'.
class KnownSMTSort (t :: SMTSort) where sortSing :: SSMTSort t
instance KnownSMTSort IntSort where sortSing = SIntSort
instance KnownSMTSort RealSort where sortSing = SRealSort
instance KnownSMTSort BoolSort where sortSing = SBoolSort
instance KnownNat n => KnownSMTSort (BvSort n) where sortSing = SBvSort (Proxy @n)
-- | An existential wrapper that hides some 'SMTSort'.
data SomeKnownSMTSort f where
SomeKnownSMTSort :: forall (t :: SMTSort) f. KnownSMTSort t => f t -> SomeKnownSMTSort f
-- | A SMT expression.
-- For internal use only.
-- For building expressions use the corresponding instances (Num, Boolean, ...).
data Expr (t :: SMTSort) where
Var :: SMTVar t -> Expr t
Constant :: Value t -> Expr t
Plus :: Num (HaskellType t) => Expr t -> Expr t -> Expr t
Neg :: Num (HaskellType t) => Expr t -> Expr t
Mul :: Num (HaskellType t) => Expr t -> Expr t -> Expr t
Abs :: Num (HaskellType t) => Expr t -> Expr t
Mod :: Expr IntSort -> Expr IntSort -> Expr IntSort
IDiv :: Expr IntSort -> Expr IntSort -> Expr IntSort
Div :: Expr RealSort -> Expr RealSort -> Expr RealSort
LTH :: (Ord (HaskellType t), KnownSMTSort t) => Expr t -> Expr t -> Expr BoolSort
LTHE :: (Ord (HaskellType t), KnownSMTSort t) => Expr t -> Expr t -> Expr BoolSort
EQU :: (Eq (HaskellType t), KnownSMTSort t) => Expr t -> Expr t -> Expr BoolSort
Distinct :: (Eq (HaskellType t), KnownSMTSort t) => Expr t -> Expr t -> Expr BoolSort
GTHE :: (Ord (HaskellType t), KnownSMTSort t) => Expr t -> Expr t -> Expr BoolSort
GTH :: (Ord (HaskellType t), KnownSMTSort t) => Expr t -> Expr t -> Expr BoolSort
Not :: Boolean (HaskellType t) => Expr t -> Expr t
And :: Boolean (HaskellType t) => Expr t -> Expr t -> Expr t
Or :: Boolean (HaskellType t) => Expr t -> Expr t -> Expr t
Impl :: Boolean (HaskellType t) => Expr t -> Expr t -> Expr t
Xor :: Boolean (HaskellType t) => Expr t -> Expr t -> Expr t
Pi :: Expr RealSort
Sqrt :: Expr RealSort -> Expr RealSort
Exp :: Expr RealSort -> Expr RealSort
Sin :: Expr RealSort -> Expr RealSort
Cos :: Expr RealSort -> Expr RealSort
Tan :: Expr RealSort -> Expr RealSort
Asin :: Expr RealSort -> Expr RealSort
Acos :: Expr RealSort -> Expr RealSort
Atan :: Expr RealSort -> Expr RealSort
ToReal :: Expr IntSort -> Expr RealSort
ToInt :: Expr RealSort -> Expr IntSort
IsInt :: Expr RealSort -> Expr BoolSort
Ite :: Expr BoolSort -> Expr t -> Expr t -> Expr t
BvNot :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n)
BvAnd :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr (BvSort n)
BvOr :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr (BvSort n)
BvXor :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr (BvSort n)
BvNand :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr (BvSort n)
BvNor :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr (BvSort n)
BvNeg :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n)
BvAdd :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr (BvSort n)
BvSub :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr (BvSort n)
BvMul :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr (BvSort n)
BvuDiv :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr (BvSort n)
BvuRem :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr (BvSort n)
BvShL :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr (BvSort n)
BvLShR :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr (BvSort n)
BvConcat :: (KnownNat n, KnownNat m) => Expr (BvSort n) -> Expr (BvSort m) -> Expr (BvSort (n + m))
BvRotL :: (KnownNat n, KnownNat i, KnownNat (Mod i n)) => Proxy i -> Expr (BvSort n) -> Expr (BvSort n)
BvRotR :: (KnownNat n, KnownNat i, KnownNat (Mod i n)) => Proxy i -> Expr (BvSort n) -> Expr (BvSort n)
BvuLT :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr BoolSort
BvuLTHE :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr BoolSort
BvuGTHE :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr BoolSort
BvuGT :: KnownNat n => Expr (BvSort n) -> Expr (BvSort n) -> Expr BoolSort
ForAll :: KnownSMTSort t => Maybe (SMTVar t) -> (Expr t -> Expr BoolSort) -> Expr BoolSort
Exists :: KnownSMTSort t => Maybe (SMTVar t) -> (Expr t -> Expr BoolSort) -> Expr BoolSort
instance Boolean (Expr BoolSort) where
bool = Constant . BoolValue
{-# INLINE bool #-}
(&&) = And
{-# INLINE (&&) #-}
(||) = Or
{-# INLINE (||) #-}
not = Not
{-# INLINE not #-}
xor = Xor
{-# INLINE xor #-}
instance KnownNat n => Boolean (Expr (BvSort n)) where
bool = Constant . BvValue . bool
{-# INLINE bool #-}
(&&) = BvAnd
{-# INLINE (&&) #-}
(||) = BvOr
{-# INLINE (||) #-}
not = BvNot
{-# INLINE not #-}
xor = BvXor
{-# INLINE xor #-}
instance Bounded (Expr BoolSort) where
minBound = false
maxBound = true
instance KnownNat n => Bounded (Expr (BvSort n)) where
minBound = Constant $ BvValue minBound
maxBound = Constant $ BvValue maxBound
instance Render (SSMTSort t) where
render SIntSort = "Int"
render SRealSort = "Real"
render SBoolSort = "Bool"
render (SBvSort p) = renderBinary "_" ("BitVec" :: Builder) (natVal p)
{-# INLINEABLE render #-}
instance Render (SMTVar t) where
render v = "var_" <> intDec (coerce @(SMTVar t) @Int v)
{-# INLINEABLE render #-}
instance KnownSMTSort t => Render (Expr t) where
render (Var v) = render v
render (Constant (IntValue x)) = render x
render (Constant (RealValue x)) = render x
render (Constant (BoolValue x)) = render x
render (Constant (BvValue v)) = "#b" <> render v
render (Plus x y) = renderBinary "+" x y
render (Neg x) = renderUnary "-" x
render (Mul x y) = renderBinary "*" x y
render (Abs x) = renderUnary "abs" x
render (Mod x y) = renderBinary "mod" x y
render (IDiv x y) = renderBinary "div" x y
render (Div x y) = renderBinary "/" x y
render (LTH x y) = renderBinary "<" x y
render (LTHE x y) = renderBinary "<=" x y
render (EQU x y) = renderBinary "=" x y
render (Distinct x y) = renderBinary "distinct" x y
render (GTHE x y) = renderBinary ">=" x y
render (GTH x y) = renderBinary ">" x y
render (Not x) = renderUnary "not" x
render (And x y) = renderBinary "and" x y
render (Or x y) = renderBinary "or" x y
render (Impl x y) = renderBinary "=>" x y
render (Xor x y) = renderBinary "xor" x y
render Pi = "real.pi"
render (Sqrt x) = renderUnary "sqrt" x
render (Exp x) = renderUnary "exp" x
render (Sin x) = renderUnary "sin" x
render (Cos x) = renderUnary "cos" x
render (Tan x) = renderUnary "tan" x
render (Asin x) = renderUnary "arcsin" x
render (Acos x) = renderUnary "arccos" x
render (Atan x) = renderUnary "arctan" x
render (ToReal x) = renderUnary "to_real" x
render (ToInt x) = renderUnary "to_int" x
render (IsInt x) = renderUnary "is_int" x
render (Ite p t f) = renderTernary "ite" p t f
render (BvNot x) = renderUnary "bvnot" (render x)
render (BvAnd x y) = renderBinary "bvand" (render x) (render y)
render (BvOr x y) = renderBinary "bvor" (render x) (render y)
render (BvXor x y) = renderBinary "bvxor" (render x) (render y)
render (BvNand x y) = renderBinary "bvnand" (render x) (render y)
render (BvNor x y) = renderBinary "bvnor" (render x) (render y)
render (BvNeg x) = renderUnary "bvneg" (render x)
render (BvAdd x y) = renderBinary "bvadd" (render x) (render y)
render (BvSub x y) = renderBinary "bvsub" (render x) (render y)
render (BvMul x y) = renderBinary "bvmul" (render x) (render y)
render (BvuDiv x y) = renderBinary "bvudiv" (render x) (render y)
render (BvuRem x y) = renderBinary "bvurem" (render x) (render y)
render (BvShL x y) = renderBinary "bvshl" (render x) (render y)
render (BvLShR x y) = renderBinary "bvlshr" (render x) (render y)
render (BvConcat x y) = renderBinary "concat" (render x) (render y)
render (BvRotL i x) = renderUnary (renderBinary "_" ("rotate_left" :: Builder) (render (natVal i))) (render x)
render (BvRotR i x) = renderUnary (renderBinary "_" ("rotate_right" :: Builder) (render (natVal i))) (render x)
render (BvuLT x y) = renderBinary "bvult" (render x) (render y)
render (BvuLTHE x y) = renderBinary "bvule" (render x) (render y)
render (BvuGTHE x y) = renderBinary "bvuge" (render x) (render y)
render (BvuGT x y) = renderBinary "bvugt" (render x) (render y)
render (ForAll mQvar f) = renderQuantifier "forall" mQvar f
render (Exists mQvar f) = renderQuantifier "exists" mQvar f
renderQuantifier :: forall t. KnownSMTSort t => Builder -> Maybe (SMTVar t) -> (Expr t -> Expr BoolSort) -> Builder
renderQuantifier qname (Just qvar) f =
renderBinary
qname
("(" <> renderUnary (render qvar) (sortSing @t) <> ")")
expr
where
expr = render $ f $ Var qvar
renderQuantifier _ Nothing _ = mempty
instance Show (Expr t) where
show (Var v) = show v
show (Constant (IntValue x)) = show x
show (Constant (RealValue x)) = show x
show (Constant (BoolValue x)) = show x
show (Constant (BvValue x)) = show x
show (Plus x y) = "(" ++ show x ++ " + " ++ show y ++ ")"
show (Neg x) = "(- " ++ show x ++ ")"
show (Mul x y) = "(" ++ show x ++ " * " ++ show y ++ ")"
show (Abs x) = "(abs " ++ show x ++ ")"
show (Mod x y) = "(" ++ show x ++ " mod " ++ show y ++ ")"
show (IDiv x y) = "(" ++ show x ++ " div " ++ show y ++ ")"
show (Div x y) = "(" ++ show x ++ " / " ++ show y ++ ")"
show (LTH x y) = "(" ++ show x ++ " < " ++ show y ++ ")"
show (LTHE x y) = "(" ++ show x ++ " <= " ++ show y ++ ")"
show (EQU x y) = "(" ++ show x ++ " == " ++ show y ++ ")"
show (Distinct x y) = "(" ++ show x ++ " /= " ++ show y ++ ")"
show (GTHE x y) = "(" ++ show x ++ " >= " ++ show y ++ ")"
show (GTH x y) = "(" ++ show x ++ " > " ++ show y ++ ")"
show (Not x) = "(not " ++ show x ++ ")"
show (And x y) = "(" ++ show x ++ " && " ++ show y ++ ")"
show (Or x y) = "(" ++ show x ++ " || " ++ show y ++ ")"
show (Impl x y) = "(" ++ show x ++ " ==> " ++ show y ++ ")"
show (Xor x y) = "(" ++ show x ++ " xor " ++ show y ++ ")"
show Pi = "pi"
show (Sqrt x) = "(sqrt " ++ show x ++ ")"
show (Exp x) = "(exp " ++ show x ++ ")"
show (Sin x) = "(sin " ++ show x ++ ")"
show (Cos x) = "(cos " ++ show x ++ ")"
show (Tan x) = "(tan " ++ show x ++ ")"
show (Asin x) = "(arcsin " ++ show x ++ ")"
show (Acos x) = "(arccos " ++ show x ++ ")"
show (Atan x) = "(arctan " ++ show x ++ ")"
show (ToReal x) = "(to_real " ++ show x ++ ")"
show (ToInt x) = "(to_int " ++ show x ++ ")"
show (IsInt x) = "(is_int " ++ show x ++ ")"
show (Ite p t f) = "(ite " ++ show p ++ " " ++ show t ++ " " ++ show f ++ ")"
show (BvNot x) = "(not " ++ show x ++ ")"
show (BvAnd x y) = "(" ++ show x ++ " && " ++ show y ++ ")"
show (BvOr x y) = "(" ++ show x ++ " || " ++ show y ++ ")"
show (BvXor x y) = "(" ++ show x ++ " xor " ++ show y ++ ")"
show (BvNand x y) = "(" ++ show x ++ " nand " ++ show y ++ ")"
show (BvNor x y) = "(" ++ show x ++ " nor " ++ show y ++ ")"
show (BvNeg x) = "(- " ++ show x ++ ")"
show (BvAdd x y) = "(" ++ show x ++ " + " ++ show y ++ ")"
show (BvSub x y) = "(" ++ show x ++ " - " ++ show y ++ ")"
show (BvMul x y) = "(" ++ show x ++ " * " ++ show y ++ ")"
show (BvuDiv x y) = "(" ++ show x ++ " udiv " ++ show y ++ ")"
show (BvuRem x y) = "(" ++ show x ++ " urem " ++ show y ++ ")"
show (BvShL x y) = "(" ++ show x ++ " bvshl " ++ show y ++ ")"
show (BvLShR x y) = "(" ++ show x ++ " bvlshr " ++ show y ++ ")"
show (BvConcat x y) = "(" ++ show x ++ " bvconcat " ++ show y ++ ")"
show (BvRotL i x) = "(" ++ show x ++ " bvrotl " ++ show (natVal i) ++ ")"
show (BvRotR i x) = "(" ++ show x ++ " bvrotr " ++ show (natVal i) ++ ")"
show (BvuLT x y) = "(" ++ show x ++ " bvult " ++ show y ++ ")"
show (BvuLTHE x y) = "(" ++ show x ++ " bvule " ++ show y ++ ")"
show (BvuGTHE x y) = "(" ++ show x ++ " bvuge " ++ show y ++ ")"
show (BvuGT x y) = "(" ++ show x ++ " bvugt " ++ show y ++ ")"
show (ForAll (Just qv) f) = "(forall " ++ show qv ++ ": " ++ show (f (Var qv)) ++ ")"
show (ForAll Nothing f) = "(forall var_-1: " ++ show (f (Var (SMTVar (-1)))) ++ ")"
show (Exists (Just qv) f) = "(exists " ++ show qv ++ ": " ++ show (f (Var qv)) ++ ")"
show (Exists Nothing f) = "(exists var_-1: " ++ show (f (Var (SMTVar (-1)))) ++ ")"