{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}

{- |
Abstraction of normed vector spaces
-}

module Algebra.NormedSpace.Euclidean where

import NumericPrelude.Base
import NumericPrelude.Numeric (sqr, abs, zero, (+), sum, Float, Double, Int, Integer, )
import qualified Prelude as P

import qualified Number.Ratio as Ratio

import qualified Algebra.PrincipalIdealDomain as PID
import qualified Algebra.Algebraic as Algebraic
import qualified Algebra.Absolute      as Absolute
import qualified Algebra.Module    as Module

import qualified Data.Complex as Complex98
import qualified Data.Foldable as Fold


{-|
Helper class for 'C' that does not need an algebraic type @a@.

Minimal definition:
'normSqr'
-}
class (Absolute.C a, Module.C a v) => Sqr a v where
  {-| Square of the Euclidean norm of a vector.
      This is sometimes easier to implement. -}
  normSqr :: v -> a
--  normSqr = sqr . norm

{- |
Default definition for 'normSqr' that is based on 'Fold.Foldable' class.
-}
{-# INLINE normSqrFoldable #-}
normSqrFoldable ::
   (Sqr a v, Fold.Foldable f) => f v -> a
normSqrFoldable :: f v -> a
normSqrFoldable =
   (a -> v -> a) -> a -> f v -> a
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
Fold.foldl (\a
a v
v -> a
a a -> a -> a
forall a. C a => a -> a -> a
+ v -> a
forall a v. Sqr a v => v -> a
normSqr v
v) a
forall a. C a => a
zero

{- |
Default definition for 'normSqr' that is based on 'Fold.Foldable' class
and the argument vector has at least one component.
-}
{-# INLINE normSqrFoldable1 #-}
normSqrFoldable1 ::
   (Sqr a v, Fold.Foldable f, Functor f) => f v -> a
normSqrFoldable1 :: f v -> a
normSqrFoldable1 =
   (a -> a -> a) -> f a -> a
forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
Fold.foldl1 a -> a -> a
forall a. C a => a -> a -> a
(+) (f a -> a) -> (f v -> f a) -> f v -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (v -> a) -> f v -> f a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap v -> a
forall a v. Sqr a v => v -> a
normSqr


{-|
A vector space equipped with an Euclidean or a Hilbert norm.

Minimal definition:
'norm'
-}
class (Sqr a v) => C a v where
  {-| Euclidean norm of a vector. -}
  norm :: v -> a


defltNorm :: (Algebraic.C a, Sqr a v) => v -> a
defltNorm :: v -> a
defltNorm = a -> a
forall a. C a => a -> a
Algebraic.sqrt (a -> a) -> (v -> a) -> v -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. v -> a
forall a v. Sqr a v => v -> a
normSqr


{-* Instances for atomic types -}

instance Sqr Float Float where
  normSqr :: Float -> Float
normSqr = Float -> Float
forall a. C a => a -> a
sqr

instance C Float Float where
  norm :: Float -> Float
norm    = Float -> Float
forall a. C a => a -> a
abs

instance Sqr Double Double where
  normSqr :: Double -> Double
normSqr = Double -> Double
forall a. C a => a -> a
sqr

instance C Double Double where
  norm :: Double -> Double
norm    = Double -> Double
forall a. C a => a -> a
abs

instance Sqr Int Int where
  normSqr :: Int -> Int
normSqr = Int -> Int
forall a. C a => a -> a
sqr

instance C Int Int where
  norm :: Int -> Int
norm    = Int -> Int
forall a. C a => a -> a
abs

instance Sqr Integer Integer where
  normSqr :: Integer -> Integer
normSqr = Integer -> Integer
forall a. C a => a -> a
sqr

instance C Integer Integer where
  norm :: Integer -> Integer
norm    = Integer -> Integer
forall a. C a => a -> a
abs


{-* Instances for composed types -}

instance (Absolute.C a, PID.C a) => Sqr (Ratio.T a) (Ratio.T a) where
  normSqr :: T a -> T a
normSqr = T a -> T a
forall a. C a => a -> a
sqr

instance (Sqr a v0, Sqr a v1) => Sqr a (v0, v1) where
  normSqr :: (v0, v1) -> a
normSqr (v0
x0,v1
x1) = v0 -> a
forall a v. Sqr a v => v -> a
normSqr v0
x0 a -> a -> a
forall a. C a => a -> a -> a
+ v1 -> a
forall a v. Sqr a v => v -> a
normSqr v1
x1

instance (Algebraic.C a, Sqr a v0, Sqr a v1) => C a (v0, v1) where
  norm :: (v0, v1) -> a
norm    = (v0, v1) -> a
forall a v. (C a, Sqr a v) => v -> a
defltNorm

instance (Sqr a v0, Sqr a v1, Sqr a v2) => Sqr a (v0, v1, v2) where
  normSqr :: (v0, v1, v2) -> a
normSqr (v0
x0,v1
x1,v2
x2) = v0 -> a
forall a v. Sqr a v => v -> a
normSqr v0
x0 a -> a -> a
forall a. C a => a -> a -> a
+ v1 -> a
forall a v. Sqr a v => v -> a
normSqr v1
x1 a -> a -> a
forall a. C a => a -> a -> a
+ v2 -> a
forall a v. Sqr a v => v -> a
normSqr v2
x2

instance (Algebraic.C a, Sqr a v0, Sqr a v1, Sqr a v2) => C a (v0, v1, v2) where
  norm :: (v0, v1, v2) -> a
norm    = (v0, v1, v2) -> a
forall a v. (C a, Sqr a v) => v -> a
defltNorm

instance (Sqr a v) => Sqr a [v] where
  normSqr :: [v] -> a
normSqr = [a] -> a
forall a. C a => [a] -> a
sum ([a] -> a) -> ([v] -> [a]) -> [v] -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (v -> a) -> [v] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map v -> a
forall a v. Sqr a v => v -> a
normSqr

instance (Algebraic.C a, Sqr a v) => C a [v] where
  norm :: [v] -> a
norm    = [v] -> a
forall a v. (C a, Sqr a v) => v -> a
defltNorm


instance (Sqr a v, P.RealFloat v) => Sqr a (Complex98.Complex v) where
  normSqr :: Complex v -> a
normSqr (v
x0 Complex98.:+ v
x1) = v -> a
forall a v. Sqr a v => v -> a
normSqr v
x0 a -> a -> a
forall a. C a => a -> a -> a
+ v -> a
forall a v. Sqr a v => v -> a
normSqr v
x1

instance
  (Algebraic.C a, Sqr a v, P.RealFloat v) =>
    C a (Complex98.Complex v) where
  norm :: Complex v -> a
norm    = Complex v -> a
forall a v. (C a, Sqr a v) => v -> a
defltNorm