Eq-1.0: EqManips/Algorithm/Eval/Floating.hs
{-# LANGUAGE Rank2Types #-}
-- | This module implements the rules to interpret all floating
-- points operations which are by nature lossy. So this set
-- of rules may or may not be used in the context of global
-- evaluation to preserve the "true" meaning of the formula.
module EqManips.Algorithm.Eval.Floating ( evalFloat, floatEvalRules ) where
import Control.Applicative
import Data.Maybe( fromMaybe )
import Data.Ratio
import qualified EqManips.ErrorMessages as Err
import EqManips.Algorithm.Eval.Types
import EqManips.Algorithm.Eval.Utils
import EqManips.EvaluationContext
import EqManips.Types
-- | General function favored to use the reduction rules
-- as it preserve meta information about the formula form.
evalFloat :: Formula anyForm -> EqContext (Formula anyForm)
evalFloat (Formula f) = Formula <$> floatEvalRules f
floatCastingOperator :: (Double -> Double -> Double) -> EvalOp
floatCastingOperator f (CInteger i1) (CFloat f2) =
left . CFloat $ f (fromIntegral i1) f2
floatCastingOperator f (UnOp _ OpNegate (CInteger i1)) (CFloat f2) =
left . CFloat $ f (fromIntegral $ negate i1) f2
floatCastingOperator f (CFloat f1) (CInteger i2) =
left . CFloat $ f f1 (fromIntegral i2)
floatCastingOperator f (CFloat f1) (UnOp _ OpNegate (CInteger i2)) =
left . CFloat $ f f1 (fromIntegral $ negate i2)
floatCastingOperator f (CFloat f1) (CFloat f2) =
left . CFloat $ f f1 f2
floatCastingOperator _ e e' = right (e, e')
add, sub, mul, division, power :: EvalOp
add = floatCastingOperator (+)
sub = floatCastingOperator (-)
mul = floatCastingOperator (*)
division = floatCastingOperator (/)
power = floatCastingOperator (**)
-----------------------------------------------
---- 'floor'
-----------------------------------------------
floorEval :: EvalFun
floorEval (CFloat f) = return . CInteger $ floor f
floorEval f = return $ unOp OpFloor f
-----------------------------------------------
---- 'frac'
-----------------------------------------------
fracEval :: EvalFun
fracEval (CFloat f) = return . CFloat . snd $ (properFraction f :: (Int,Double))
fracEval f = return $ unOp OpFrac f
-----------------------------------------------
---- 'Ceil'
-----------------------------------------------
ceilEval :: EvalFun
ceilEval i@(CInteger _) = return i
ceilEval (CFloat f) = return . CInteger $ ceiling f
ceilEval f = return $ unOp OpCeil f
-----------------------------------------------
---- 'negate'
-----------------------------------------------
fNegate :: EvalFun
fNegate (CFloat f) = return . CFloat $ negate f
fNegate f = return $ negate f
-----------------------------------------------
---- 'abs'
-----------------------------------------------
fAbs :: EvalFun
fAbs (CFloat f) = return . CFloat $ abs f
fAbs f = return $ abs f
-----------------------------------------------
---- General evaluation
-----------------------------------------------
-- | All the rules for floats
floatEvalRules :: EvalFun
floatEvalRules (Fraction f) = return . CFloat $ fromInteger (numerator f)
/ fromInteger (denominator f)
floatEvalRules (NumEntity Pi) = return $ CFloat pi
floatEvalRules (BinOp _ OpAdd fs) = binEval OpAdd add add fs
floatEvalRules (BinOp _ OpSub fs) = binEval OpSub sub add fs
floatEvalRules (BinOp _ OpMul fs) = binEval OpMul mul mul fs
-- | Todo fix this, it's incorrect
floatEvalRules (BinOp _ OpPow fs) = binEval OpPow power power fs
floatEvalRules (BinOp _ OpDiv fs) = binEval OpDiv division mul fs
floatEvalRules (UnOp _ OpFloor f) = floorEval f
floatEvalRules (UnOp _ OpCeil f) = ceilEval f
floatEvalRules (UnOp _ OpFrac f) = fracEval f
floatEvalRules (UnOp _ OpNegate f) = fNegate f
floatEvalRules (UnOp _ OpAbs f) = fAbs f
floatEvalRules formula@(UnOp _ op f) =
return . fromMaybe formula $ unOpReduce (funOf op) f
where funOf OpSqrt = sqrt
funOf OpSin = sin
funOf OpSinh = sinh
funOf OpASin = asin
funOf OpASinh = asinh
funOf OpCos = cos
funOf OpCosh = cosh
funOf OpACos = acos
funOf OpACosh = acosh
funOf OpTan = tan
funOf OpTanh = tanh
funOf OpATan = atan
funOf OpATanh = atanh
funOf OpLn = log
funOf OpLog = logBase 10.0
funOf OpExp = exp
funOf OpAbs = error $ Err.not_here "unop : abs - "
funOf OpNegate = error $ Err.not_here "unop : negate - "
funOf OpFloor = error $ Err.not_here "unop : floor - "
funOf OpFrac = error $ Err.not_here "unop : frac - "
funOf OpCeil = error $ Err.not_here "unop : ceil - "
funOf OpFactorial = error $ Err.not_here "unop : Should - "
floatEvalRules end = return end
--------------------------------------------------------------
---- Scalar related function
--------------------------------------------------------------
unOpReduce :: (forall a. (Floating a) => a -> a) -> FormulaPrim -> Maybe FormulaPrim
unOpReduce f (Fraction r) = unOpReduce f . CFloat $ fromRational r
unOpReduce f (CInteger i) = unOpReduce f . CFloat $ fromInteger i
unOpReduce f (CFloat num) = Just . CFloat $ f num
unOpReduce _ _ = Nothing