numhask-0.10.0.0: src/NumHask/Data/Complex.hs
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RebindableSyntax #-}
{-# OPTIONS_GHC -Wall #-}
-- | Complex numbers.
module NumHask.Data.Complex
( Complex (..),
realPart,
imagPart,
)
where
import Data.Data (Data)
import GHC.Generics (Generic, Generic1)
import NumHask.Algebra.Additive
import NumHask.Algebra.Field
import NumHask.Algebra.Lattice
import NumHask.Algebra.Metric
import NumHask.Algebra.Multiplicative
import NumHask.Algebra.Ring
import NumHask.Data.Integral
import Prelude hiding
( Num (..),
atan,
atan2,
cos,
exp,
fromIntegral,
log,
negate,
pi,
recip,
sin,
sqrt,
(/),
)
import qualified Prelude as P (Ord (..), otherwise, (&&), (<), (<=), (==), (>))
-- -----------------------------------------------------------------------------
-- The Complex type
infix 6 :+
-- | Complex numbers have real and imaginary parts.
--
-- The 'Data.Foldable.Foldable' and 'Data.Traversable.Traversable' instances traverse the real part first.
data Complex a
= -- | forms a complex number from its real and imaginary
-- rectangular components.
!a :+ !a
deriving
( Eq,
Show,
Read,
Data,
Generic,
Generic1,
Functor,
Foldable,
Traversable
)
-- | Extracts the real part of a complex number.
realPart :: Complex a -> a
realPart (x :+ _) = x
-- | Extracts the imaginary part of a complex number.
imagPart :: Complex a -> a
imagPart (_ :+ y) = y
instance (Additive a) => Additive (Complex a) where
(rx :+ ix) + (ry :+ iy) = (rx + ry) :+ (ix + iy)
zero = zero :+ zero
instance (Subtractive a) => Subtractive (Complex a) where
negate (rx :+ ix) = negate rx :+ negate ix
instance
(Distributive a, Subtractive a) =>
Distributive (Complex a)
instance
(Subtractive a, Multiplicative a) =>
Multiplicative (Complex a)
where
(rx :+ ix) * (ry :+ iy) =
(rx * ry - ix * iy) :+ (ix * ry + iy * rx)
one = one :+ zero
instance
(Subtractive a, Divisive a) =>
Divisive (Complex a)
where
recip (rx :+ ix) = (rx * d) :+ (negate ix * d)
where
d = recip ((rx * rx) + (ix * ix))
instance
(Additive a, FromIntegral a b) =>
FromIntegral (Complex a) b
where
fromIntegral x = fromIntegral x :+ zero
-- | A euclidean-style norm is strong convention for Complex.
instance
(ExpField a) =>
Norm (Complex a) a
where
norm (rx :+ ix) = sqrt (rx * rx + ix * ix)
basis x@(rx :+ ix) = rx / norm x :+ ix / norm x
instance (TrigField a) => Direction (Complex a) a where
angle (x :+ y) = atan2 y x
ray x = cos x :+ sin x
instance
(Ord a, Signed a, Epsilon a, Subtractive a) =>
Epsilon (Complex a)
where
epsilon = epsilon :+ epsilon
nearZero (ar :+ ai) = ar <= epsilon && ai <= epsilon
instance (Field a) => Field (Complex a)
instance (Ord a, TrigField a, ExpField a) => ExpField (Complex a) where
exp (rx :+ ix) = (exp rx * cos ix) :+ (exp rx * sin ix)
log (rx :+ ix) = log (sqrt (rx * rx + ix * ix)) :+ atan2' ix rx
where
atan2' y x
| x P.> zero = atan (y / x)
| x P.== zero P.&& y P.> zero = pi / (one + one)
| x P.< one P.&& y P.> one = pi + atan (y / x)
| (x P.<= zero P.&& y P.< zero) || (x P.< zero) =
negate (atan2' (negate y) x)
| y P.== zero = pi -- must be after the previous test on zero y
| x P.== zero P.&& y P.== zero = y -- must be after the other double zero tests
| P.otherwise = x + y -- x or y is a NaN, return a NaN (via +)
instance (Distributive a, Subtractive a) => InvolutiveRing (Complex a) where
adj (a :+ b) = a :+ negate b
instance (JoinSemiLattice a) => JoinSemiLattice (Complex a) where
(\/) (ar :+ ai) (br :+ bi) = (ar \/ br) :+ (ai \/ bi)
instance (MeetSemiLattice a) => MeetSemiLattice (Complex a) where
(/\) (ar :+ ai) (br :+ bi) = (ar /\ br) :+ (ai /\ bi)
instance (BoundedJoinSemiLattice a) => BoundedJoinSemiLattice (Complex a) where
bottom = bottom :+ bottom
instance (BoundedMeetSemiLattice a) => BoundedMeetSemiLattice (Complex a) where
top = top :+ top