{-# LANGUAGE GADTs #-}

module Language.Drasil.Code.Expr where

import Language.Drasil
import Language.Drasil.Literal.Development
import Prelude hiding (sqrt)
import Control.Lens
import Language.Drasil.Expr.Development (Completeness(Complete, Incomplete))

-- * Operators (mostly binary)

-- | Arithmetic operators (fractional, power, and subtraction).
data ArithBinOp = Frac | Pow | Subt
  deriving ArithBinOp -> ArithBinOp -> Bool
(ArithBinOp -> ArithBinOp -> Bool)
-> (ArithBinOp -> ArithBinOp -> Bool) -> Eq ArithBinOp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ArithBinOp -> ArithBinOp -> Bool
$c/= :: ArithBinOp -> ArithBinOp -> Bool
== :: ArithBinOp -> ArithBinOp -> Bool
$c== :: ArithBinOp -> ArithBinOp -> Bool
Eq

-- | Equality operators (equal or not equal).
data EqBinOp = Eq | NEq
  deriving EqBinOp -> EqBinOp -> Bool
(EqBinOp -> EqBinOp -> Bool)
-> (EqBinOp -> EqBinOp -> Bool) -> Eq EqBinOp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: EqBinOp -> EqBinOp -> Bool
$c/= :: EqBinOp -> EqBinOp -> Bool
== :: EqBinOp -> EqBinOp -> Bool
$c== :: EqBinOp -> EqBinOp -> Bool
Eq

-- | Conditional and Biconditional operators (Expressions can imply
-- one another, or exist if and only if another expression exists).
data BoolBinOp = Impl | Iff
  deriving BoolBinOp -> BoolBinOp -> Bool
(BoolBinOp -> BoolBinOp -> Bool)
-> (BoolBinOp -> BoolBinOp -> Bool) -> Eq BoolBinOp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: BoolBinOp -> BoolBinOp -> Bool
$c/= :: BoolBinOp -> BoolBinOp -> Bool
== :: BoolBinOp -> BoolBinOp -> Bool
$c== :: BoolBinOp -> BoolBinOp -> Bool
Eq

-- | Index operator.
data LABinOp = Index
  deriving LABinOp -> LABinOp -> Bool
(LABinOp -> LABinOp -> Bool)
-> (LABinOp -> LABinOp -> Bool) -> Eq LABinOp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LABinOp -> LABinOp -> Bool
$c/= :: LABinOp -> LABinOp -> Bool
== :: LABinOp -> LABinOp -> Bool
$c== :: LABinOp -> LABinOp -> Bool
Eq

-- | Ordered binary operators (less than, greater than, less than or equal to, greater than or equal to).
data OrdBinOp = Lt | Gt | LEq | GEq
  deriving OrdBinOp -> OrdBinOp -> Bool
(OrdBinOp -> OrdBinOp -> Bool)
-> (OrdBinOp -> OrdBinOp -> Bool) -> Eq OrdBinOp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: OrdBinOp -> OrdBinOp -> Bool
$c/= :: OrdBinOp -> OrdBinOp -> Bool
== :: OrdBinOp -> OrdBinOp -> Bool
$c== :: OrdBinOp -> OrdBinOp -> Bool
Eq

-- | @Vector x Vector -> Vector@ binary operations (cross product).
data VVVBinOp = Cross
  deriving VVVBinOp -> VVVBinOp -> Bool
(VVVBinOp -> VVVBinOp -> Bool)
-> (VVVBinOp -> VVVBinOp -> Bool) -> Eq VVVBinOp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: VVVBinOp -> VVVBinOp -> Bool
$c/= :: VVVBinOp -> VVVBinOp -> Bool
== :: VVVBinOp -> VVVBinOp -> Bool
$c== :: VVVBinOp -> VVVBinOp -> Bool
Eq

-- | @Vector x Vector -> Number@ binary operations (dot product).
data VVNBinOp = Dot
  deriving VVNBinOp -> VVNBinOp -> Bool
(VVNBinOp -> VVNBinOp -> Bool)
-> (VVNBinOp -> VVNBinOp -> Bool) -> Eq VVNBinOp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: VVNBinOp -> VVNBinOp -> Bool
$c/= :: VVNBinOp -> VVNBinOp -> Bool
== :: VVNBinOp -> VVNBinOp -> Bool
$c== :: VVNBinOp -> VVNBinOp -> Bool
Eq

-- | Associative operators (adding and multiplication). Also specifies whether it is for integers or for real numbers.
data AssocArithOper = AddI | AddRe | MulI | MulRe
  deriving AssocArithOper -> AssocArithOper -> Bool
(AssocArithOper -> AssocArithOper -> Bool)
-> (AssocArithOper -> AssocArithOper -> Bool) -> Eq AssocArithOper
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AssocArithOper -> AssocArithOper -> Bool
$c/= :: AssocArithOper -> AssocArithOper -> Bool
== :: AssocArithOper -> AssocArithOper -> Bool
$c== :: AssocArithOper -> AssocArithOper -> Bool
Eq

-- | Associative boolean operators (and, or).
data AssocBoolOper = And | Or
  deriving AssocBoolOper -> AssocBoolOper -> Bool
(AssocBoolOper -> AssocBoolOper -> Bool)
-> (AssocBoolOper -> AssocBoolOper -> Bool) -> Eq AssocBoolOper
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: AssocBoolOper -> AssocBoolOper -> Bool
$c/= :: AssocBoolOper -> AssocBoolOper -> Bool
== :: AssocBoolOper -> AssocBoolOper -> Bool
$c== :: AssocBoolOper -> AssocBoolOper -> Bool
Eq

-- | Unary functions (abs, log, ln, sin, etc.).
data UFunc = Abs | Log | Ln | Sin | Cos | Tan | Sec | Csc | Cot | Arcsin
  | Arccos | Arctan | Exp | Sqrt | Neg
  deriving UFunc -> UFunc -> Bool
(UFunc -> UFunc -> Bool) -> (UFunc -> UFunc -> Bool) -> Eq UFunc
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UFunc -> UFunc -> Bool
$c/= :: UFunc -> UFunc -> Bool
== :: UFunc -> UFunc -> Bool
$c== :: UFunc -> UFunc -> Bool
Eq

-- | @Bool -> Bool@ operators.
data UFuncB = Not
  deriving UFuncB -> UFuncB -> Bool
(UFuncB -> UFuncB -> Bool)
-> (UFuncB -> UFuncB -> Bool) -> Eq UFuncB
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UFuncB -> UFuncB -> Bool
$c/= :: UFuncB -> UFuncB -> Bool
== :: UFuncB -> UFuncB -> Bool
$c== :: UFuncB -> UFuncB -> Bool
Eq

-- | @Vector -> Vector@ operators.
data UFuncVV = NegV
  deriving UFuncVV -> UFuncVV -> Bool
(UFuncVV -> UFuncVV -> Bool)
-> (UFuncVV -> UFuncVV -> Bool) -> Eq UFuncVV
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UFuncVV -> UFuncVV -> Bool
$c/= :: UFuncVV -> UFuncVV -> Bool
== :: UFuncVV -> UFuncVV -> Bool
$c== :: UFuncVV -> UFuncVV -> Bool
Eq

-- | @Vector -> Number@ operators.
data UFuncVN = Norm | Dim
  deriving UFuncVN -> UFuncVN -> Bool
(UFuncVN -> UFuncVN -> Bool)
-> (UFuncVN -> UFuncVN -> Bool) -> Eq UFuncVN
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UFuncVN -> UFuncVN -> Bool
$c/= :: UFuncVN -> UFuncVN -> Bool
== :: UFuncVN -> UFuncVN -> Bool
$c== :: UFuncVN -> UFuncVN -> Bool
Eq

-- * CodeExpr

-- | Expression language where all terms also denote a term in GOOL
--   (i.e. translation is total and meaning preserving).
data CodeExpr where
  -- | Brings literals into the expression language.
  Lit      :: Literal -> CodeExpr

  -- | Takes an associative arithmetic operator with a list of expressions.
  AssocA   :: AssocArithOper -> [CodeExpr] -> CodeExpr
  -- | Takes an associative boolean operator with a list of expressions.
  AssocB   :: AssocBoolOper  -> [CodeExpr] -> CodeExpr
  -- | C stands for "Chunk", for referring to a chunk in an expression.
  --   Implicitly assumes that the chunk has a symbol.
  C        :: UID -> CodeExpr
  -- | A function call accepts a list of parameters and a list of named parameters.
  --   For example
  --
  --   * F(x) is (FCall F [x] []).
  --   * F(x,y) would be (FCall F [x,y]).
  --   * F(x,n=y) would be (FCall F [x] [(n,y)]).
  FCall    :: UID -> [CodeExpr] -> [(UID, CodeExpr)] -> CodeExpr
  -- | Actor creation given 'UID', parameters, and named parameters.
  New      :: UID -> [CodeExpr] -> [(UID, CodeExpr)] -> CodeExpr
  -- | Message an actor:
  --
  --   * 1st 'UID' is the actor,
  --   * 2nd 'UID' is the method.
  Message  :: UID -> UID -> [CodeExpr] -> [(UID, CodeExpr)] -> CodeExpr
  -- | Access a field of an actor:
  --
  --   * 1st 'UID' is the actor,
  --   * 2nd 'UID' is the field.
  Field    :: UID -> UID -> CodeExpr
  -- | For multi-case expressions, each pair represents one case.
  Case     :: Completeness -> [(CodeExpr, CodeExpr)] -> CodeExpr
  -- | Represents a matrix of expressions.
  Matrix   :: [[CodeExpr]] -> CodeExpr
  
  -- | Unary operation for most functions (eg. sin, cos, log, etc.).
  UnaryOp       :: UFunc -> CodeExpr -> CodeExpr
  -- | Unary operation for @Bool -> Bool@ operations.
  UnaryOpB      :: UFuncB -> CodeExpr -> CodeExpr
  -- | Unary operation for @Vector -> Vector@ operations.
  UnaryOpVV     :: UFuncVV -> CodeExpr -> CodeExpr
  -- | Unary operation for @Vector -> Number@ operations.
  UnaryOpVN     :: UFuncVN -> CodeExpr -> CodeExpr

  -- | Binary operator for arithmetic between expressions (fractional, power, and subtraction).
  ArithBinaryOp :: ArithBinOp -> CodeExpr -> CodeExpr -> CodeExpr
  -- | Binary operator for boolean operators (implies, iff).
  BoolBinaryOp  :: BoolBinOp -> CodeExpr -> CodeExpr -> CodeExpr
  -- | Binary operator for equality between expressions.
  EqBinaryOp    :: EqBinOp -> CodeExpr -> CodeExpr -> CodeExpr
  -- | Binary operator for indexing two expressions.
  LABinaryOp    :: LABinOp -> CodeExpr -> CodeExpr -> CodeExpr
  -- | Binary operator for ordering expressions (less than, greater than, etc.).
  OrdBinaryOp   :: OrdBinOp -> CodeExpr -> CodeExpr -> CodeExpr
  -- | Binary operator for @Vector x Vector -> Vector@ operations (cross product).
  VVVBinaryOp   :: VVVBinOp -> CodeExpr -> CodeExpr -> CodeExpr
  -- | Binary operator for @Vector x Vector -> Number@ operations (dot product).
  VVNBinaryOp   :: VVNBinOp -> CodeExpr -> CodeExpr -> CodeExpr

  -- | Operators are generalized arithmetic operators over a 'DomainDesc'
  --   of an 'Expr'.  Could be called BigOp.
  --   ex: Summation is represented via 'Add' over a discrete domain.
  Operator :: AssocArithOper -> DiscreteDomainDesc CodeExpr CodeExpr -> CodeExpr -> CodeExpr
  -- | The expression is an element of a space.
  -- IsIn     :: Expr -> Space -> Expr
  -- | A different kind of 'IsIn'. A 'UID' is an element of an interval.
  RealI    :: UID -> RealInterval CodeExpr CodeExpr -> CodeExpr

instance LiteralC CodeExpr where
  str :: String -> CodeExpr
str      = Literal -> CodeExpr
Lit (Literal -> CodeExpr) -> (String -> Literal) -> String -> CodeExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Literal
forall r. LiteralC r => String -> r
str
  int :: Integer -> CodeExpr
int      = Literal -> CodeExpr
Lit (Literal -> CodeExpr)
-> (Integer -> Literal) -> Integer -> CodeExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Literal
forall r. LiteralC r => Integer -> r
int
  dbl :: Double -> CodeExpr
dbl      = Literal -> CodeExpr
Lit (Literal -> CodeExpr) -> (Double -> Literal) -> Double -> CodeExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Double -> Literal
forall r. LiteralC r => Double -> r
dbl
  exactDbl :: Integer -> CodeExpr
exactDbl = Literal -> CodeExpr
Lit (Literal -> CodeExpr)
-> (Integer -> Literal) -> Integer -> CodeExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Literal
forall r. LiteralC r => Integer -> r
exactDbl
  perc :: Integer -> Integer -> CodeExpr
perc l :: Integer
l r :: Integer
r = Literal -> CodeExpr
Lit (Literal -> CodeExpr) -> Literal -> CodeExpr
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Literal
forall r. LiteralC r => Integer -> Integer -> r
perc Integer
l Integer
r


instance ExprC CodeExpr where
  lit :: Literal -> CodeExpr
lit = Literal -> CodeExpr
Lit

  -- | Smart constructor for equating two expressions.
  $= :: CodeExpr -> CodeExpr -> CodeExpr
($=)  = EqBinOp -> CodeExpr -> CodeExpr -> CodeExpr
EqBinaryOp EqBinOp
Eq
  -- | Smart constructor for showing that two expressions are not equal.
  $!= :: CodeExpr -> CodeExpr -> CodeExpr
($!=) = EqBinOp -> CodeExpr -> CodeExpr -> CodeExpr
EqBinaryOp EqBinOp
NEq
  
  -- | Smart constructor for ordering two equations.
  -- | Less than.
  $< :: CodeExpr -> CodeExpr -> CodeExpr
($<)  = OrdBinOp -> CodeExpr -> CodeExpr -> CodeExpr
OrdBinaryOp OrdBinOp
Lt
  -- | Greater than.
  $> :: CodeExpr -> CodeExpr -> CodeExpr
($>)  = OrdBinOp -> CodeExpr -> CodeExpr -> CodeExpr
OrdBinaryOp OrdBinOp
Gt
  -- | Less than or equal to.
  $<= :: CodeExpr -> CodeExpr -> CodeExpr
($<=) = OrdBinOp -> CodeExpr -> CodeExpr -> CodeExpr
OrdBinaryOp OrdBinOp
LEq
  -- | Greater than or equal to.
  $>= :: CodeExpr -> CodeExpr -> CodeExpr
($>=) = OrdBinOp -> CodeExpr -> CodeExpr -> CodeExpr
OrdBinaryOp OrdBinOp
GEq
  
  -- | Smart constructor for the dot product of two equations.
  $. :: CodeExpr -> CodeExpr -> CodeExpr
($.) = VVNBinOp -> CodeExpr -> CodeExpr -> CodeExpr
VVNBinaryOp VVNBinOp
Dot
  
  -- | Add two expressions (Integers).
  addI :: CodeExpr -> CodeExpr -> CodeExpr
addI l :: CodeExpr
l (Lit (Int 0)) = CodeExpr
l
  addI (Lit (Int 0)) r :: CodeExpr
r = CodeExpr
r
  addI (AssocA AddI l :: [CodeExpr]
l) (AssocA AddI r :: [CodeExpr]
r) = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
AddI ([CodeExpr]
l [CodeExpr] -> [CodeExpr] -> [CodeExpr]
forall a. [a] -> [a] -> [a]
++ [CodeExpr]
r)
  addI (AssocA AddI l :: [CodeExpr]
l) r :: CodeExpr
r = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
AddI ([CodeExpr]
l [CodeExpr] -> [CodeExpr] -> [CodeExpr]
forall a. [a] -> [a] -> [a]
++ [CodeExpr
r])
  addI l :: CodeExpr
l (AssocA AddI r :: [CodeExpr]
r) = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
AddI (CodeExpr
l CodeExpr -> [CodeExpr] -> [CodeExpr]
forall a. a -> [a] -> [a]
: [CodeExpr]
r)
  addI l :: CodeExpr
l r :: CodeExpr
r = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
AddI [CodeExpr
l, CodeExpr
r]
  
  -- | Add two expressions (Real numbers).
  addRe :: CodeExpr -> CodeExpr -> CodeExpr
addRe l :: CodeExpr
l (Lit (Dbl 0))= CodeExpr
l
  addRe (Lit(Dbl 0)) r :: CodeExpr
r      = CodeExpr
r
  addRe l :: CodeExpr
l (Lit (ExactDbl 0)) = CodeExpr
l
  addRe (Lit (ExactDbl 0)) r :: CodeExpr
r = CodeExpr
r
  addRe (AssocA AddRe l :: [CodeExpr]
l) (AssocA AddRe r :: [CodeExpr]
r) = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
AddRe ([CodeExpr]
l [CodeExpr] -> [CodeExpr] -> [CodeExpr]
forall a. [a] -> [a] -> [a]
++ [CodeExpr]
r)
  addRe (AssocA AddRe l :: [CodeExpr]
l) r :: CodeExpr
r = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
AddRe ([CodeExpr]
l [CodeExpr] -> [CodeExpr] -> [CodeExpr]
forall a. [a] -> [a] -> [a]
++ [CodeExpr
r])
  addRe l :: CodeExpr
l (AssocA AddRe r :: [CodeExpr]
r) = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
AddRe (CodeExpr
l CodeExpr -> [CodeExpr] -> [CodeExpr]
forall a. a -> [a] -> [a]
: [CodeExpr]
r)
  addRe l :: CodeExpr
l r :: CodeExpr
r = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
AddRe [CodeExpr
l, CodeExpr
r]
  
  -- | Multiply two expressions (Integers).
  mulI :: CodeExpr -> CodeExpr -> CodeExpr
mulI l :: CodeExpr
l (Lit (Int 1)) = CodeExpr
l
  mulI (Lit (Int 1)) r :: CodeExpr
r = CodeExpr
r
  mulI (AssocA MulI l :: [CodeExpr]
l) (AssocA MulI r :: [CodeExpr]
r) = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
MulI ([CodeExpr]
l [CodeExpr] -> [CodeExpr] -> [CodeExpr]
forall a. [a] -> [a] -> [a]
++ [CodeExpr]
r)
  mulI (AssocA MulI l :: [CodeExpr]
l) r :: CodeExpr
r = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
MulI ([CodeExpr]
l [CodeExpr] -> [CodeExpr] -> [CodeExpr]
forall a. [a] -> [a] -> [a]
++ [CodeExpr
r])
  mulI l :: CodeExpr
l (AssocA MulI r :: [CodeExpr]
r) = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
MulI (CodeExpr
l CodeExpr -> [CodeExpr] -> [CodeExpr]
forall a. a -> [a] -> [a]
: [CodeExpr]
r)
  mulI l :: CodeExpr
l r :: CodeExpr
r = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
MulI [CodeExpr
l, CodeExpr
r]
  
  -- | Multiply two expressions (Real numbers).
  mulRe :: CodeExpr -> CodeExpr -> CodeExpr
mulRe l :: CodeExpr
l (Lit (Dbl 1))      = CodeExpr
l
  mulRe (Lit (Dbl 1)) r :: CodeExpr
r      = CodeExpr
r
  mulRe l :: CodeExpr
l (Lit (ExactDbl 1)) = CodeExpr
l
  mulRe (Lit (ExactDbl 1)) r :: CodeExpr
r = CodeExpr
r
  mulRe (AssocA MulRe l :: [CodeExpr]
l) (AssocA MulRe r :: [CodeExpr]
r) = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
MulRe ([CodeExpr]
l [CodeExpr] -> [CodeExpr] -> [CodeExpr]
forall a. [a] -> [a] -> [a]
++ [CodeExpr]
r)
  mulRe (AssocA MulRe l :: [CodeExpr]
l) r :: CodeExpr
r = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
MulRe ([CodeExpr]
l [CodeExpr] -> [CodeExpr] -> [CodeExpr]
forall a. [a] -> [a] -> [a]
++ [CodeExpr
r])
  mulRe l :: CodeExpr
l (AssocA MulRe r :: [CodeExpr]
r) = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
MulRe (CodeExpr
l CodeExpr -> [CodeExpr] -> [CodeExpr]
forall a. a -> [a] -> [a]
: [CodeExpr]
r)
  mulRe l :: CodeExpr
l r :: CodeExpr
r = AssocArithOper -> [CodeExpr] -> CodeExpr
AssocA AssocArithOper
MulRe [CodeExpr
l, CodeExpr
r]
  
  -- | Smart constructor for subtracting two expressions.
  $- :: CodeExpr -> CodeExpr -> CodeExpr
($-) = ArithBinOp -> CodeExpr -> CodeExpr -> CodeExpr
ArithBinaryOp ArithBinOp
Subt
  -- | Smart constructor for dividing two expressions.
  $/ :: CodeExpr -> CodeExpr -> CodeExpr
($/) = ArithBinOp -> CodeExpr -> CodeExpr -> CodeExpr
ArithBinaryOp ArithBinOp
Frac
  -- | Smart constructor for rasing the first expression to the power of the second.
  $^ :: CodeExpr -> CodeExpr -> CodeExpr
($^) = ArithBinOp -> CodeExpr -> CodeExpr -> CodeExpr
ArithBinaryOp ArithBinOp
Pow
  
  -- | Smart constructor to show that one expression implies the other (conditional operator).
  $=> :: CodeExpr -> CodeExpr -> CodeExpr
($=>)  = BoolBinOp -> CodeExpr -> CodeExpr -> CodeExpr
BoolBinaryOp BoolBinOp
Impl
  -- | Smart constructor to show that an expression exists if and only if another expression exists (biconditional operator).
  $<=> :: CodeExpr -> CodeExpr -> CodeExpr
($<=>) = BoolBinOp -> CodeExpr -> CodeExpr -> CodeExpr
BoolBinaryOp BoolBinOp
Iff
  
  -- | Smart constructor for the boolean /and/ operator.
  a :: CodeExpr
a $&& :: CodeExpr -> CodeExpr -> CodeExpr
$&& b :: CodeExpr
b = AssocBoolOper -> [CodeExpr] -> CodeExpr
AssocB AssocBoolOper
And [CodeExpr
a, CodeExpr
b]
  -- | Smart constructor for the boolean /or/ operator.
  a :: CodeExpr
a $|| :: CodeExpr -> CodeExpr -> CodeExpr
$|| b :: CodeExpr
b = AssocBoolOper -> [CodeExpr] -> CodeExpr
AssocB AssocBoolOper
Or  [CodeExpr
a, CodeExpr
b]
  
  -- | Smart constructor for taking the absolute value of an expression.
  abs_ :: CodeExpr -> CodeExpr
abs_ = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Abs
  
  -- | Smart constructor for negating an expression.
  neg :: CodeExpr -> CodeExpr
neg = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Neg
  
  -- | Smart constructor to take the log of an expression.
  log :: CodeExpr -> CodeExpr
log = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Log
  
  -- | Smart constructor to take the ln of an expression.
  ln :: CodeExpr -> CodeExpr
ln = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Ln
  
  -- | Smart constructor to take the square root of an expression.
  sqrt :: CodeExpr -> CodeExpr
sqrt = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Sqrt
  
  -- | Smart constructor to apply sin to an expression.
  sin :: CodeExpr -> CodeExpr
sin = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Sin
  
  -- | Smart constructor to apply cos to an expression.
  cos :: CodeExpr -> CodeExpr
cos = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Cos
  
  -- | Smart constructor to apply tan to an expression.
  tan :: CodeExpr -> CodeExpr
tan = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Tan
  
  -- | Smart constructor to apply sec to an expression.
  sec :: CodeExpr -> CodeExpr
sec = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Sec
  
  -- | Smart constructor to apply csc to an expression.
  csc :: CodeExpr -> CodeExpr
csc = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Csc
  
  -- | Smart constructor to apply cot to an expression.
  cot :: CodeExpr -> CodeExpr
cot = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Cot
  
  -- | Smart constructor to apply arcsin to an expression.
  arcsin :: CodeExpr -> CodeExpr
arcsin = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Arcsin
  
  -- | Smart constructor to apply arccos to an expression.
  arccos :: CodeExpr -> CodeExpr
arccos = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Arccos
  
  -- | Smart constructor to apply arctan to an expression.
  arctan :: CodeExpr -> CodeExpr
arctan = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Arctan
  
  -- | Smart constructor for the exponential (base e) function.
  exp :: CodeExpr -> CodeExpr
exp = UFunc -> CodeExpr -> CodeExpr
UnaryOp UFunc
Exp
  
  -- | Smart constructor for calculating the dimension of a vector.
  dim :: CodeExpr -> CodeExpr
dim = UFuncVN -> CodeExpr -> CodeExpr
UnaryOpVN UFuncVN
Dim
  
  -- | Smart constructor for calculating the normal form of a vector.
  norm :: CodeExpr -> CodeExpr
norm = UFuncVN -> CodeExpr -> CodeExpr
UnaryOpVN UFuncVN
Norm
  
  -- | Smart constructor for negating vectors.
  negVec :: CodeExpr -> CodeExpr
negVec = UFuncVV -> CodeExpr -> CodeExpr
UnaryOpVV UFuncVV
NegV
  
  -- | Smart constructor for applying logical negation to an expression.
  not_ :: CodeExpr -> CodeExpr
not_ = UFuncB -> CodeExpr -> CodeExpr
UnaryOpB UFuncB
Not
  
  -- | Smart constructor for indexing.
  idx :: CodeExpr -> CodeExpr -> CodeExpr
idx = LABinOp -> CodeExpr -> CodeExpr -> CodeExpr
LABinaryOp LABinOp
Index
  
  -- | Integrate over some expression with bounds (∫).
  defint :: Symbol -> CodeExpr -> CodeExpr -> CodeExpr -> CodeExpr
defint v :: Symbol
v low :: CodeExpr
low high :: CodeExpr
high = AssocArithOper
-> DiscreteDomainDesc CodeExpr CodeExpr -> CodeExpr -> CodeExpr
Operator AssocArithOper
AddRe (Symbol
-> RTopology
-> CodeExpr
-> CodeExpr
-> DiscreteDomainDesc CodeExpr CodeExpr
forall a b.
Symbol -> RTopology -> a -> b -> DomainDesc 'Discrete a b
BoundedDD Symbol
v RTopology
Continuous CodeExpr
low CodeExpr
high)
  
  -- | Sum over some expression with bounds (∑).
  defsum :: Symbol -> CodeExpr -> CodeExpr -> CodeExpr -> CodeExpr
defsum v :: Symbol
v low :: CodeExpr
low high :: CodeExpr
high = AssocArithOper
-> DiscreteDomainDesc CodeExpr CodeExpr -> CodeExpr -> CodeExpr
Operator AssocArithOper
AddRe (Symbol
-> RTopology
-> CodeExpr
-> CodeExpr
-> DiscreteDomainDesc CodeExpr CodeExpr
forall a b.
Symbol -> RTopology -> a -> b -> DomainDesc 'Discrete a b
BoundedDD Symbol
v RTopology
Discrete CodeExpr
low CodeExpr
high)
  
  -- | Product over some expression with bounds (∏).
  defprod :: Symbol -> CodeExpr -> CodeExpr -> CodeExpr -> CodeExpr
defprod v :: Symbol
v low :: CodeExpr
low high :: CodeExpr
high = AssocArithOper
-> DiscreteDomainDesc CodeExpr CodeExpr -> CodeExpr -> CodeExpr
Operator AssocArithOper
MulRe (Symbol
-> RTopology
-> CodeExpr
-> CodeExpr
-> DiscreteDomainDesc CodeExpr CodeExpr
forall a b.
Symbol -> RTopology -> a -> b -> DomainDesc 'Discrete a b
BoundedDD Symbol
v RTopology
Discrete CodeExpr
low CodeExpr
high)
  
  -- | Smart constructor for 'real interval' membership.
  realInterval :: c -> RealInterval CodeExpr CodeExpr -> CodeExpr
realInterval c :: c
c = UID -> RealInterval CodeExpr CodeExpr -> CodeExpr
RealI (c
c c -> Getting UID c UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID c UID
forall c. HasUID c => Lens' c UID
uid)
  
  -- | Euclidean function : takes a vector and returns the sqrt of the sum-of-squares.
  euclidean :: [CodeExpr] -> CodeExpr
euclidean = CodeExpr -> CodeExpr
forall r. ExprC r => r -> r
sqrt (CodeExpr -> CodeExpr)
-> ([CodeExpr] -> CodeExpr) -> [CodeExpr] -> CodeExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CodeExpr -> CodeExpr -> CodeExpr) -> [CodeExpr] -> CodeExpr
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldr1 CodeExpr -> CodeExpr -> CodeExpr
forall r. ExprC r => r -> r -> r
addRe ([CodeExpr] -> CodeExpr)
-> ([CodeExpr] -> [CodeExpr]) -> [CodeExpr] -> CodeExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (CodeExpr -> CodeExpr) -> [CodeExpr] -> [CodeExpr]
forall a b. (a -> b) -> [a] -> [b]
map CodeExpr -> CodeExpr
forall r. (ExprC r, LiteralC r) => r -> r
square
  
  -- | Smart constructor to cross product two expressions.
  cross :: CodeExpr -> CodeExpr -> CodeExpr
cross = VVVBinOp -> CodeExpr -> CodeExpr -> CodeExpr
VVVBinaryOp VVVBinOp
Cross
  
  -- | Smart constructor for case statements with a complete set of cases.
  completeCase :: [(CodeExpr, CodeExpr)] -> CodeExpr
completeCase = Completeness -> [(CodeExpr, CodeExpr)] -> CodeExpr
Case Completeness
Complete
  
  -- | Smart constructor for case statements with an incomplete set of cases.
  incompleteCase :: [(CodeExpr, CodeExpr)] -> CodeExpr
incompleteCase = Completeness -> [(CodeExpr, CodeExpr)] -> CodeExpr
Case Completeness
Incomplete
  
  matrix :: [[CodeExpr]] -> CodeExpr
matrix = [[CodeExpr]] -> CodeExpr
Matrix

  -- | Create a two-by-two matrix from four given values. For example:
  --
  -- >>> m2x2 1 2 3 4
  -- [ [1,2],
  --   [3,4] ]
  m2x2 :: CodeExpr -> CodeExpr -> CodeExpr -> CodeExpr -> CodeExpr
m2x2 a :: CodeExpr
a b :: CodeExpr
b c :: CodeExpr
c d :: CodeExpr
d = [[CodeExpr]] -> CodeExpr
forall r. ExprC r => [[r]] -> r
matrix [[CodeExpr
a,CodeExpr
b],[CodeExpr
c,CodeExpr
d]]
  
  -- | Create a 2D vector (a matrix with two rows, one column). First argument is placed above the second.
  vec2D :: CodeExpr -> CodeExpr -> CodeExpr
vec2D a :: CodeExpr
a b :: CodeExpr
b    = [[CodeExpr]] -> CodeExpr
forall r. ExprC r => [[r]] -> r
matrix [[CodeExpr
a],[CodeExpr
b]]
  
  -- | Creates a diagonal two-by-two matrix. For example:
  --
  -- >>> dgnl2x2 1 2
  -- [ [1, 0],
  --   [0, 2] ]
  dgnl2x2 :: CodeExpr -> CodeExpr -> CodeExpr
dgnl2x2 a :: CodeExpr
a  = CodeExpr -> CodeExpr -> CodeExpr -> CodeExpr -> CodeExpr
forall r. ExprC r => r -> r -> r -> r -> r
m2x2 CodeExpr
a (Integer -> CodeExpr
forall r. LiteralC r => Integer -> r
int 0) (Integer -> CodeExpr
forall r. LiteralC r => Integer -> r
int 0)
  
  -- Some helper functions to do function application
  
  -- FIXME: These constructors should check that the UID is associated with a
  -- chunk that is actually callable.
  -- | Applies a given function with a list of parameters.
  apply :: f -> [CodeExpr] -> CodeExpr
apply f :: f
f ps :: [CodeExpr]
ps = UID -> [CodeExpr] -> [(UID, CodeExpr)] -> CodeExpr
FCall (f
f f -> Getting UID f UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID f UID
forall c. HasUID c => Lens' c UID
uid) [CodeExpr]
ps []
  
  -- | Similar to 'apply', but takes a relation to apply to 'FCall'.
  applyWithNamedArgs :: f -> [CodeExpr] -> [(a, CodeExpr)] -> CodeExpr
applyWithNamedArgs f :: f
f ps :: [CodeExpr]
ps ns :: [(a, CodeExpr)]
ns = UID -> [CodeExpr] -> [(UID, CodeExpr)] -> CodeExpr
FCall (f
f f -> Getting UID f UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID f UID
forall c. HasUID c => Lens' c UID
uid) [CodeExpr]
ps ([UID] -> [CodeExpr] -> [(UID, CodeExpr)]
forall a b. [a] -> [b] -> [(a, b)]
zip (((a, CodeExpr) -> UID) -> [(a, CodeExpr)] -> [UID]
forall a b. (a -> b) -> [a] -> [b]
map ((a -> Getting UID a UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID a UID
forall c. HasUID c => Lens' c UID
uid) (a -> UID) -> ((a, CodeExpr) -> a) -> (a, CodeExpr) -> UID
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a, CodeExpr) -> a
forall a b. (a, b) -> a
fst) [(a, CodeExpr)]
ns) 
    (((a, CodeExpr) -> CodeExpr) -> [(a, CodeExpr)] -> [CodeExpr]
forall a b. (a -> b) -> [a] -> [b]
map (a, CodeExpr) -> CodeExpr
forall a b. (a, b) -> b
snd [(a, CodeExpr)]
ns))
  
  -- Note how |sy| 'enforces' having a symbol
  -- | Create an 'Expr' from a 'Symbol'ic Chunk.
  sy :: c -> CodeExpr
sy x :: c
x = UID -> CodeExpr
C (c
x c -> Getting UID c UID -> UID
forall s a. s -> Getting a s a -> a
^. Getting UID c UID
forall c. HasUID c => Lens' c UID
uid)