Eq-1.0: EqManips/Types.hs
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE Rank2Types #-}
module EqManips.Types
( FormulaPrim( .. )
, Formula( .. )
-- | Tell that the formula is in form binop op [a,b ...]
, ListForm
-- | Tell that formula is in form Binop op [a,b]
, TreeForm
, hashOfFormula
, BinOperator( .. )
, UnOperator( .. )
, Entity( .. )
, binopString
, unopString
-- | Exported only to permit the main program to display
-- accurate help.
, binopDefs
-- | For more information about others unary operator,
-- refer to the link section.
, realUnopOperators
-- | To query associativity side
, AssocSide(..)
-- | Return type for associativity side
, OpAssoc( .. )
-- | Gain access to operator's priority
, Priority(.. )
, LeafNode( .. )
, OpProp( .. )
, OperatorText(..)
, MetaOperation( .. )
, Polynome( .. ), PolyCoeff( .. )
, coeffPredicate, polyCoeffCast
, foldf
, canDistributeOver
, distributeOver
, binOp, unOp, complex, meta
, app, summ, productt, derivate
, integrate, lambda, matrix, poly
, indexes, list
) where
import Data.Ord( comparing )
import Data.Monoid( Monoid( .. ), getSum )
import qualified Data.Monoid as Monoid
import qualified EqManips.ErrorMessages as Err
import Data.Bits
import Data.Ratio
import Data.List( foldl', foldl1' )
import Data.Maybe( fromJust )
import EqManips.Propreties
import {-# SOURCE #-} EqManips.Polynome()
import {-# SOURCE #-} EqManips.Renderer.Sexpr
-- | All Binary operators
data BinOperator =
-- | '+'
OpAdd
-- | '-'
| OpSub
-- | '*'
| OpMul
-- | '/'
| OpDiv
-- | '^'
| OpPow
| OpAnd -- ^ '&'
| OpOr -- ^ '|'
| OpEq -- ^ '='
| OpNe -- ^ '/='
| OpLt -- ^ '<'
| OpGt -- ^ '>'
| OpGe -- ^ '>='
| OpLe -- ^ '<='
| OpLazyAttrib -- ^ ':>'
| OpAttrib -- ^ ':='
| OpCons -- ^ '::'
deriving (Eq,Show,Enum)
-- | All `unary` operators are in there. some are mathematical
-- functions. They're present here, because it's easier to pattern
-- match them this way
data UnOperator =
OpNegate | OpAbs | OpSqrt
| OpSin | OpSinh | OpASin | OpASinh
| OpCos | OpCosh | OpACos | OpACosh
| OpTan | OpTanh | OpATan | OpATanh
| OpLn | OpLog | OpExp
| OpFactorial
| OpCeil | OpFloor | OpFrac
deriving (Eq, Show, Enum)
-- | Some entity which cannot be represented in other mannear
data Entity =
Pi
| Nabla
| Infinite
| Ellipsis -- ^ ... no value can be bound to it
deriving (Eq, Show, Ord, Enum)
data MetaOperation =
-- | Avoid an evaluation, replace itself by the
-- without touching it.
Hold
-- | Inverse of hold, whenever encountered in
-- evaluation, should force an evaluation.
| Force
| Expand -- ^ trigger an expend operation
| Cleanup -- ^ trigger a basic formula cleanup
| LambdaBuild -- ^ To generate a full blown Lambda
| Sort -- ^ To sort the formula
deriving (Eq, Show, Read, Enum)
type FloatingValue = Double
type HashResume = Int
-- | Main type manipulated by the software.
-- All relevant instances for numeric types
-- are provided for ease of use
data FormulaPrim =
Variable String
| NumEntity Entity
| Truth Bool
| CInteger Integer
| CFloat FloatingValue
| Fraction (Ratio Integer)
| Complex HashResume (FormulaPrim , FormulaPrim)
-- | To index nDimensional data
| Indexes HashResume FormulaPrim [FormulaPrim]
-- | Yay, adding list to the language
| List HashResume [FormulaPrim]
-- | FunName arguments
| App HashResume FormulaPrim [FormulaPrim]
-- | LowBound highbound expression
| Sum HashResume FormulaPrim FormulaPrim FormulaPrim
-- | LowBound highbound expression
| Product HashResume FormulaPrim FormulaPrim FormulaPrim
-- | Derivate expression withVar
| Derivate HashResume FormulaPrim FormulaPrim
-- | lowBound highBound expression dx
| Integrate HashResume FormulaPrim FormulaPrim FormulaPrim FormulaPrim
-- | -1 for example
| UnOp HashResume UnOperator FormulaPrim
-- | Represent a function. a function
-- can have many definitions. The applied
-- one must be the first in the list which
-- unify with the applied parameters.
| Lambda HashResume [( [FormulaPrim] {- clause args -}
, FormulaPrim {- clause body -})
] {- clauses -}
-- | f1 op f2
| BinOp HashResume BinOperator [FormulaPrim]
-- | Width, Height, all formulas
| Matrix HashResume Int Int [[FormulaPrim]]
-- | Form that can be used to make nice simplification.
| Poly HashResume Polynome
-- | Used for debug
| Block Int Int Int
-- | A meta operation is an operation used
-- by the sysem, but that doesn't appear in the
-- normal output.
| Meta HashResume MetaOperation FormulaPrim
deriving (Eq, Show)
--------------------------------------------------
---- Hash construction
--------------------------------------------------
hashOfFormula :: FormulaPrim -> HashResume
hashOfFormula (CInteger i) = fromIntegral i
hashOfFormula (Variable s) = sum $ map fromEnum s
hashOfFormula (NumEntity e) = fromEnum e
hashOfFormula (Truth True) = maxBound
hashOfFormula (Truth False) = minBound
hashOfFormula (CFloat f) = fromEnum f
hashOfFormula (Fraction frac) = fromIntegral (numerator frac)
+ fromIntegral (denominator frac)
hashOfFormula (Complex hash _) = hash
hashOfFormula (Indexes hash _ _) = hash
hashOfFormula (List hash _) = hash
hashOfFormula (App hash _ _) = hash
hashOfFormula (Sum hash _ _ _) = hash
hashOfFormula (Product hash _ _ _) = hash
hashOfFormula (Derivate hash _ _) = hash
hashOfFormula (Integrate hash _ _ _ _) = hash
hashOfFormula (UnOp hash _ _) = hash
hashOfFormula (Lambda hash _) = hash
hashOfFormula (BinOp hash _ _) = hash
hashOfFormula (Matrix hash _ _ _) = hash
hashOfFormula (Poly hash _) = hash
hashOfFormula (Block _ _ _) = 0
hashOfFormula (Meta hash _ _) = hash
listHasher :: [FormulaPrim] -> HashResume
listHasher = foldl' hasher 0
where hasher acc formula =
(acc `rotateL` 3) `xor` hashOfFormula formula
polyCoeffHash :: PolyCoeff -> HashResume
polyCoeffHash (CoeffFloat f) = truncate $ 1000 * f
polyCoeffHash (CoeffInt i) = fromInteger i
polyCoeffHash (CoeffRatio r) = 100 * (fromInteger $ numerator r)
+ (fromInteger $ denominator r)
polynomeHash :: Polynome -> HashResume
polynomeHash (PolyRest p) = polyCoeffHash p
polynomeHash (Polynome var coeffList) = varHash + coeffHash
where varHash = sum $ map fromEnum var
hasher acc (coeff, subPoly) =
(acc `rotateR` 2) `xor` ( polyCoeffHash coeff
+ polynomeHash subPoly )
coeffHash = foldl' hasher 0 coeffList
app :: FormulaPrim -> [FormulaPrim] -> FormulaPrim
app what lst = App hash what lst
where hash = (1 `shiftL` 3) `xor` (wHash `rotateL` 4) `xor` hashLst
wHash = hashOfFormula what
hashLst = listHasher lst
summ :: FormulaPrim -> FormulaPrim -> FormulaPrim -> FormulaPrim
summ a b c = Sum hash a b c
where hash = (0xFF `shiftL` 15) + listHasher [a, b, c]
productt :: FormulaPrim -> FormulaPrim -> FormulaPrim -> FormulaPrim
productt a b c = Product hash a b c
where hash = (0xFF `shiftL` 25) + listHasher [a, b, c]
derivate :: FormulaPrim -> FormulaPrim -> FormulaPrim
derivate what v = Derivate hash what v
where hash = (0xCA03 `shiftL` 10) + (hashWhat `rotateL` 16) + hashVar
hashWhat = hashOfFormula what
hashVar = hashOfFormula v
integrate :: FormulaPrim -> FormulaPrim -> FormulaPrim -> FormulaPrim -> FormulaPrim
integrate beg end what var = Integrate hash beg end what var
where hash = 0xF00000F00 + hashSub
hashSub = listHasher [beg, end, what, var]
lambda :: [([FormulaPrim], FormulaPrim)] -> FormulaPrim
lambda clauses = Lambda hash clauses
where hash = xor 14
$ foldr (\x acc -> (acc `rotateL` 2) + x) 0
[listHasher subs + hashOfFormula ap | (subs, ap) <- clauses]
matrix :: Int -> Int -> [[FormulaPrim]] -> FormulaPrim
matrix n m mlines = Matrix hash n m mlines
where hash = ((n * m) `shiftL` 4) + 0xFF + subHash
subHash = sum $ map listHasher mlines
poly :: Polynome -> FormulaPrim
poly createdPoly = Poly (polynomeHash createdPoly) createdPoly
binOp :: BinOperator -> [FormulaPrim] -> FormulaPrim
binOp op lst = BinOp hash op lst
where hash = (4 `xor` (hashOp `shiftL` 2)) + listHasher lst
hashOp = fromEnum op
unOp :: UnOperator -> FormulaPrim -> FormulaPrim
unOp op sub = UnOp hash op sub
where hash = (5 `xor` (hashOp `shiftL` 4)) + subHash
subHash = hashOfFormula sub
hashOp = fromEnum op
complex :: (FormulaPrim, FormulaPrim) -> FormulaPrim
complex (re, im) = Complex hash (re, im)
where hash = 7 + reHash + imHash `rotateR` 4
reHash = hashOfFormula re
imHash = hashOfFormula im
meta :: MetaOperation -> FormulaPrim -> FormulaPrim
meta op sub = Meta hash op sub
where hash = (6 `xor` (opHash `shiftL` 8)) + (subHash `rotateR` 4)
subHash = hashOfFormula sub
opHash = fromEnum op
indexes :: FormulaPrim -> [FormulaPrim] -> FormulaPrim
indexes (Indexes _initHash a b) lst = Indexes hash a $ b ++ lst
where hash = 0xAAAAAA `xor` (listHasher $ b ++ lst)
indexes a b = Indexes hash a b
where hash = 0xAAAAAA `xor` (listHasher b)
list :: [FormulaPrim] -> FormulaPrim
list lst = List hash lst
where hash = 0xBBBBBB `xor` listHasher lst
-- | Special binOp declaration used to merge two previous binary
-- operators. Update the hash rather than perform full recalculation.
binOpMerger :: BinOperator -> FormulaPrim -> FormulaPrim -> FormulaPrim
binOpMerger op (BinOp _ op1 lst1) (BinOp _ op2 lst2)
| op == op1 && op == op2 = binOp op $ lst1 ++ lst2
binOpMerger op (BinOp _ op1 lst1) node2
| op == op1 = binOp op $ lst1 ++ [node2]
binOpMerger op node1 (BinOp _ op2 lst2)
| op == op2 = binOp op $ node1 : lst2
binOpMerger op node1 node2 = binOp op [node1, node2]
-- | Type used to carry some meta information
-- with the type system.
-- - formula Form : how is handled the binop form
newtype Formula formulaForm = Formula { unTagFormula :: FormulaPrim }
deriving (Eq, {-Show,-} Ord)
-- | Type token for format of the form [a,b,c,d,e...]
data ListForm
-- | Type token for format of the form [a,b]
data TreeForm
-- | Ok the data doesn't have any specific form
-- | Coefficient for polynoms
data PolyCoeff =
CoeffFloat FloatingValue
| CoeffInt Integer
| CoeffRatio (Ratio Integer)
deriving (Show, Read)
-- | This type store polynome in a recursive way, as presented
-- in chapter 3 of "Algorithm for Computer Algebra". It's a
-- recursive linked list
data Polynome =
Polynome String [(PolyCoeff, Polynome)]
| PolyRest PolyCoeff
deriving (Eq, Show, Read)
instance Eq PolyCoeff where
(==) = coeffPredicate (==)
coeffPredicate :: (forall a. Ord a => a -> a -> Bool) -> PolyCoeff -> PolyCoeff -> Bool
coeffPredicate op c1 c2 = eval $ polyCoeffCast c1 c2
where eval (CoeffInt i1, CoeffInt i2) = i1 `op` i2
eval (CoeffFloat f1, CoeffFloat f2) = f1 `op` f2
eval (CoeffRatio r1, CoeffRatio r2) = r1 `op` r2
eval _ = error Err.polynom_bad_casting
-- | polyCoeffCast autocast to the same level
polyCoeffCast :: PolyCoeff -> PolyCoeff -> (PolyCoeff, PolyCoeff)
polyCoeffCast (CoeffInt i1) (CoeffInt i2) = (CoeffInt i1, CoeffInt i2)
polyCoeffCast (CoeffFloat f1) (CoeffFloat f2) = (CoeffFloat f1,CoeffFloat f2)
polyCoeffCast (CoeffRatio r1) (CoeffRatio r2) = (CoeffRatio r1, CoeffRatio r2)
polyCoeffCast (CoeffInt i1) (CoeffRatio r2) = (CoeffRatio $ i1 % 1, CoeffRatio r2)
polyCoeffCast (CoeffRatio r1) (CoeffInt i2) = (CoeffRatio r1, CoeffRatio $ i2 % 1)
polyCoeffCast (CoeffInt i1) (CoeffFloat f2) = (CoeffFloat $ fromInteger i1, CoeffFloat f2)
polyCoeffCast (CoeffFloat f1) (CoeffInt i2) = (CoeffFloat f1, CoeffFloat $ fromInteger i2)
polyCoeffCast (CoeffFloat f1) (CoeffRatio r2) = (CoeffFloat f1, CoeffFloat $ fromRational r2)
polyCoeffCast (CoeffRatio r1) (CoeffFloat f2) = (CoeffFloat $ fromRational r1, CoeffFloat f2)
infixl 4 <<>>
(<<>>) :: Ordering -> Ordering -> Ordering
a <<>> b = ordIt a
where ordIt EQ = b
ordIt o = o
-----------------------------------------------------------
-- Ord def, used to sort-out '+' list for exemples
-----------------------------------------------------------
instance Show (Formula anyForm) where
showsPrec _ (Formula a) =
("{-"++)
. sexprRenderS (Formula a)
. (++) "-} Formula ("
. shows a . (++) ")"
instance Ord PolyCoeff where
compare left right = case polyCoeffCast left right of
(CoeffInt a, CoeffInt b) -> compare a b
(CoeffFloat a, CoeffFloat b) -> compare a b
(CoeffRatio a, CoeffRatio b) -> compare a b
_ -> error "Bad cast"
instance Ord Polynome where
compare (PolyRest a) (PolyRest b) = compare a b
compare (Polynome v1 c1) (Polynome v2 c2)
| v1 /= v2 = compare v1 v2
| otherwise = case compare coeff1 coeff2 of
EQ -> compare sub1 sub2
a -> a
where (coeff1, sub1) = last c1
(coeff2, sub2) = last c2
compare (Polynome _ _) _ = LT
compare _ (Polynome _ _) = GT
instance Ord FormulaPrim where
-- Ignoring meta in comparisons
compare (Meta _ _ f) f2 = compare f f2
compare f (Meta _ _ f2) = compare f f2
compare (NumEntity e1) (NumEntity e2) = compare e1 e2
compare (UnOp _ _ f1) (UnOp _ _ f2) = compare f1 f2
compare (CInteger i) (CInteger i2) = compare i i2
compare (CFloat f) (CFloat f2) = compare f f2
compare (CInteger i) (CFloat f) = compare (fromIntegral i) f
compare (CFloat f) (CInteger i) = compare f $ fromIntegral i
compare (CFloat _) _ = LT
compare (CInteger _) _ = LT
compare (Poly _ p1) (Poly _ p2) = compare p1 p2
compare (Poly _ _) _ = LT
compare _ (Poly _ _) = GT
-- x < y
compare (Variable v) (Variable v1) = compare v v1
-- Variable last
compare (Variable _) _ = LT
compare _ (CInteger _) = GT
compare _ (CFloat _) = GT
compare _ (Block _ _ _) = LT
compare _ (NumEntity _) = GT
-- we don't sort matrixes, because the mul
compare (Matrix _ _ _ _) (Matrix _ _ _ _) = EQ
compare _ (Matrix _ _ _ _) = LT
compare (Matrix _ _ _ _) _ = LT
compare (BinOp _ OpPow [Variable v1, p1])
(BinOp _ OpPow [Variable v2, p2])
| p1 == p2 = compare v1 v2
| otherwise = compare p1 p2
compare (BinOp _ OpPow a) (BinOp _ OpPow b) =
case comparing length a b of
LT -> LT
EQ -> foldl' (\acc (a', b') -> acc <<>> compare a' b') EQ $ zip a b
GT -> GT
compare (BinOp _ OpPow _) _ = GT
compare _ (BinOp _ OpPow _) = LT
compare (BinOp _ op (BinOp _ OpPow (Variable v1: p1: _):_))
(BinOp _ op' (BinOp _ OpPow (Variable v2: p2: _):_))
| op == op' && v1 == v2 && op `elem` [OpMul, OpDiv] = compare p1 p2
compare (BinOp _ op (_:(BinOp _ OpPow (Variable v1: p1: _):_)))
(BinOp _ op' (_:(BinOp _ OpPow (Variable v2: p2: _):_)))
| op == op' && v1 == v2 && op `elem` [OpMul, OpDiv] = compare p1 p2
compare (BinOp _ _ f1) (BinOp _ _ f2) = compare f1 f2
compare (Derivate _ w _) (Derivate _ w' _) = compare w w'
compare (Derivate _ _ _) (Integrate _ _ _ _ _) = LT
compare (Derivate _ _ _) _ = GT
compare (Integrate _ _ _ w _) (Integrate _ _ _ w' _) = compare w w'
compare (Integrate _ _ _ _ _) _ = GT
compare (Product _ l h w) (Product _ l' h' w') =
compare l l' <<>> compare h h' <<>> compare w w'
compare (Product _ _ _ _) _ = GT
compare (Sum _ l h w) (Sum _ l' h' w') =
compare l l' <<>> compare h h' <<>> compare w w'
compare (Sum _ _ _ _) _ = GT
compare (App _ _ _) _ = LT
compare (Block _ _ _) _ = GT
compare (NumEntity _) _ = LT
compare f1 f2 = comparing nodeCount f1 f2
where nodeCount = getSum . foldf
(\_ a -> Monoid.Sum $ getSum a + 1)
(Monoid.Sum 0 :: Monoid.Sum Int)
-----------------------------------------------------------
-- Side Associativity
-----------------------------------------------------------
-- | Used to retrieve association property of operators.
-- It's only a type token
data AssocSide = AssocSide
deriving (Eq)
-- | The implementation of property operators
data OpAssoc = OpAssocLeft | OpAssocRight
deriving (Eq, Show)
-- | Help to query operator associativity
instance Property BinOperator AssocSide OpAssoc where
getProps OpLazyAttrib = [(AssocSide, OpAssocRight)]
getProps OpAttrib = [(AssocSide, OpAssocRight)]
getProps OpEq = [(AssocSide, OpAssocRight)]
getProps OpCons = [(AssocSide, OpAssocRight)]
getProps _ = [(AssocSide, OpAssocLeft)]
-----------------------------------------------------------
-- General operator property
-----------------------------------------------------------
-- | Some use full informations which can be used for$
-- transformation based on operators. Distributivity
-- is handled elsewhere because we need to specify which
-- operator we can distribute uppon.
data OpProp = Associativ -- ^ if (a . b) . c <=> a . (b . c)
| Commutativ -- ^ if a . b = b . a
| Distributiv -- ^ if a . (b ! c) <=> a . b ! a . c
-- /!\ must check on what it is distributiv
| InverseOp -- ^ Inverse operation
deriving (Eq, Show)
emptyProps :: e -> [p] -> [(p,e)]
emptyProps = map . flip (,)
instance Property BinOperator OpProp BinOperator where
getProps OpEq = []
getProps OpAnd = []
getProps OpOr = []
getProps OpNe = []
getProps OpLe = []
getProps OpGe = []
getProps OpLt = []
getProps OpGt = []
getProps OpPow = []
getProps OpAttrib = []
getProps OpCons = []
getProps OpLazyAttrib = []
getProps OpSub = [(InverseOp, OpAdd)]
getProps OpAdd =
(InverseOp, OpSub) : emptyProps OpAdd [Associativ, Commutativ]
getProps OpMul =
(InverseOp, OpDiv) : emptyProps OpMul [Associativ, Commutativ, Distributiv]
getProps OpDiv =
(InverseOp, OpMul) : emptyProps OpDiv [Distributiv]
canDistributeOver :: BinOperator -> BinOperator -> Bool
canDistributeOver op1 = (`elem` distributeOver op1)
distributeOver :: BinOperator -> [BinOperator]
distributeOver OpMul = [OpAdd, OpSub]
distributeOver OpDiv = [OpAdd, OpSub]
distributeOver OpOr = [OpAnd]
distributeOver _ = []
-----------------------------------------------------------
-- Priority Property
-----------------------------------------------------------
data Priority = Priority deriving Eq
instance Property BinOperator Priority Int where
getProps op = [(Priority, first. fromJust $ lookup op binopDefs)]
where first (f,_,_) = f
instance Property UnOperator Priority Int where
getProps OpFactorial = [(Priority, 0)]
getProps OpNegate = [(Priority, 1)]
getProps OpExp = [(Priority, 2)]
getProps _ = [(Priority, 1000)]
-----------------------------------------------------------
-- Leaf Property
-----------------------------------------------------------
data LeafNode = LeafNode deriving Eq
instance Property FormulaPrim LeafNode Bool where
getProps (Variable _) = [(LeafNode, True)]
getProps (CInteger _) = [(LeafNode, True)]
getProps (CFloat _) = [(LeafNode, True)]
getProps (NumEntity _) = [(LeafNode, True)]
getProps _ = [(LeafNode, False)]
hasProp (Variable _) _ = True
hasProp (CInteger _) _ = True
hasProp (CFloat _) _ = True
hasProp (NumEntity _) _ = True
hasProp _ _ = False
-----------------------------------------------------------
-- Text
-----------------------------------------------------------
data OperatorText = OperatorText deriving Eq
instance Property UnOperator OperatorText String where
getProps op = [(OperatorText, fromJust $ lookup op unOpNames)]
-- | Priority and textual representation
-- of binary operators
binopDefs :: [(BinOperator, (Int, String, String))]
binopDefs =
[ (OpAttrib, (8, ":=", "Attribution operator"))
, (OpLazyAttrib, (8, ":>", "Lazy attribution operator"))
, (OpCons,(7, "::", "List appending operator"))
, (OpAnd, (6, "&", "Logical and operator"))
, (OpOr, (6, "|", "Logical or operator"))
, (OpEq, (5, "=", "Equality operator"))
, (OpNe, (5, "/=", "Different operator"))
, (OpLt, (5, "<" , "Lower than operator"))
, (OpGt, (5, ">" , "Greater than operator"))
, (OpGe, (5, ">=", "Greater or equal operator"))
, (OpLe, (5, "<=", "Lower or equal operator"))
, (OpAdd, (4, "+", "Addition operator"))
, (OpSub, (4, "-", "Substraction operator"))
, (OpMul, (3, "*", "Multiplication operator"))
, (OpDiv, (3, "/", "Division/fraction operator"))
, (OpPow, (2, "^", "Power operator"))
]
binopString :: BinOperator -> String
binopString a = second . fromJust $ lookup a binopDefs
where second (_, s, _) = s
unopString :: UnOperator -> String
unopString a = fromJust $ lookup a unOpNames
realUnopOperators :: [(UnOperator, String, String)]
realUnopOperators = [ (OpNegate, "-", "Negation operator, put it before expression (-x)")
, (OpFactorial, "!", "Factorial operator, put it after expression (x!)")
]
-- | Textual representation of "unary" operators
unOpNames :: [(UnOperator, String)]
unOpNames = [ (op, reprez) | (op, reprez,_) <- realUnopOperators] ++
[ (OpAbs, "abs")
, (OpSqrt, "sqrt")
, (OpSin, "sin")
, (OpASin, "asin")
, (OpSinh, "sinh")
, (OpASinh, "asinh")
, (OpCos, "cos")
, (OpACos, "acos")
, (OpCosh, "cosh")
, (OpACosh, "acosh")
, (OpTan, "tan")
, (OpATan, "atan")
, (OpTanh, "tanh")
, (OpATanh, "atanh")
, (OpLn, "ln")
, (OpLog, "log")
, (OpExp, "exp")
, (OpCeil, "ceil")
, (OpFloor, "floor")
, (OpFrac, "frac")
]
-------------------------------------------
---- Formula Folding
-------------------------------------------
foldf :: (Monoid b)
=> (FormulaPrim -> b -> b) -> b -> FormulaPrim -> b
foldf f acc m@(Meta _ _ fo) = f m $ foldf f acc fo
foldf f acc fo@(UnOp _ _ sub) = f fo $ foldf f acc sub
foldf f acc fo@(App _ def args) =
f fo (foldf f listAcc def)
where listAcc = foldr f acc args
foldf f acc fo@(BinOp _ _ args) =
f fo $ foldr f acc args
foldf f acc fo@(Sum _ ini end what) = f fo finalAcc
where whatAcc = foldf f acc what
iniAcc = foldf f acc ini
endAcc = foldf f acc end
finalAcc = whatAcc `mappend` iniAcc `mappend` endAcc
foldf f acc fo@(Product _ ini end what) = f fo finalAcc
where whatAcc = foldf f acc what
iniAcc = foldf f acc ini
endAcc = foldf f acc end
finalAcc = whatAcc `mappend` iniAcc `mappend` endAcc
foldf f acc fo@(Integrate _ ini end what var) = f fo finalAcc
where whatAcc = foldf f acc what
iniAcc = foldf f acc ini
endAcc = foldf f acc end
varAcc = foldf f acc var
finalAcc = whatAcc `mappend` iniAcc
`mappend` endAcc `mappend` varAcc
foldf f acc fo@(Derivate _ what var) = f fo $ whatAcc `mappend` varAcc
where whatAcc = foldf f acc what
varAcc = foldf f acc var
foldf f acc fo@(Matrix _ _ _ cells) = f fo finalAcc
where lineFolder acc' formu = acc' `mappend` foldf f acc formu
rowAccs = [ foldl' lineFolder mempty row | row <- cells]
finalAcc = foldl1' mappend rowAccs
foldf f acc fo = f fo acc
----------------------------------------
---- Strong and valid instances ----
----------------------------------------
instance Num FormulaPrim where
(+) = binOpMerger OpAdd
(-) = binOpMerger OpSub
(*) = binOpMerger OpMul
negate = unOp OpNegate
abs = unOp OpAbs
signum (CInteger n) = CInteger (signum n)
signum (CFloat f) = CFloat (signum f)
signum _ = CInteger 0
fromInteger = CInteger . fromInteger
instance Fractional FormulaPrim where
(/) = binOpMerger OpDiv
recip b = binOp OpDiv [CInteger 1, b]
fromRational a = binOp OpDiv [ int $ numerator a
, int $ denominator a]
where int = CInteger . fromInteger
instance Floating FormulaPrim where
pi = CFloat pi
exp = unOp OpExp
sqrt = unOp OpSqrt
log = unOp OpLn
(**) = binOpMerger OpPow
sin = unOp OpSin
cos = unOp OpCos
tan = unOp OpTan
asin = unOp OpASin
acos = unOp OpACos
atan = unOp OpATan
sinh = unOp OpSinh
cosh = unOp OpCosh
tanh = unOp OpTanh
asinh = unOp OpASinh
acosh = unOp OpACosh
atanh = unOp OpATanh