{-# LANGUAGE NoImplicitPrelude #-}
{-
Reciprocal of variance of a Gaussian bell curve.
We describe the curve only in terms of its variance
thus we represent a bell curve at the coordinate origin
neglecting its amplitude.

We could also define the amplitude as @root 4 c@,
but then @dilate@ and @shrink@ also include an amplification.

We could do some projective geometry in the exponent
in order to also have zero variance,
which corresponds to the dirac impulse.
-}
module MathObj.Gaussian.Variance where

import qualified MathObj.Polynomial as Poly

import qualified Algebra.Transcendental as Trans
import qualified Algebra.Algebraic      as Algebraic
import qualified Algebra.Field          as Field
import qualified Algebra.Real           as Real
import qualified Algebra.Ring           as Ring
import qualified Algebra.Additive       as Additive

import Algebra.Transcendental (pi, )
import Algebra.Ring ((*), (^), )
import Algebra.Additive ((+))

import Test.QuickCheck (Arbitrary, arbitrary, coarbitrary, )


-- import Prelude (($))
import NumericPrelude
import PreludeBase


data T a = Cons {c :: a}
   deriving (Eq, Show)

instance (Real.C a, Arbitrary a) => Arbitrary (T a) where
   arbitrary = fmap (Cons . (1+) . abs) arbitrary
   coarbitrary = undefined


constant :: Additive.C a => T a
constant = Cons zero

{-# INLINE evaluate #-}
evaluate :: (Trans.C a) =>
   T a -> a -> a
evaluate f x =
   exp $ (-pi * c f * x^2)

exponentPolynomial :: (Additive.C a) =>
   T a -> Poly.T a
exponentPolynomial f =
   Poly.fromCoeffs [zero, zero, c f]


norm1 :: (Algebraic.C a) => T a -> a
norm1 f =
   recip $ sqrt $ c f

norm2 :: (Algebraic.C a) => T a -> a
norm2 f =
   recip $ sqrt $ sqrt $ 2 * c f

normP :: (Trans.C a) => a -> T a -> a
normP p f =
   (p * c f) ^? (- recip (2*p))


variance :: (Trans.C a) =>
   T a -> a
variance f =
   recip $ c f * 2*pi

multiply :: (Additive.C a) =>
   T a -> T a -> T a
multiply f g =
   Cons $ c f + c g

{- |
> convolve x y t =
>    integrate $ \s -> x s * y(t-s)
-}
convolve :: (Field.C a) =>
   T a -> T a -> T a
convolve f g =
   Cons $ recip $ recip (c f) + recip (c g)

{- |
> fourier x f =
>    integrate $ \t -> x t * cis (-2*pi*t*f)
-}
fourier :: (Field.C a) =>
   T a -> T a
fourier f =
   Cons $ recip $ c f
{-
fourier (t -> exp(-(a*t)^2))
-}

dilate :: (Field.C a) => a -> T a -> T a
dilate k f =
   Cons $ c f / k^2

shrink :: (Ring.C a) => a -> T a -> T a
shrink k f =
   Cons $ c f * k^2

{- laws
fourier (convolve f g) = multiply (fourier f) (fourier g)

dilate k (dilate m f) = dilate (k*m) f

dilate k (shrink k f) = f

variance (dilate k f) = k^2 * variance f

variance (convolve f g) = variance f + variance g
-}