--------------------------------------------------------------------------------

{-# LANGUAGE ExistentialQuantification, GADTs, LambdaCase #-}
{-# LANGUAGE Safe #-}

module Copilot.Theorem.IL.Spec
  ( Type (..)
  , Op1  (..)
  , Op2  (..)
  , SeqId
  , SeqIndex (..)
  , SeqDescr (..)
  , VarDescr (..)
  , Expr (..)
  , IL (..)
  , PropId
  , typeOf
  , _n_
  , _n_plus
  , evalAt
  ) where

import Data.Map (Map)
import Data.Function (on)

--------------------------------------------------------------------------------

type SeqId    =  String

data SeqIndex = Fixed Integer | Var Integer
  deriving (SeqIndex -> SeqIndex -> Bool
(SeqIndex -> SeqIndex -> Bool)
-> (SeqIndex -> SeqIndex -> Bool) -> Eq SeqIndex
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SeqIndex -> SeqIndex -> Bool
$c/= :: SeqIndex -> SeqIndex -> Bool
== :: SeqIndex -> SeqIndex -> Bool
$c== :: SeqIndex -> SeqIndex -> Bool
Eq, Eq SeqIndex
Eq SeqIndex
-> (SeqIndex -> SeqIndex -> Ordering)
-> (SeqIndex -> SeqIndex -> Bool)
-> (SeqIndex -> SeqIndex -> Bool)
-> (SeqIndex -> SeqIndex -> Bool)
-> (SeqIndex -> SeqIndex -> Bool)
-> (SeqIndex -> SeqIndex -> SeqIndex)
-> (SeqIndex -> SeqIndex -> SeqIndex)
-> Ord SeqIndex
SeqIndex -> SeqIndex -> Bool
SeqIndex -> SeqIndex -> Ordering
SeqIndex -> SeqIndex -> SeqIndex
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: SeqIndex -> SeqIndex -> SeqIndex
$cmin :: SeqIndex -> SeqIndex -> SeqIndex
max :: SeqIndex -> SeqIndex -> SeqIndex
$cmax :: SeqIndex -> SeqIndex -> SeqIndex
>= :: SeqIndex -> SeqIndex -> Bool
$c>= :: SeqIndex -> SeqIndex -> Bool
> :: SeqIndex -> SeqIndex -> Bool
$c> :: SeqIndex -> SeqIndex -> Bool
<= :: SeqIndex -> SeqIndex -> Bool
$c<= :: SeqIndex -> SeqIndex -> Bool
< :: SeqIndex -> SeqIndex -> Bool
$c< :: SeqIndex -> SeqIndex -> Bool
compare :: SeqIndex -> SeqIndex -> Ordering
$ccompare :: SeqIndex -> SeqIndex -> Ordering
$cp1Ord :: Eq SeqIndex
Ord, Int -> SeqIndex -> ShowS
[SeqIndex] -> ShowS
SeqIndex -> String
(Int -> SeqIndex -> ShowS)
-> (SeqIndex -> String) -> ([SeqIndex] -> ShowS) -> Show SeqIndex
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SeqIndex] -> ShowS
$cshowList :: [SeqIndex] -> ShowS
show :: SeqIndex -> String
$cshow :: SeqIndex -> String
showsPrec :: Int -> SeqIndex -> ShowS
$cshowsPrec :: Int -> SeqIndex -> ShowS
Show)

data Type = Bool  | Real
  | SBV8 | SBV16 | SBV32 | SBV64
  | BV8  | BV16 | BV32 | BV64
  deriving (Type -> Type -> Bool
(Type -> Type -> Bool) -> (Type -> Type -> Bool) -> Eq Type
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Type -> Type -> Bool
$c/= :: Type -> Type -> Bool
== :: Type -> Type -> Bool
$c== :: Type -> Type -> Bool
Eq, Eq Type
Eq Type
-> (Type -> Type -> Ordering)
-> (Type -> Type -> Bool)
-> (Type -> Type -> Bool)
-> (Type -> Type -> Bool)
-> (Type -> Type -> Bool)
-> (Type -> Type -> Type)
-> (Type -> Type -> Type)
-> Ord Type
Type -> Type -> Bool
Type -> Type -> Ordering
Type -> Type -> Type
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Type -> Type -> Type
$cmin :: Type -> Type -> Type
max :: Type -> Type -> Type
$cmax :: Type -> Type -> Type
>= :: Type -> Type -> Bool
$c>= :: Type -> Type -> Bool
> :: Type -> Type -> Bool
$c> :: Type -> Type -> Bool
<= :: Type -> Type -> Bool
$c<= :: Type -> Type -> Bool
< :: Type -> Type -> Bool
$c< :: Type -> Type -> Bool
compare :: Type -> Type -> Ordering
$ccompare :: Type -> Type -> Ordering
$cp1Ord :: Eq Type
Ord)

instance Show Type where
  show :: Type -> String
show = \case
    Type
Bool  -> String
"Bool"
    Type
Real  -> String
"Real"
    Type
SBV8  -> String
"SBV8"
    Type
SBV16 -> String
"SBV16"
    Type
SBV32 -> String
"SBV32"
    Type
SBV64 -> String
"SBV64"
    Type
BV8   -> String
"BV8"
    Type
BV16  -> String
"BV16"
    Type
BV32  -> String
"BV32"
    Type
BV64  -> String
"BV64"

data Expr
  = ConstB Bool
  | ConstR Double
  | ConstI Type Integer
  | Ite    Type Expr Expr Expr
  | Op1    Type Op1 Expr
  | Op2    Type Op2 Expr Expr
  | SVal   Type SeqId SeqIndex
  | FunApp Type String [Expr]
  deriving (Expr -> Expr -> Bool
(Expr -> Expr -> Bool) -> (Expr -> Expr -> Bool) -> Eq Expr
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Expr -> Expr -> Bool
$c/= :: Expr -> Expr -> Bool
== :: Expr -> Expr -> Bool
$c== :: Expr -> Expr -> Bool
Eq, Eq Expr
Eq Expr
-> (Expr -> Expr -> Ordering)
-> (Expr -> Expr -> Bool)
-> (Expr -> Expr -> Bool)
-> (Expr -> Expr -> Bool)
-> (Expr -> Expr -> Bool)
-> (Expr -> Expr -> Expr)
-> (Expr -> Expr -> Expr)
-> Ord Expr
Expr -> Expr -> Bool
Expr -> Expr -> Ordering
Expr -> Expr -> Expr
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Expr -> Expr -> Expr
$cmin :: Expr -> Expr -> Expr
max :: Expr -> Expr -> Expr
$cmax :: Expr -> Expr -> Expr
>= :: Expr -> Expr -> Bool
$c>= :: Expr -> Expr -> Bool
> :: Expr -> Expr -> Bool
$c> :: Expr -> Expr -> Bool
<= :: Expr -> Expr -> Bool
$c<= :: Expr -> Expr -> Bool
< :: Expr -> Expr -> Bool
$c< :: Expr -> Expr -> Bool
compare :: Expr -> Expr -> Ordering
$ccompare :: Expr -> Expr -> Ordering
$cp1Ord :: Eq Expr
Ord, Int -> Expr -> ShowS
[Expr] -> ShowS
Expr -> String
(Int -> Expr -> ShowS)
-> (Expr -> String) -> ([Expr] -> ShowS) -> Show Expr
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Expr] -> ShowS
$cshowList :: [Expr] -> ShowS
show :: Expr -> String
$cshow :: Expr -> String
showsPrec :: Int -> Expr -> ShowS
$cshowsPrec :: Int -> Expr -> ShowS
Show)

--------------------------------------------------------------------------------

data VarDescr = VarDescr
  { VarDescr -> String
varName :: String
  , VarDescr -> Type
varType :: Type
  , VarDescr -> [Type]
args    :: [Type]
  }

instance Eq VarDescr where
  == :: VarDescr -> VarDescr -> Bool
(==) = String -> String -> Bool
forall a. Eq a => a -> a -> Bool
(==) (String -> String -> Bool)
-> (VarDescr -> String) -> VarDescr -> VarDescr -> Bool
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` VarDescr -> String
varName

instance Ord VarDescr where
  compare :: VarDescr -> VarDescr -> Ordering
compare = String -> String -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (String -> String -> Ordering)
-> (VarDescr -> String) -> VarDescr -> VarDescr -> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` VarDescr -> String
varName

--------------------------------------------------------------------------------

type PropId = String

data SeqDescr = SeqDescr
  { SeqDescr -> String
seqId    :: SeqId
  , SeqDescr -> Type
seqType  :: Type
  }

data IL = IL
  { IL -> [Expr]
modelInit   :: [Expr]
  , IL -> [Expr]
modelRec    :: [Expr]
  , IL -> Map String ([Expr], Expr)
properties  :: Map PropId ([Expr], Expr)
  , IL -> Bool
inductive   :: Bool
  }

--------------------------------------------------------------------------------

data Op1 = Not | Neg | Abs | Exp | Sqrt | Log | Sin | Tan | Cos | Asin | Atan
         | Acos | Sinh | Tanh | Cosh | Asinh | Atanh | Acosh
         deriving (Op1 -> Op1 -> Bool
(Op1 -> Op1 -> Bool) -> (Op1 -> Op1 -> Bool) -> Eq Op1
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Op1 -> Op1 -> Bool
$c/= :: Op1 -> Op1 -> Bool
== :: Op1 -> Op1 -> Bool
$c== :: Op1 -> Op1 -> Bool
Eq, Eq Op1
Eq Op1
-> (Op1 -> Op1 -> Ordering)
-> (Op1 -> Op1 -> Bool)
-> (Op1 -> Op1 -> Bool)
-> (Op1 -> Op1 -> Bool)
-> (Op1 -> Op1 -> Bool)
-> (Op1 -> Op1 -> Op1)
-> (Op1 -> Op1 -> Op1)
-> Ord Op1
Op1 -> Op1 -> Bool
Op1 -> Op1 -> Ordering
Op1 -> Op1 -> Op1
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Op1 -> Op1 -> Op1
$cmin :: Op1 -> Op1 -> Op1
max :: Op1 -> Op1 -> Op1
$cmax :: Op1 -> Op1 -> Op1
>= :: Op1 -> Op1 -> Bool
$c>= :: Op1 -> Op1 -> Bool
> :: Op1 -> Op1 -> Bool
$c> :: Op1 -> Op1 -> Bool
<= :: Op1 -> Op1 -> Bool
$c<= :: Op1 -> Op1 -> Bool
< :: Op1 -> Op1 -> Bool
$c< :: Op1 -> Op1 -> Bool
compare :: Op1 -> Op1 -> Ordering
$ccompare :: Op1 -> Op1 -> Ordering
$cp1Ord :: Eq Op1
Ord)

data Op2 = Eq | And | Or | Le | Lt | Ge | Gt | Add | Sub | Mul | Mod | Fdiv | Pow
         deriving (Op2 -> Op2 -> Bool
(Op2 -> Op2 -> Bool) -> (Op2 -> Op2 -> Bool) -> Eq Op2
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Op2 -> Op2 -> Bool
$c/= :: Op2 -> Op2 -> Bool
== :: Op2 -> Op2 -> Bool
$c== :: Op2 -> Op2 -> Bool
Eq, Eq Op2
Eq Op2
-> (Op2 -> Op2 -> Ordering)
-> (Op2 -> Op2 -> Bool)
-> (Op2 -> Op2 -> Bool)
-> (Op2 -> Op2 -> Bool)
-> (Op2 -> Op2 -> Bool)
-> (Op2 -> Op2 -> Op2)
-> (Op2 -> Op2 -> Op2)
-> Ord Op2
Op2 -> Op2 -> Bool
Op2 -> Op2 -> Ordering
Op2 -> Op2 -> Op2
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Op2 -> Op2 -> Op2
$cmin :: Op2 -> Op2 -> Op2
max :: Op2 -> Op2 -> Op2
$cmax :: Op2 -> Op2 -> Op2
>= :: Op2 -> Op2 -> Bool
$c>= :: Op2 -> Op2 -> Bool
> :: Op2 -> Op2 -> Bool
$c> :: Op2 -> Op2 -> Bool
<= :: Op2 -> Op2 -> Bool
$c<= :: Op2 -> Op2 -> Bool
< :: Op2 -> Op2 -> Bool
$c< :: Op2 -> Op2 -> Bool
compare :: Op2 -> Op2 -> Ordering
$ccompare :: Op2 -> Op2 -> Ordering
$cp1Ord :: Eq Op2
Ord)

-------------------------------------------------------------------------------

instance Show Op1 where
  show :: Op1 -> String
show Op1
op = case Op1
op of
    Op1
Neg   -> String
"-"
    Op1
Not   -> String
"not"
    Op1
Abs   -> String
"abs"
    Op1
Exp   -> String
"exp"
    Op1
Sqrt  -> String
"sqrt"
    Op1
Log   -> String
"log"
    Op1
Sin   -> String
"sin"
    Op1
Tan   -> String
"tan"
    Op1
Cos   -> String
"cos"
    Op1
Asin  -> String
"asin"
    Op1
Atan  -> String
"atan"
    Op1
Acos  -> String
"acos"
    Op1
Sinh  -> String
"sinh"
    Op1
Tanh  -> String
"tanh"
    Op1
Cosh  -> String
"cosh"
    Op1
Asinh -> String
"asinh"
    Op1
Atanh -> String
"atanh"
    Op1
Acosh -> String
"acosh"

instance Show Op2 where
  show :: Op2 -> String
show Op2
op = case Op2
op of
    Op2
And  -> String
"and"
    Op2
Or   -> String
"or"

    Op2
Add  -> String
"+"
    Op2
Sub  -> String
"-"
    Op2
Mul  -> String
"*"

    Op2
Mod  -> String
"mod"

    Op2
Fdiv -> String
"/"

    Op2
Pow  -> String
"^"

    Op2
Eq   -> String
"="

    Op2
Le   -> String
"<="
    Op2
Ge   -> String
">="
    Op2
Lt   -> String
"<"
    Op2
Gt   -> String
">"

-------------------------------------------------------------------------------

typeOf :: Expr -> Type
typeOf :: Expr -> Type
typeOf Expr
e = case Expr
e of
  ConstB Bool
_       -> Type
Bool
  ConstR Double
_       -> Type
Real
  ConstI Type
t Integer
_     -> Type
t
  Ite    Type
t Expr
_ Expr
_ Expr
_ -> Type
t
  Op1    Type
t Op1
_ Expr
_   -> Type
t
  Op2    Type
t Op2
_ Expr
_ Expr
_ -> Type
t
  SVal   Type
t String
_ SeqIndex
_   -> Type
t
  FunApp Type
t String
_ [Expr]
_   -> Type
t

_n_ :: SeqIndex
_n_ :: SeqIndex
_n_ = Integer -> SeqIndex
Var Integer
0

_n_plus :: (Integral a) => a -> SeqIndex
_n_plus :: a -> SeqIndex
_n_plus a
d = Integer -> SeqIndex
Var (a -> Integer
forall a. Integral a => a -> Integer
toInteger a
d)

evalAt :: SeqIndex -> Expr -> Expr
evalAt :: SeqIndex -> Expr -> Expr
evalAt SeqIndex
_ e :: Expr
e@(ConstB Bool
_) = Expr
e
evalAt SeqIndex
_ e :: Expr
e@(ConstR Double
_) = Expr
e
evalAt SeqIndex
_ e :: Expr
e@(ConstI Type
_ Integer
_) = Expr
e
evalAt SeqIndex
i (Op1 Type
t Op1
op Expr
e) = Type -> Op1 -> Expr -> Expr
Op1 Type
t Op1
op (SeqIndex -> Expr -> Expr
evalAt SeqIndex
i Expr
e)
evalAt SeqIndex
i (Op2 Type
t Op2
op Expr
e1 Expr
e2) = Type -> Op2 -> Expr -> Expr -> Expr
Op2 Type
t Op2
op (SeqIndex -> Expr -> Expr
evalAt SeqIndex
i Expr
e1) (SeqIndex -> Expr -> Expr
evalAt SeqIndex
i Expr
e2)
evalAt SeqIndex
i (Ite Type
t Expr
c Expr
e1 Expr
e2) = Type -> Expr -> Expr -> Expr -> Expr
Ite Type
t (SeqIndex -> Expr -> Expr
evalAt SeqIndex
i Expr
c) (SeqIndex -> Expr -> Expr
evalAt SeqIndex
i Expr
e1) (SeqIndex -> Expr -> Expr
evalAt SeqIndex
i Expr
e2)
evalAt SeqIndex
i (FunApp Type
t String
name [Expr]
args) = Type -> String -> [Expr] -> Expr
FunApp Type
t String
name ([Expr] -> Expr) -> [Expr] -> Expr
forall a b. (a -> b) -> a -> b
$ (Expr -> Expr) -> [Expr] -> [Expr]
forall a b. (a -> b) -> [a] -> [b]
map (\Expr
e -> SeqIndex -> Expr -> Expr
evalAt SeqIndex
i Expr
e) [Expr]
args

evalAt SeqIndex
_ e :: Expr
e@(SVal Type
_ String
_ (Fixed Integer
_)) = Expr
e
evalAt (Fixed Integer
n) (SVal Type
t String
s (Var Integer
d)) = Type -> String -> SeqIndex -> Expr
SVal Type
t String
s (Integer -> SeqIndex
Fixed (Integer -> SeqIndex) -> Integer -> SeqIndex
forall a b. (a -> b) -> a -> b
$ Integer
n Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
d)
evalAt (Var   Integer
k) (SVal Type
t String
s (Var Integer
d)) = Type -> String -> SeqIndex -> Expr
SVal Type
t String
s (Integer -> SeqIndex
Var   (Integer -> SeqIndex) -> Integer -> SeqIndex
forall a b. (a -> b) -> a -> b
$ Integer
k Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
d)

--------------------------------------------------------------------------------