module MathObj.Gaussian.Bell where
import qualified MathObj.Polynomial as Poly
import qualified Number.Complex as Complex
import qualified Algebra.Transcendental as Trans
import qualified Algebra.Field as Field
import qualified Algebra.Absolute as Absolute
import qualified Algebra.Ring as Ring
import qualified Algebra.Additive as Additive
import Number.Complex ((+:), )
import Test.QuickCheck (Arbitrary, arbitrary, )
import Control.Monad (liftM4, )
import NumericPrelude.Numeric
import NumericPrelude.Base hiding (reverse, )
data T a = Cons {amp :: a, c0, c1 :: Complex.T a, c2 :: a}
deriving (Eq, Show)
instance (Absolute.C a, Arbitrary a) => Arbitrary (T a) where
arbitrary =
liftM4
(\k a b c -> Cons (abs k) a b (1 + abs c))
arbitrary arbitrary arbitrary arbitrary
constant :: Ring.C a => T a
constant = Cons one zero zero zero
unit :: Ring.C a => T a
unit = Cons one zero zero one
evaluate :: (Trans.C a) =>
T a -> a -> Complex.T a
evaluate f x =
Complex.scale
(sqrt (amp f))
(Complex.exp $ Complex.scale (pi) $
c0 f + Complex.scale x (c1 f) + Complex.fromReal (c2 f * x^2))
evaluateSqRt :: (Trans.C a) =>
T a -> a -> Complex.T a
evaluateSqRt f x0 =
Complex.scale
(sqrt (amp f))
(let x = sqrt pi * x0
in Complex.exp $ negate $
c0 f + Complex.scale x (c1 f) + Complex.fromReal (c2 f * x^2))
exponentPolynomial :: (Additive.C a) =>
T a -> Poly.T (Complex.T a)
exponentPolynomial f =
Poly.fromCoeffs [c0 f, c1 f, Complex.fromReal (c2 f)]
variance :: (Trans.C a) =>
T a -> a
variance f =
recip $ c2 f * 2*pi
multiply :: (Ring.C a) =>
T a -> T a -> T a
multiply f g =
Cons
(amp f * amp g)
(c0 f + c0 g) (c1 f + c1 g) (c2 f + c2 g)
powerRing :: (Trans.C a) =>
Integer -> T a -> T a
powerRing p f =
let pa = fromInteger p
in Cons
(amp f ^ p)
(pa * c0 f) (pa * c1 f) (fromInteger p * c2 f)
powerAlgebraic :: (Trans.C a) =>
Rational -> T a -> T a
powerAlgebraic p f =
let pa = fromRational' p
in Cons
(amp f ^/ p)
(pa * c0 f) (pa * c1 f) (fromRational' p * c2 f)
powerTranscendental :: (Trans.C a) =>
a -> T a -> T a
powerTranscendental p f =
Cons
(amp f ^? p)
(Complex.scale p $ c0 f) (Complex.scale p $ c1 f) (p * c2 f)
convolve :: (Field.C a) =>
T a -> T a -> T a
convolve f g =
let s = c2 f + c2 g
in Cons
(amp f * amp g / s)
(c0 f + c0 g
Complex.scale (recip (4*s)) ((c1 f c1 g)^2))
(Complex.scale (c2 g / s) (c1 f) +
Complex.scale (c2 f / s) (c1 g))
(c2 f * c2 g / s)
convolveByTranslation :: (Field.C a) =>
T a -> T a -> T a
convolveByTranslation f0 g0 =
let fd = Complex.scale (recip (2 * c2 f0)) $ c1 f0
gd = Complex.scale (recip (2 * c2 g0)) $ c1 g0
f1 = translateComplex fd f0
g1 = translateComplex gd g0
s = c2 f1 + c2 g1
in translateComplex (negate $ fd + gd) $
Cons
(amp f1 * amp g1 / s)
(c0 f1 + c0 g1) zero
(c2 f1 * c2 g1 / s)
convolveByFourier :: (Field.C a) =>
T a -> T a -> T a
convolveByFourier f g =
reverse $ fourier $ multiply (fourier f) (fourier g)
fourier :: (Field.C a) =>
T a -> T a
fourier f =
let a = c0 f
b = c1 f
rc = recip $ c2 f
in Cons
(amp f * rc)
(Complex.scale (rc/4) (b^2) + a)
(Complex.scale rc $ Complex.quarterRight b)
rc
fourierByTranslation :: (Field.C a) =>
T a -> T a
fourierByTranslation f =
translateComplex (Complex.scale (1/2) $ Complex.quarterLeft $ c1 f) $
Cons (amp f / c2 f) (c0 f) zero (recip $ c2 f)
translate :: Ring.C a => a -> T a -> T a
translate d f =
let a = c0 f
b = c1 f
c = c2 f
in Cons
(amp f)
(Complex.fromReal (c*d^2) Complex.scale d b + a)
(Complex.fromReal (2*c*d) + b)
c
translateComplex :: Ring.C a => Complex.T a -> T a -> T a
translateComplex d f =
let a = c0 f
b = c1 f
c = c2 f
in Cons
(amp f)
(Complex.scale c (d^2) b*d + a)
(Complex.scale (2*c) d + b)
c
modulate :: Ring.C a => a -> T a -> T a
modulate d f =
Cons
(amp f)
(c0 f)
(c1 f + (zero +: 2*d))
(c2 f)
turn :: Ring.C a => a -> T a -> T a
turn d f =
Cons
(amp f)
(c0 f + (zero +: 2*d))
(c1 f)
(c2 f)
reverse :: Additive.C a => T a -> T a
reverse f =
f{c1 = negate $ c1 f}
dilate :: Field.C a => a -> T a -> T a
dilate k f =
Cons
(amp f)
(c0 f)
(Complex.scale (recip k) $ c1 f)
(c2 f / k^2)
shrink :: Ring.C a => a -> T a -> T a
shrink k f =
Cons
(amp f)
(c0 f)
(Complex.scale k $ c1 f)
(c2 f * k^2)
amplify :: (Ring.C a) => a -> T a -> T a
amplify k f =
Cons
(k^2 * amp f)
(c0 f)
(c1 f)
(c2 f)