{-# LANGUAGE RebindableSyntax #-}
module Algebra.Transcendental where

import qualified Algebra.Algebraic as Algebraic

import qualified Algebra.Laws as Laws

import Algebra.Algebraic (sqrt)
import Algebra.Field     ((/), recip)
import Algebra.Ring      ((*), (^), fromInteger)
import Algebra.Additive  ((+), (-), negate)

import qualified Prelude as P
import NumericPrelude.Base


infixr 8  **, ^?

{-|
Transcendental is the type of numbers supporting the elementary
transcendental functions.  Examples include real numbers, complex
numbers, and computable reals represented as a lazy list of rational
approximations.

Note the default declaration for a superclass.  See the comments
below, under "Instance declaractions for superclasses".

The semantics of these operations are rather ill-defined because of
branch cuts, etc.

Minimal complete definition:
     pi, exp, (log or logBase), sin, cos, atan
-}
class (Algebraic.C a) => C a where
    {-# MINIMAL pi, exp, (log | logBase), sin, cos, atan #-}
    pi                  :: a
    exp, log            :: a -> a
    logBase, (**)       :: a -> a -> a
    sin, cos, tan       :: a -> a
    asin, acos, atan    :: a -> a
    sinh, cosh, tanh    :: a -> a
    asinh, acosh, atanh :: a -> a

    {-# INLINE logBase #-}
    {-# INLINE (**) #-}
    {-# INLINE tan #-}
    {-# INLINE asin #-}
    {-# INLINE acos #-}
    {-# INLINE sinh #-}
    {-# INLINE tanh #-}
    {-# INLINE cosh #-}
    {-# INLINE asinh #-}
    {-# INLINE atanh #-}
    {-# INLINE acosh #-}

    a
x ** a
y           =  a -> a
forall a. C a => a -> a
exp (a -> a
forall a. C a => a -> a
log a
x a -> a -> a
forall a. C a => a -> a -> a
* a
y)
    logBase a
x a
y      =  a -> a
forall a. C a => a -> a
log a
y a -> a -> a
forall a. C a => a -> a -> a
/ a -> a
forall a. C a => a -> a
log a
x
    log              =  a -> a -> a
forall a. C a => a -> a -> a
logBase (a -> a
forall a. C a => a -> a
exp a
1)

    tan  a
x           =  a -> a
forall a. C a => a -> a
sin a
x a -> a -> a
forall a. C a => a -> a -> a
/ a -> a
forall a. C a => a -> a
cos a
x

    asin a
x           =  a -> a
forall a. C a => a -> a
atan (a
x a -> a -> a
forall a. C a => a -> a -> a
/ a -> a
forall a. C a => a -> a
sqrt (a
1a -> a -> a
forall a. C a => a -> a -> a
-a
xa -> Integer -> a
forall a. C a => a -> Integer -> a
^Integer
2))
    acos a
x           =  a
forall a. C a => a
pia -> a -> a
forall a. C a => a -> a -> a
/a
2 a -> a -> a
forall a. C a => a -> a -> a
- a -> a
forall a. C a => a -> a
asin a
x

    -- if these definitions have errors, then those in FMP.Types have them, too
    sinh a
x           =  (a -> a
forall a. C a => a -> a
exp a
x a -> a -> a
forall a. C a => a -> a -> a
- a -> a
forall a. C a => a -> a
exp (-a
x)) a -> a -> a
forall a. C a => a -> a -> a
/ a
2
    cosh a
x           =  (a -> a
forall a. C a => a -> a
exp a
x a -> a -> a
forall a. C a => a -> a -> a
+ a -> a
forall a. C a => a -> a
exp (-a
x)) a -> a -> a
forall a. C a => a -> a -> a
/ a
2
    -- tanh x           =  (exp x - exp (-x)) / (exp x + exp (-x))
    tanh a
x           =  a -> a
forall a. C a => a -> a
sinh a
x a -> a -> a
forall a. C a => a -> a -> a
/ a -> a
forall a. C a => a -> a
cosh a
x

    asinh a
x          =  a -> a
forall a. C a => a -> a
log (a -> a
forall a. C a => a -> a
sqrt (a
xa -> Integer -> a
forall a. C a => a -> Integer -> a
^Integer
2a -> a -> a
forall a. C a => a -> a -> a
+a
1) a -> a -> a
forall a. C a => a -> a -> a
+ a
x)
    acosh a
x          =  a -> a
forall a. C a => a -> a
log (a -> a
forall a. C a => a -> a
sqrt (a
xa -> Integer -> a
forall a. C a => a -> Integer -> a
^Integer
2a -> a -> a
forall a. C a => a -> a -> a
-a
1) a -> a -> a
forall a. C a => a -> a -> a
+ a
x)
    atanh a
x          =  (a -> a
forall a. C a => a -> a
log (a
1a -> a -> a
forall a. C a => a -> a -> a
+a
x) a -> a -> a
forall a. C a => a -> a -> a
- a -> a
forall a. C a => a -> a
log (a
1a -> a -> a
forall a. C a => a -> a -> a
-a
x)) a -> a -> a
forall a. C a => a -> a -> a
/ a
2


instance C P.Float where
    {-# INLINE pi #-}
    {-# INLINE exp #-}
    {-# INLINE log #-}
    {-# INLINE logBase #-}
    {-# INLINE (**) #-}
    {-# INLINE sin #-}
    {-# INLINE tan #-}
    {-# INLINE cos #-}
    {-# INLINE asin #-}
    {-# INLINE atan #-}
    {-# INLINE acos #-}
    {-# INLINE sinh #-}
    {-# INLINE tanh #-}
    {-# INLINE cosh #-}
    {-# INLINE asinh #-}
    {-# INLINE atanh #-}
    {-# INLINE acosh #-}

    ** :: Float -> Float -> Float
(**)  = Float -> Float -> Float
forall a. Floating a => a -> a -> a
(P.**)
    exp :: Float -> Float
exp   = Float -> Float
forall a. Floating a => a -> a
P.exp;   log :: Float -> Float
log   = Float -> Float
forall a. Floating a => a -> a
P.log;   logBase :: Float -> Float -> Float
logBase = Float -> Float -> Float
forall a. Floating a => a -> a -> a
P.logBase
    pi :: Float
pi    = Float
forall a. Floating a => a
P.pi;
    sin :: Float -> Float
sin   = Float -> Float
forall a. Floating a => a -> a
P.sin;   cos :: Float -> Float
cos   = Float -> Float
forall a. Floating a => a -> a
P.cos;   tan :: Float -> Float
tan     = Float -> Float
forall a. Floating a => a -> a
P.tan
    asin :: Float -> Float
asin  = Float -> Float
forall a. Floating a => a -> a
P.asin;  acos :: Float -> Float
acos  = Float -> Float
forall a. Floating a => a -> a
P.acos;  atan :: Float -> Float
atan    = Float -> Float
forall a. Floating a => a -> a
P.atan
    sinh :: Float -> Float
sinh  = Float -> Float
forall a. Floating a => a -> a
P.sinh;  cosh :: Float -> Float
cosh  = Float -> Float
forall a. Floating a => a -> a
P.cosh;  tanh :: Float -> Float
tanh    = Float -> Float
forall a. Floating a => a -> a
P.tanh
    asinh :: Float -> Float
asinh = Float -> Float
forall a. Floating a => a -> a
P.asinh; acosh :: Float -> Float
acosh = Float -> Float
forall a. Floating a => a -> a
P.acosh; atanh :: Float -> Float
atanh   = Float -> Float
forall a. Floating a => a -> a
P.atanh

instance C P.Double where
    {-# INLINE pi #-}
    {-# INLINE exp #-}
    {-# INLINE log #-}
    {-# INLINE logBase #-}
    {-# INLINE (**) #-}
    {-# INLINE sin #-}
    {-# INLINE tan #-}
    {-# INLINE cos #-}
    {-# INLINE asin #-}
    {-# INLINE atan #-}
    {-# INLINE acos #-}
    {-# INLINE sinh #-}
    {-# INLINE tanh #-}
    {-# INLINE cosh #-}
    {-# INLINE asinh #-}
    {-# INLINE atanh #-}
    {-# INLINE acosh #-}

    ** :: Double -> Double -> Double
(**)  = Double -> Double -> Double
forall a. Floating a => a -> a -> a
(P.**)
    exp :: Double -> Double
exp   = Double -> Double
forall a. Floating a => a -> a
P.exp;   log :: Double -> Double
log   = Double -> Double
forall a. Floating a => a -> a
P.log;   logBase :: Double -> Double -> Double
logBase = Double -> Double -> Double
forall a. Floating a => a -> a -> a
P.logBase
    pi :: Double
pi    = Double
forall a. Floating a => a
P.pi;
    sin :: Double -> Double
sin   = Double -> Double
forall a. Floating a => a -> a
P.sin;   cos :: Double -> Double
cos   = Double -> Double
forall a. Floating a => a -> a
P.cos;   tan :: Double -> Double
tan     = Double -> Double
forall a. Floating a => a -> a
P.tan
    asin :: Double -> Double
asin  = Double -> Double
forall a. Floating a => a -> a
P.asin;  acos :: Double -> Double
acos  = Double -> Double
forall a. Floating a => a -> a
P.acos;  atan :: Double -> Double
atan    = Double -> Double
forall a. Floating a => a -> a
P.atan
    sinh :: Double -> Double
sinh  = Double -> Double
forall a. Floating a => a -> a
P.sinh;  cosh :: Double -> Double
cosh  = Double -> Double
forall a. Floating a => a -> a
P.cosh;  tanh :: Double -> Double
tanh    = Double -> Double
forall a. Floating a => a -> a
P.tanh
    asinh :: Double -> Double
asinh = Double -> Double
forall a. Floating a => a -> a
P.asinh; acosh :: Double -> Double
acosh = Double -> Double
forall a. Floating a => a -> a
P.acosh; atanh :: Double -> Double
atanh   = Double -> Double
forall a. Floating a => a -> a
P.atanh



{-# INLINE (^?) #-}
(^?) :: C a => a -> a -> a
^? :: a -> a -> a
(^?) = a -> a -> a
forall a. C a => a -> a -> a
(**)


{-* Transcendental laws, will only hold approximately on floating point numbers -}

propExpLog      :: (Eq a, C a) => a -> Bool
propLogExp      :: (Eq a, C a) => a -> Bool
propExpNeg      :: (Eq a, C a) => a -> Bool
propLogRecip    :: (Eq a, C a) => a -> Bool
propExpProduct  :: (Eq a, C a) => a -> a -> Bool
propExpLogPower :: (Eq a, C a) => a -> a -> Bool
propLogSum      :: (Eq a, C a) => a -> a -> Bool

propExpLog :: a -> Bool
propExpLog      a
x   = a -> a
forall a. C a => a -> a
exp (a -> a
forall a. C a => a -> a
log a
x)     a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
x
propLogExp :: a -> Bool
propLogExp      a
x   = a -> a
forall a. C a => a -> a
log (a -> a
forall a. C a => a -> a
exp a
x)     a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
x
propExpNeg :: a -> Bool
propExpNeg      a
x   = a -> a
forall a. C a => a -> a
exp (a -> a
forall a. C a => a -> a
negate a
x)  a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a -> a
forall a. C a => a -> a
recip (a -> a
forall a. C a => a -> a
exp a
x)
propLogRecip :: a -> Bool
propLogRecip    a
x   = a -> a
forall a. C a => a -> a
log (a -> a
forall a. C a => a -> a
recip a
x)   a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a -> a
forall a. C a => a -> a
negate (a -> a
forall a. C a => a -> a
log a
x)
propExpProduct :: a -> a -> Bool
propExpProduct  a
x a
y = (a -> a) -> (a -> a -> a) -> (a -> a -> a) -> a -> a -> Bool
forall a b.
Eq a =>
(b -> a) -> (b -> b -> b) -> (a -> a -> a) -> b -> b -> Bool
Laws.homomorphism a -> a
forall a. C a => a -> a
exp a -> a -> a
forall a. C a => a -> a -> a
(+) a -> a -> a
forall a. C a => a -> a -> a
(*) a
x a
y
propExpLogPower :: a -> a -> Bool
propExpLogPower a
x a
y = a -> a
forall a. C a => a -> a
exp (a -> a
forall a. C a => a -> a
log a
x a -> a -> a
forall a. C a => a -> a -> a
* a
y) a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
x a -> a -> a
forall a. C a => a -> a -> a
** a
y
propLogSum :: a -> a -> Bool
propLogSum      a
x a
y = (a -> a) -> (a -> a -> a) -> (a -> a -> a) -> a -> a -> Bool
forall a b.
Eq a =>
(b -> a) -> (b -> b -> b) -> (a -> a -> a) -> b -> b -> Bool
Laws.homomorphism a -> a
forall a. C a => a -> a
log a -> a -> a
forall a. C a => a -> a -> a
(*) a -> a -> a
forall a. C a => a -> a -> a
(+) a
x a
y


propPowerCascade      :: (Eq a, C a) => a -> a -> a -> Bool
propPowerProduct      :: (Eq a, C a) => a -> a -> a -> Bool
propPowerDistributive :: (Eq a, C a) => a -> a -> a -> Bool

propPowerCascade :: a -> a -> a -> Bool
propPowerCascade      a
x a
i a
j  =  (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
forall a b.
Eq a =>
(b -> b -> b) -> (a -> b -> a) -> a -> b -> b -> Bool
Laws.rightCascade a -> a -> a
forall a. C a => a -> a -> a
(*) a -> a -> a
forall a. C a => a -> a -> a
(**) a
x a
i a
j
propPowerProduct :: a -> a -> a -> Bool
propPowerProduct      a
x a
i a
j  =  (a -> a) -> (a -> a -> a) -> (a -> a -> a) -> a -> a -> Bool
forall a b.
Eq a =>
(b -> a) -> (b -> b -> b) -> (a -> a -> a) -> b -> b -> Bool
Laws.homomorphism (a
xa -> a -> a
forall a. C a => a -> a -> a
**) a -> a -> a
forall a. C a => a -> a -> a
(+) a -> a -> a
forall a. C a => a -> a -> a
(*) a
i a
j
propPowerDistributive :: a -> a -> a -> Bool
propPowerDistributive a
i a
x a
y  =  (a -> a -> a) -> (a -> a -> a) -> a -> a -> a -> Bool
forall a b.
Eq a =>
(b -> a -> a) -> (a -> a -> a) -> b -> a -> a -> Bool
Laws.rightDistributive a -> a -> a
forall a. C a => a -> a -> a
(**) a -> a -> a
forall a. C a => a -> a -> a
(*) a
i a
x a
y

{- * Trigonometric laws, addition theorems -}

propTrigonometricPythagoras :: (Eq a, C a) => a -> Bool
propTrigonometricPythagoras :: a -> Bool
propTrigonometricPythagoras a
x  =  a -> a
forall a. C a => a -> a
cos a
x a -> Integer -> a
forall a. C a => a -> Integer -> a
^ Integer
2 a -> a -> a
forall a. C a => a -> a -> a
+ a -> a
forall a. C a => a -> a
sin a
x a -> Integer -> a
forall a. C a => a -> Integer -> a
^ Integer
2 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
1

propSinPeriod   :: (Eq a, C a) => a -> Bool
propCosPeriod   :: (Eq a, C a) => a -> Bool
propTanPeriod   :: (Eq a, C a) => a -> Bool

propSinPeriod :: a -> Bool
propSinPeriod a
x = a -> a
forall a. C a => a -> a
sin (a
xa -> a -> a
forall a. C a => a -> a -> a
+a
2a -> a -> a
forall a. C a => a -> a -> a
*a
forall a. C a => a
pi) a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a -> a
forall a. C a => a -> a
sin a
x
propCosPeriod :: a -> Bool
propCosPeriod a
x = a -> a
forall a. C a => a -> a
cos (a
xa -> a -> a
forall a. C a => a -> a -> a
+a
2a -> a -> a
forall a. C a => a -> a -> a
*a
forall a. C a => a
pi) a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a -> a
forall a. C a => a -> a
cos a
x
propTanPeriod :: a -> Bool
propTanPeriod a
x = a -> a
forall a. C a => a -> a
tan (a
xa -> a -> a
forall a. C a => a -> a -> a
+a
2a -> a -> a
forall a. C a => a -> a -> a
*a
forall a. C a => a
pi) a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a -> a
forall a. C a => a -> a
tan a
x

propSinAngleSum  :: (Eq a, C a) => a -> a -> Bool
propCosAngleSum  :: (Eq a, C a) => a -> a -> Bool

propSinAngleSum :: a -> a -> Bool
propSinAngleSum a
x a
y  =  a -> a
forall a. C a => a -> a
sin (a
xa -> a -> a
forall a. C a => a -> a -> a
+a
y) a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a -> a
forall a. C a => a -> a
sin a
x a -> a -> a
forall a. C a => a -> a -> a
* a -> a
forall a. C a => a -> a
cos a
y a -> a -> a
forall a. C a => a -> a -> a
+ a -> a
forall a. C a => a -> a
cos a
x a -> a -> a
forall a. C a => a -> a -> a
* a -> a
forall a. C a => a -> a
sin a
y
propCosAngleSum :: a -> a -> Bool
propCosAngleSum a
x a
y  =  a -> a
forall a. C a => a -> a
cos (a
xa -> a -> a
forall a. C a => a -> a -> a
+a
y) a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a -> a
forall a. C a => a -> a
cos a
x a -> a -> a
forall a. C a => a -> a -> a
* a -> a
forall a. C a => a -> a
cos a
y a -> a -> a
forall a. C a => a -> a -> a
- a -> a
forall a. C a => a -> a
sin a
x a -> a -> a
forall a. C a => a -> a -> a
* a -> a
forall a. C a => a -> a
sin a
y

propSinDoubleAngle :: (Eq a, C a) => a -> Bool
propCosDoubleAngle :: (Eq a, C a) => a -> Bool

propSinDoubleAngle :: a -> Bool
propSinDoubleAngle a
x  =  a -> a
forall a. C a => a -> a
sin (a
2a -> a -> a
forall a. C a => a -> a -> a
*a
x) a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
2 a -> a -> a
forall a. C a => a -> a -> a
* a -> a
forall a. C a => a -> a
sin a
x a -> a -> a
forall a. C a => a -> a -> a
* a -> a
forall a. C a => a -> a
cos a
x
propCosDoubleAngle :: a -> Bool
propCosDoubleAngle a
x  =  a -> a
forall a. C a => a -> a
cos (a
2a -> a -> a
forall a. C a => a -> a -> a
*a
x) a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
2 a -> a -> a
forall a. C a => a -> a -> a
* a -> a
forall a. C a => a -> a
cos a
x a -> Integer -> a
forall a. C a => a -> Integer -> a
^ Integer
2 a -> a -> a
forall a. C a => a -> a -> a
- a
1

propSinSquare :: (Eq a, C a) => a -> Bool
propCosSquare :: (Eq a, C a) => a -> Bool

propSinSquare :: a -> Bool
propSinSquare a
x  =  a -> a
forall a. C a => a -> a
sin a
x a -> Integer -> a
forall a. C a => a -> Integer -> a
^ Integer
2 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== (a
1 a -> a -> a
forall a. C a => a -> a -> a
- a -> a
forall a. C a => a -> a
cos (a
2a -> a -> a
forall a. C a => a -> a -> a
*a
x)) a -> a -> a
forall a. C a => a -> a -> a
/ a
2
propCosSquare :: a -> Bool
propCosSquare a
x  =  a -> a
forall a. C a => a -> a
cos a
x a -> Integer -> a
forall a. C a => a -> Integer -> a
^ Integer
2 a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== (a
1 a -> a -> a
forall a. C a => a -> a -> a
+ a -> a
forall a. C a => a -> a
cos (a
2a -> a -> a
forall a. C a => a -> a -> a
*a
x)) a -> a -> a
forall a. C a => a -> a -> a
/ a
2