{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
module Language.Drasil.Expr.Class (
  ExprC(..),
  frac, recip_,
  square, half,
  oneHalf, oneThird,
  apply1, apply2
) where

import Prelude hiding (sqrt, log, sin, cos, tan, exp)

import Control.Lens ((^.))

import Language.Drasil.Symbol
import Language.Drasil.Expr.Lang
import Language.Drasil.Literal.Lang
import Language.Drasil.Space (DomainDesc(..), RTopology(..), RealInterval)
import Language.Drasil.Classes (IsArgumentName)
import qualified Language.Drasil.ModelExpr.Lang as M
import Language.Drasil.Literal.Class (LiteralC(..))
import Language.Drasil.UID (HasUID(..))

-- TODO: figure out which ones can be moved outside of the ExprC class

-- | Smart constructor for fractions.
frac :: (ExprC r, LiteralC r) => Integer -> Integer -> r
frac :: Integer -> Integer -> r
frac n :: Integer
n d :: Integer
d = Integer -> r
forall r. LiteralC r => Integer -> r
exactDbl Integer
n r -> r -> r
forall r. ExprC r => r -> r -> r
$/ Integer -> r
forall r. LiteralC r => Integer -> r
exactDbl Integer
d

-- | Smart constructor for rational expressions (only in 1/x form).
recip_ :: (ExprC r, LiteralC r) => r -> r
recip_ :: r -> r
recip_ denom :: r
denom = Integer -> r
forall r. LiteralC r => Integer -> r
exactDbl 1 r -> r -> r
forall r. ExprC r => r -> r -> r
$/ r
denom

-- | Smart constructor to square a function.
square :: (ExprC r, LiteralC r) => r -> r
square :: r -> r
square x :: r
x = r
x r -> r -> r
forall r. ExprC r => r -> r -> r
$^ Integer -> r
forall r. LiteralC r => Integer -> r
exactDbl 2

-- | Smart constructor to half a function exactly.
half :: (ExprC r, LiteralC r) => r -> r
half :: r -> r
half x :: r
x = r
x r -> r -> r
forall r. ExprC r => r -> r -> r
$/ Integer -> r
forall r. LiteralC r => Integer -> r
exactDbl 2

-- | 1/2, as an expression.
oneHalf :: (ExprC r, LiteralC r) => r
oneHalf :: r
oneHalf = Integer -> Integer -> r
forall r. (ExprC r, LiteralC r) => Integer -> Integer -> r
frac 1 2

-- | 1/3rd, as an expression.
oneThird :: (ExprC r, LiteralC r) => r
oneThird :: r
oneThird = Integer -> Integer -> r
forall r. (ExprC r, LiteralC r) => Integer -> Integer -> r
frac 1 3

-- | Similar to 'apply', but converts second argument into 'Symbol's.
apply1 :: (ExprC r, HasUID f, HasSymbol f, HasUID a, HasSymbol a) => f -> a -> r
apply1 :: f -> a -> r
apply1 f :: f
f a :: a
a = f -> [r] -> r
forall r f. (ExprC r, HasUID f, HasSymbol f) => f -> [r] -> r
apply f
f [a -> r
forall r c. (ExprC r, HasUID c, HasSymbol c) => c -> r
sy a
a]

-- | Similar to 'apply', but the applied function takes two parameters (which are both 'Symbol's).
apply2 :: (ExprC r, HasUID f, HasSymbol f, HasUID a, HasSymbol a, HasUID b, HasSymbol b) 
    => f -> a -> b -> r
apply2 :: f -> a -> b -> r
apply2 f :: f
f a :: a
a b :: b
b = f -> [r] -> r
forall r f. (ExprC r, HasUID f, HasSymbol f) => f -> [r] -> r
apply f
f [a -> r
forall r c. (ExprC r, HasUID c, HasSymbol c) => c -> r
sy a
a, b -> r
forall r c. (ExprC r, HasUID c, HasSymbol c) => c -> r
sy b
b]

class ExprC r where
  infixr 8 $^
  infixl 7 $/
  infixr 4 $=
  infixr 9 $&&
  infixr 9 $||
  
  lit :: Literal -> r

  -- * Binary Operators
  
  ($=), ($!=) :: r -> r -> r
  
  -- | Smart constructor for ordering two equations.
  ($<), ($>), ($<=), ($>=) :: r -> r -> r
  
  -- | Smart constructor for the dot product of two equations.
  ($.) :: r -> r -> r
  
  -- | Add two expressions (Integers).
  addI :: r -> r -> r
  
  -- | Add two expressions (Real numbers).
  addRe :: r -> r -> r
  
  -- | Multiply two expressions (Integers).
  mulI :: r -> r -> r
  
  -- | Multiply two expressions (Real numbers).
  mulRe :: r -> r -> r
  
  ($-), ($/), ($^) :: r -> r -> r
  
  ($=>), ($<=>) :: r -> r -> r
  
  ($&&), ($||) :: r -> r -> r
  
  -- | Smart constructor for taking the absolute value of an expression.
  abs_ :: r -> r
  
  -- | Smart constructor for negating an expression.
  neg :: r -> r 
  
  -- | Smart constructor to take the log of an expression.
  log :: r -> r
  
  -- | Smart constructor to take the ln of an expression.
  ln :: r -> r
  
  -- | Smart constructor to take the square root of an expression.
  sqrt :: r -> r
  
  -- | Smart constructor to apply sin to an expression.
  sin :: r -> r
  
  -- | Smart constructor to apply cos to an expression.
  cos :: r -> r 
  
  -- | Smart constructor to apply tan to an expression.
  tan :: r -> r
  
  -- | Smart constructor to apply sec to an expression.
  sec :: r -> r 
  
  -- | Smart constructor to apply csc to an expression.
  csc :: r -> r
  
  -- | Smart constructor to apply cot to an expression.
  cot :: r -> r 
  
  -- | Smart constructor to apply arcsin to an expression.
  arcsin :: r -> r 
  
  -- | Smart constructor to apply arccos to an expression.
  arccos :: r -> r 
  
  -- | Smart constructor to apply arctan to an expression.
  arctan :: r -> r 
  
  -- | Smart constructor for the exponential (base e) function.
  exp :: r -> r
  
  -- | Smart constructor for calculating the dimension of a vector.
  dim :: r -> r
  
  -- | Smart constructor for calculating the normal form of a vector.
  norm :: r -> r
  
  -- | Smart constructor for negating vectors.
  negVec :: r -> r
  
  -- | Smart constructor for applying logical negation to an expression.
  not_ :: r -> r
  
  -- | Smart constructor for indexing.
  idx :: r -> r -> r
  
  -- | Smart constructor for the summation, product, and integral functions over an interval.
  defint, defsum, defprod :: Symbol -> r -> r -> r -> r
  
  -- | Smart constructor for 'real interval' membership.
  realInterval :: HasUID c => c -> RealInterval r r -> r
  
  -- | Euclidean function : takes a vector and returns the sqrt of the sum-of-squares.
  euclidean :: [r] -> r
  
-- TODO:  sum' :: (Num a, Foldable t) => t a -> a
-- TODO:  sum' = foldr1 (+)
    
  -- | Smart constructor to cross product two expressions.
  cross :: r -> r -> r
  
  -- | Smart constructor for case statements with a complete set of cases.
  completeCase :: [(r, r)] -> r
  
  -- | Smart constructor for case statements with an incomplete set of cases.
  incompleteCase :: [(r, r)] -> r
  
  -- | Create a matrix.
  -- TODO: Re-work later.
  matrix :: [[r]] -> r

  -- TODO: The 3 below smart constructors can be re-built above without needing to be inside of this typeclass definition.

  -- | Create a two-by-two matrix from four given values. For example:
  --
  -- >>> m2x2 1 2 3 4
  -- [ [1,2],
  --   [3,4] ]
  m2x2 :: r -> r -> r -> r -> r
  
  -- | Create a 2D vector (a matrix with two rows, one column). First argument is placed above the second.
  vec2D :: r -> r -> r
  
  -- | Creates a diagonal two-by-two matrix. For example:
  --
  -- >>> dgnl2x2 1 2
  -- [ [1, 0],
  --   [0, 2] ]
  dgnl2x2 :: r -> r -> r
  
  -- 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 :: (HasUID f, HasSymbol f) => f -> [r] -> r
  
  -- | Similar to 'apply', but takes a relation to apply to 'FCall'.
  applyWithNamedArgs :: (HasUID f, HasSymbol f, HasUID a, IsArgumentName a) => f 
    -> [r] -> [(a, r)] -> r
  
  -- Note how |sy| 'enforces' having a symbol
  -- | Create an 'Expr' from a 'Symbol'ic Chunk.
  sy :: (HasUID c, HasSymbol c) => c -> r

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

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

  -- | Create a two-by-two matrix from four given values. For example:
  --
  -- >>> m2x2 1 2 3 4
  -- [ [1,2],
  --   [3,4] ]
  m2x2 :: Expr -> Expr -> Expr -> Expr -> Expr
m2x2 a :: Expr
a b :: Expr
b c :: Expr
c d :: Expr
d = [[Expr]] -> Expr
forall r. ExprC r => [[r]] -> r
matrix [[Expr
a,Expr
b],[Expr
c,Expr
d]]
  
  -- | Create a 2D vector (a matrix with two rows, one column). First argument is placed above the second.
  vec2D :: Expr -> Expr -> Expr
vec2D a :: Expr
a b :: Expr
b    = [[Expr]] -> Expr
forall r. ExprC r => [[r]] -> r
matrix [[Expr
a],[Expr
b]]
  
  -- | Creates a diagonal two-by-two matrix. For example:
  --
  -- >>> dgnl2x2 1 2
  -- [ [1, 0],
  --   [0, 2] ]
  dgnl2x2 :: Expr -> Expr -> Expr
dgnl2x2 a :: Expr
a  = Expr -> Expr -> Expr -> Expr -> Expr
forall r. ExprC r => r -> r -> r -> r -> r
m2x2 Expr
a (Integer -> Expr
forall r. LiteralC r => Integer -> r
int 0) (Integer -> Expr
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 -> [Expr] -> Expr
apply f :: f
f ps :: [Expr]
ps = UID -> [Expr] -> [(UID, Expr)] -> Expr
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) [Expr]
ps []
  
  -- | Similar to 'apply', but takes a relation to apply to 'FCall'.
  applyWithNamedArgs :: f -> [Expr] -> [(a, Expr)] -> Expr
applyWithNamedArgs f :: f
f ps :: [Expr]
ps ns :: [(a, Expr)]
ns = UID -> [Expr] -> [(UID, Expr)] -> Expr
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) [Expr]
ps ([UID] -> [Expr] -> [(UID, Expr)]
forall a b. [a] -> [b] -> [(a, b)]
zip (((a, Expr) -> UID) -> [(a, Expr)] -> [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, Expr) -> a) -> (a, Expr) -> UID
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a, Expr) -> a
forall a b. (a, b) -> a
fst) [(a, Expr)]
ns) 
    (((a, Expr) -> Expr) -> [(a, Expr)] -> [Expr]
forall a b. (a -> b) -> [a] -> [b]
map (a, Expr) -> Expr
forall a b. (a, b) -> b
snd [(a, Expr)]
ns))
  
  -- Note how |sy| 'enforces' having a symbol
  -- | Create an 'Expr' from a 'Symbol'ic Chunk.
  sy :: c -> Expr
sy x :: c
x = UID -> Expr
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)
  
instance ExprC M.ModelExpr where
  lit :: Literal -> ModelExpr
lit = Literal -> ModelExpr
M.Lit

  -- | Smart constructor for equating two expressions.
  $= :: ModelExpr -> ModelExpr -> ModelExpr
($=)  = EqBinOp -> ModelExpr -> ModelExpr -> ModelExpr
M.EqBinaryOp EqBinOp
M.Eq
  -- | Smart constructor for showing that two expressions are not equal.
  $!= :: ModelExpr -> ModelExpr -> ModelExpr
($!=) = EqBinOp -> ModelExpr -> ModelExpr -> ModelExpr
M.EqBinaryOp EqBinOp
M.NEq

  -- | Smart constructor for ordering two equations.
  -- | Less than.
  $< :: ModelExpr -> ModelExpr -> ModelExpr
($<)  = OrdBinOp -> ModelExpr -> ModelExpr -> ModelExpr
M.OrdBinaryOp OrdBinOp
M.Lt
  -- | Greater than.
  $> :: ModelExpr -> ModelExpr -> ModelExpr
($>)  = OrdBinOp -> ModelExpr -> ModelExpr -> ModelExpr
M.OrdBinaryOp OrdBinOp
M.Gt
  -- | Less than or equal to.
  $<= :: ModelExpr -> ModelExpr -> ModelExpr
($<=) = OrdBinOp -> ModelExpr -> ModelExpr -> ModelExpr
M.OrdBinaryOp OrdBinOp
M.LEq
  -- | Greater than or equal to.
  $>= :: ModelExpr -> ModelExpr -> ModelExpr
($>=) = OrdBinOp -> ModelExpr -> ModelExpr -> ModelExpr
M.OrdBinaryOp OrdBinOp
M.GEq

  -- | Smart constructor for the dot product of two equations.
  $. :: ModelExpr -> ModelExpr -> ModelExpr
($.) = VVNBinOp -> ModelExpr -> ModelExpr -> ModelExpr
M.VVNBinaryOp VVNBinOp
M.Dot

  -- | Add two expressions (Integers).
  addI :: ModelExpr -> ModelExpr -> ModelExpr
addI l :: ModelExpr
l (M.Lit (Int 0)) = ModelExpr
l
  addI (M.Lit (Int 0)) r :: ModelExpr
r = ModelExpr
r
  addI (M.AssocA M.AddI l :: [ModelExpr]
l) (M.AssocA M.AddI r :: [ModelExpr]
r) = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.AddI ([ModelExpr]
l [ModelExpr] -> [ModelExpr] -> [ModelExpr]
forall a. [a] -> [a] -> [a]
++ [ModelExpr]
r)
  addI (M.AssocA M.AddI l :: [ModelExpr]
l) r :: ModelExpr
r = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.AddI ([ModelExpr]
l [ModelExpr] -> [ModelExpr] -> [ModelExpr]
forall a. [a] -> [a] -> [a]
++ [ModelExpr
r])
  addI l :: ModelExpr
l (M.AssocA M.AddI r :: [ModelExpr]
r) = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.AddI (ModelExpr
l ModelExpr -> [ModelExpr] -> [ModelExpr]
forall a. a -> [a] -> [a]
: [ModelExpr]
r)
  addI l :: ModelExpr
l r :: ModelExpr
r = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.AddI [ModelExpr
l, ModelExpr
r]

  -- | Add two expressions (Real numbers).
  addRe :: ModelExpr -> ModelExpr -> ModelExpr
addRe l :: ModelExpr
l (M.Lit (Dbl 0))      = ModelExpr
l
  addRe (M.Lit (Dbl 0)) r :: ModelExpr
r      = ModelExpr
r
  addRe l :: ModelExpr
l (M.Lit (ExactDbl 0)) = ModelExpr
l
  addRe (M.Lit (ExactDbl 0)) r :: ModelExpr
r = ModelExpr
r
  addRe (M.AssocA M.AddRe l :: [ModelExpr]
l) (M.AssocA M.AddRe r :: [ModelExpr]
r) = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.AddRe ([ModelExpr]
l [ModelExpr] -> [ModelExpr] -> [ModelExpr]
forall a. [a] -> [a] -> [a]
++ [ModelExpr]
r)
  addRe (M.AssocA M.AddRe l :: [ModelExpr]
l) r :: ModelExpr
r = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.AddRe ([ModelExpr]
l [ModelExpr] -> [ModelExpr] -> [ModelExpr]
forall a. [a] -> [a] -> [a]
++ [ModelExpr
r])
  addRe l :: ModelExpr
l (M.AssocA M.AddRe r :: [ModelExpr]
r) = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.AddRe (ModelExpr
l ModelExpr -> [ModelExpr] -> [ModelExpr]
forall a. a -> [a] -> [a]
: [ModelExpr]
r)
  addRe l :: ModelExpr
l r :: ModelExpr
r = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.AddRe [ModelExpr
l, ModelExpr
r]

  -- | Multiply two expressions (Integers).
  mulI :: ModelExpr -> ModelExpr -> ModelExpr
mulI l :: ModelExpr
l (M.Lit (Int 1)) = ModelExpr
l
  mulI (M.Lit (Int 1)) r :: ModelExpr
r = ModelExpr
r
  mulI (M.AssocA M.MulI l :: [ModelExpr]
l) (M.AssocA M.MulI r :: [ModelExpr]
r) = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.MulI ([ModelExpr]
l [ModelExpr] -> [ModelExpr] -> [ModelExpr]
forall a. [a] -> [a] -> [a]
++ [ModelExpr]
r)
  mulI (M.AssocA M.MulI l :: [ModelExpr]
l) r :: ModelExpr
r = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.MulI ([ModelExpr]
l [ModelExpr] -> [ModelExpr] -> [ModelExpr]
forall a. [a] -> [a] -> [a]
++ [ModelExpr
r])
  mulI l :: ModelExpr
l (M.AssocA M.MulI r :: [ModelExpr]
r) = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.MulI (ModelExpr
l ModelExpr -> [ModelExpr] -> [ModelExpr]
forall a. a -> [a] -> [a]
: [ModelExpr]
r)
  mulI l :: ModelExpr
l r :: ModelExpr
r = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.MulI [ModelExpr
l, ModelExpr
r]

  -- | Multiply two expressions (Real numbers).
  mulRe :: ModelExpr -> ModelExpr -> ModelExpr
mulRe l :: ModelExpr
l (M.Lit (Dbl 1))      = ModelExpr
l
  mulRe (M.Lit (Dbl 1)) r :: ModelExpr
r      = ModelExpr
r
  mulRe l :: ModelExpr
l (M.Lit (ExactDbl 1)) = ModelExpr
l
  mulRe (M.Lit (ExactDbl 1)) r :: ModelExpr
r = ModelExpr
r
  mulRe (M.AssocA M.MulRe l :: [ModelExpr]
l) (M.AssocA M.MulRe r :: [ModelExpr]
r) = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.MulRe ([ModelExpr]
l [ModelExpr] -> [ModelExpr] -> [ModelExpr]
forall a. [a] -> [a] -> [a]
++ [ModelExpr]
r)
  mulRe (M.AssocA M.MulRe l :: [ModelExpr]
l) r :: ModelExpr
r = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.MulRe ([ModelExpr]
l [ModelExpr] -> [ModelExpr] -> [ModelExpr]
forall a. [a] -> [a] -> [a]
++ [ModelExpr
r])
  mulRe l :: ModelExpr
l (M.AssocA M.MulRe r :: [ModelExpr]
r) = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.MulRe (ModelExpr
l ModelExpr -> [ModelExpr] -> [ModelExpr]
forall a. a -> [a] -> [a]
: [ModelExpr]
r)
  mulRe l :: ModelExpr
l r :: ModelExpr
r = AssocArithOper -> [ModelExpr] -> ModelExpr
M.AssocA AssocArithOper
M.MulRe [ModelExpr
l, ModelExpr
r]

  -- | Smart constructor for subtracting two expressions.
  $- :: ModelExpr -> ModelExpr -> ModelExpr
($-) = ArithBinOp -> ModelExpr -> ModelExpr -> ModelExpr
M.ArithBinaryOp ArithBinOp
M.Subt
  -- | Smart constructor for dividing two expressions.
  $/ :: ModelExpr -> ModelExpr -> ModelExpr
($/) = ArithBinOp -> ModelExpr -> ModelExpr -> ModelExpr
M.ArithBinaryOp ArithBinOp
M.Frac
  -- | Smart constructor for rasing the first expression to the power of the second.
  $^ :: ModelExpr -> ModelExpr -> ModelExpr
($^) = ArithBinOp -> ModelExpr -> ModelExpr -> ModelExpr
M.ArithBinaryOp ArithBinOp
M.Pow

  -- | Smart constructor to show that one expression implies the other (conditional operator).
  $=> :: ModelExpr -> ModelExpr -> ModelExpr
($=>)  = BoolBinOp -> ModelExpr -> ModelExpr -> ModelExpr
M.BoolBinaryOp BoolBinOp
M.Impl
  -- | Smart constructor to show that an expression exists if and only if another expression exists (biconditional operator).
  $<=> :: ModelExpr -> ModelExpr -> ModelExpr
($<=>) = BoolBinOp -> ModelExpr -> ModelExpr -> ModelExpr
M.BoolBinaryOp BoolBinOp
M.Iff

  -- | Smart constructor for the boolean /and/ operator.
  a :: ModelExpr
a $&& :: ModelExpr -> ModelExpr -> ModelExpr
$&& b :: ModelExpr
b = AssocBoolOper -> [ModelExpr] -> ModelExpr
M.AssocB AssocBoolOper
M.And [ModelExpr
a, ModelExpr
b]
  -- | Smart constructor for the boolean /or/ operator.
  a :: ModelExpr
a $|| :: ModelExpr -> ModelExpr -> ModelExpr
$|| b :: ModelExpr
b = AssocBoolOper -> [ModelExpr] -> ModelExpr
M.AssocB AssocBoolOper
M.Or  [ModelExpr
a, ModelExpr
b]

  -- | Smart constructor for taking the absolute value of an expression.
  abs_ :: ModelExpr -> ModelExpr
abs_ = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Abs

  -- | Smart constructor for negating an expression.
  neg :: ModelExpr -> ModelExpr
neg = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Neg

  -- | Smart constructor to take the log of an expression.
  log :: ModelExpr -> ModelExpr
log = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Log

  -- | Smart constructor to take the ln of an expression.
  ln :: ModelExpr -> ModelExpr
ln = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Ln

  -- | Smart constructor to take the square root of an expression.
  sqrt :: ModelExpr -> ModelExpr
sqrt = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Sqrt

  -- | Smart constructor to apply sin to an expression.
  sin :: ModelExpr -> ModelExpr
sin = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Sin

  -- | Smart constructor to apply cos to an expression.
  cos :: ModelExpr -> ModelExpr
cos = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Cos

  -- | Smart constructor to apply tan to an expression.
  tan :: ModelExpr -> ModelExpr
tan = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Tan

  -- | Smart constructor to apply sec to an expression.
  sec :: ModelExpr -> ModelExpr
sec = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Sec

  -- | Smart constructor to apply csc to an expression.
  csc :: ModelExpr -> ModelExpr
csc = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Csc

  -- | Smart constructor to apply cot to an expression.
  cot :: ModelExpr -> ModelExpr
cot = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Cot

  -- | Smart constructor to apply arcsin to an expression.
  arcsin :: ModelExpr -> ModelExpr
arcsin = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Arcsin

  -- | Smart constructor to apply arccos to an expression.
  arccos :: ModelExpr -> ModelExpr
arccos = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Arccos

  -- | Smart constructor to apply arctan to an expression.
  arctan :: ModelExpr -> ModelExpr
arctan = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Arctan

  -- | Smart constructor for the exponential (base e) function.
  exp :: ModelExpr -> ModelExpr
exp = UFunc -> ModelExpr -> ModelExpr
M.UnaryOp UFunc
M.Exp

  -- | Smart constructor for calculating the dimension of a vector.
  dim :: ModelExpr -> ModelExpr
dim = UFuncVN -> ModelExpr -> ModelExpr
M.UnaryOpVN UFuncVN
M.Dim

  -- | Smart constructor for calculating the normal form of a vector.
  norm :: ModelExpr -> ModelExpr
norm = UFuncVN -> ModelExpr -> ModelExpr
M.UnaryOpVN UFuncVN
M.Norm

  -- | Smart constructor for negating vectors.
  negVec :: ModelExpr -> ModelExpr
negVec = UFuncVV -> ModelExpr -> ModelExpr
M.UnaryOpVV UFuncVV
M.NegV

  -- | Smart constructor for applying logical negation to an expression.
  not_ :: ModelExpr -> ModelExpr
not_ = UFuncB -> ModelExpr -> ModelExpr
M.UnaryOpB UFuncB
M.Not

  -- | Smart constructor for indexing.
  idx :: ModelExpr -> ModelExpr -> ModelExpr
idx = LABinOp -> ModelExpr -> ModelExpr -> ModelExpr
M.LABinaryOp LABinOp
M.Index

  -- | Integrate over some expression with bounds (∫).
  defint :: Symbol -> ModelExpr -> ModelExpr -> ModelExpr -> ModelExpr
defint v :: Symbol
v low :: ModelExpr
low high :: ModelExpr
high = AssocArithOper
-> DomainDesc 'Discrete ModelExpr ModelExpr
-> ModelExpr
-> ModelExpr
forall (t :: RTopology).
AssocArithOper
-> DomainDesc t ModelExpr ModelExpr -> ModelExpr -> ModelExpr
M.Operator AssocArithOper
M.AddRe (Symbol
-> RTopology
-> ModelExpr
-> ModelExpr
-> DomainDesc 'Discrete ModelExpr ModelExpr
forall a b.
Symbol -> RTopology -> a -> b -> DomainDesc 'Discrete a b
BoundedDD Symbol
v RTopology
Continuous ModelExpr
low ModelExpr
high)

  -- | Sum over some expression with bounds (∑).
  defsum :: Symbol -> ModelExpr -> ModelExpr -> ModelExpr -> ModelExpr
defsum v :: Symbol
v low :: ModelExpr
low high :: ModelExpr
high = AssocArithOper
-> DomainDesc 'Discrete ModelExpr ModelExpr
-> ModelExpr
-> ModelExpr
forall (t :: RTopology).
AssocArithOper
-> DomainDesc t ModelExpr ModelExpr -> ModelExpr -> ModelExpr
M.Operator AssocArithOper
M.AddRe (Symbol
-> RTopology
-> ModelExpr
-> ModelExpr
-> DomainDesc 'Discrete ModelExpr ModelExpr
forall a b.
Symbol -> RTopology -> a -> b -> DomainDesc 'Discrete a b
BoundedDD Symbol
v RTopology
Discrete ModelExpr
low ModelExpr
high)

  -- | Product over some expression with bounds (∏).
  defprod :: Symbol -> ModelExpr -> ModelExpr -> ModelExpr -> ModelExpr
defprod v :: Symbol
v low :: ModelExpr
low high :: ModelExpr
high = AssocArithOper
-> DomainDesc 'Discrete ModelExpr ModelExpr
-> ModelExpr
-> ModelExpr
forall (t :: RTopology).
AssocArithOper
-> DomainDesc t ModelExpr ModelExpr -> ModelExpr -> ModelExpr
M.Operator AssocArithOper
M.MulRe (Symbol
-> RTopology
-> ModelExpr
-> ModelExpr
-> DomainDesc 'Discrete ModelExpr ModelExpr
forall a b.
Symbol -> RTopology -> a -> b -> DomainDesc 'Discrete a b
BoundedDD Symbol
v RTopology
Discrete ModelExpr
low ModelExpr
high)

  -- | Smart constructor for 'real interval' membership.
  realInterval :: c -> RealInterval ModelExpr ModelExpr -> ModelExpr
realInterval c :: c
c = UID -> RealInterval ModelExpr ModelExpr -> ModelExpr
M.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 :: [ModelExpr] -> ModelExpr
euclidean = ModelExpr -> ModelExpr
forall r. ExprC r => r -> r
sqrt (ModelExpr -> ModelExpr)
-> ([ModelExpr] -> ModelExpr) -> [ModelExpr] -> ModelExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ModelExpr -> ModelExpr -> ModelExpr) -> [ModelExpr] -> ModelExpr
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldr1 ModelExpr -> ModelExpr -> ModelExpr
forall r. ExprC r => r -> r -> r
addRe ([ModelExpr] -> ModelExpr)
-> ([ModelExpr] -> [ModelExpr]) -> [ModelExpr] -> ModelExpr
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ModelExpr -> ModelExpr) -> [ModelExpr] -> [ModelExpr]
forall a b. (a -> b) -> [a] -> [b]
map ModelExpr -> ModelExpr
forall r. (ExprC r, LiteralC r) => r -> r
square

  -- | Smart constructor to cross product two expressions.
  cross :: ModelExpr -> ModelExpr -> ModelExpr
cross = VVVBinOp -> ModelExpr -> ModelExpr -> ModelExpr
M.VVVBinaryOp VVVBinOp
M.Cross

  -- | Smart constructor for case statements with a complete set of cases.
  completeCase :: [(ModelExpr, ModelExpr)] -> ModelExpr
completeCase = Completeness -> [(ModelExpr, ModelExpr)] -> ModelExpr
M.Case Completeness
Complete

  -- | Smart constructor for case statements with an incomplete set of cases.
  incompleteCase :: [(ModelExpr, ModelExpr)] -> ModelExpr
incompleteCase = Completeness -> [(ModelExpr, ModelExpr)] -> ModelExpr
M.Case Completeness
Incomplete

  matrix :: [[ModelExpr]] -> ModelExpr
matrix = [[ModelExpr]] -> ModelExpr
M.Matrix

  -- | Create a two-by-two matrix from four given values. For example:
  --
  -- >>> m2x2 1 2 3 4
  -- [ [1,2],
  --   [3,4] ]
  m2x2 :: ModelExpr -> ModelExpr -> ModelExpr -> ModelExpr -> ModelExpr
m2x2 a :: ModelExpr
a b :: ModelExpr
b c :: ModelExpr
c d :: ModelExpr
d = [[ModelExpr]] -> ModelExpr
forall r. ExprC r => [[r]] -> r
matrix [[ModelExpr
a,ModelExpr
b],[ModelExpr
c,ModelExpr
d]]

  -- | Create a 2D vector (a matrix with two rows, one column). First argument is placed above the second.
  vec2D :: ModelExpr -> ModelExpr -> ModelExpr
vec2D a :: ModelExpr
a b :: ModelExpr
b    = [[ModelExpr]] -> ModelExpr
forall r. ExprC r => [[r]] -> r
matrix [[ModelExpr
a],[ModelExpr
b]]

  -- | Creates a diagonal two-by-two matrix. For example:
  --
  -- >>> dgnl2x2 1 2
  -- [ [1, 0],
  --   [0, 2] ]
  dgnl2x2 :: ModelExpr -> ModelExpr -> ModelExpr
dgnl2x2 a :: ModelExpr
a  = ModelExpr -> ModelExpr -> ModelExpr -> ModelExpr -> ModelExpr
forall r. ExprC r => r -> r -> r -> r -> r
m2x2 ModelExpr
a (Integer -> ModelExpr
forall r. LiteralC r => Integer -> r
int 0) (Integer -> ModelExpr
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 -> [ModelExpr] -> ModelExpr
apply f :: f
f ps :: [ModelExpr]
ps = UID -> [ModelExpr] -> [(UID, ModelExpr)] -> ModelExpr
M.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) [ModelExpr]
ps []

  -- | Similar to 'apply', but takes a relation to apply to 'FCall'.
  applyWithNamedArgs :: f -> [ModelExpr] -> [(a, ModelExpr)] -> ModelExpr
applyWithNamedArgs f :: f
f ps :: [ModelExpr]
ps ns :: [(a, ModelExpr)]
ns = UID -> [ModelExpr] -> [(UID, ModelExpr)] -> ModelExpr
M.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) [ModelExpr]
ps ([UID] -> [ModelExpr] -> [(UID, ModelExpr)]
forall a b. [a] -> [b] -> [(a, b)]
zip (((a, ModelExpr) -> UID) -> [(a, ModelExpr)] -> [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, ModelExpr) -> a) -> (a, ModelExpr) -> UID
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a, ModelExpr) -> a
forall a b. (a, b) -> a
fst) [(a, ModelExpr)]
ns) 
    (((a, ModelExpr) -> ModelExpr) -> [(a, ModelExpr)] -> [ModelExpr]
forall a b. (a -> b) -> [a] -> [b]
map (a, ModelExpr) -> ModelExpr
forall a b. (a, b) -> b
snd [(a, ModelExpr)]
ns))

  -- Note how |sy| 'enforces' having a symbol
  -- | Create an 'Expr' from a 'Symbol'ic Chunk.
  sy :: c -> ModelExpr
sy x :: c
x = UID -> ModelExpr
M.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)