-- | Provides the 'Normed' typeclass.
--
-- @since 0.1
module Numeric.Algebra.Normed
  ( Normed (..),
  )
where

import Data.Complex (Complex)
import Data.Int (Int16, Int32, Int64, Int8)
import Data.Kind (Constraint, Type)
import Data.Ratio (Ratio)
import Data.Word (Word16, Word32, Word64, Word8)
import GHC.Natural (Natural)

-- | Defines a \"norm\" on a given structure. We have the following laws:
--
-- * Positive definiteness: @norm x > 0 for x /= 0, norm 0 = 0@.
-- * Subadditivity: @norm (x + y) <= norm x + norm y@.
-- * Inversion : @norm x = norm (-x)@.
--
-- Notice these laws require various algebraic assumptions, from a semigroup
-- up to a group structure. It is expected that types that implement
-- 'Numeric.Algebra.Additive.ASemigroup.ASemigroup',
-- 'Numeric.Algebra.Additive.ASemigroup.AMonoid', and
-- 'Numeric.Algebra.Additive.ASemigroup.AGroup' will follow the respective laws.
--
-- We do not /require/ any of these typeclasses as constraints as it is
-- possible that we may want to abstract over "positive" types with a type
-- that does not have an additive semigroup instance (consider multiplicative
-- groups).
--
-- @since 0.1
type Normed :: Type -> Constraint
class Normed s where
  -- | @since 0.1
  norm :: s -> s

-- | @since 0.1
instance Normed Double where
  norm :: Double -> Double
norm = Double -> Double
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed Float where
  norm :: Float -> Float
norm = Float -> Float
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed Int where
  norm :: Int -> Int
norm = Int -> Int
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed Int8 where
  norm :: Int8 -> Int8
norm = Int8 -> Int8
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed Int16 where
  norm :: Int16 -> Int16
norm = Int16 -> Int16
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed Int32 where
  norm :: Int32 -> Int32
norm = Int32 -> Int32
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed Int64 where
  norm :: Int64 -> Int64
norm = Int64 -> Int64
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed Integer where
  norm :: Integer -> Integer
norm = Integer -> Integer
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed Word where
  norm :: Word -> Word
norm = Word -> Word
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed Word8 where
  norm :: Word8 -> Word8
norm = Word8 -> Word8
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed Word16 where
  norm :: Word16 -> Word16
norm = Word16 -> Word16
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed Word32 where
  norm :: Word32 -> Word32
norm = Word32 -> Word32
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed Word64 where
  norm :: Word64 -> Word64
norm = Word64 -> Word64
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed Natural where
  norm :: Natural -> Natural
norm = Natural -> Natural
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed (Ratio Integer) where
  norm :: Ratio Integer -> Ratio Integer
norm = Ratio Integer -> Ratio Integer
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance Normed (Ratio Natural) where
  norm :: Ratio Natural -> Ratio Natural
norm = Ratio Natural -> Ratio Natural
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance (RealFloat a) => Normed (Complex a) where
  norm :: Complex a -> Complex a
norm = Complex a -> Complex a
forall a. Num a => a -> a
abs
  {-# INLINE norm #-}

-- | @since 0.1
instance (Normed a) => Normed (a, a) where
  norm :: (a, a) -> (a, a)
norm (a
x1, a
x2) = (a -> a
forall s. Normed s => s -> s
norm a
x1, a -> a
forall s. Normed s => s -> s
norm a
x2)
  {-# INLINE norm #-}

-- | @since 0.1
instance (Normed a) => Normed (a, a, a) where
  norm :: (a, a, a) -> (a, a, a)
norm (a
x1, a
x2, a
x3) = (a -> a
forall s. Normed s => s -> s
norm a
x1, a -> a
forall s. Normed s => s -> s
norm a
x2, a -> a
forall s. Normed s => s -> s
norm a
x3)
  {-# INLINE norm #-}

-- | @since 0.1
instance (Normed a) => Normed (a, a, a, a) where
  norm :: (a, a, a, a) -> (a, a, a, a)
norm (a
x1, a
x2, a
x3, a
x4) = (a -> a
forall s. Normed s => s -> s
norm a
x1, a -> a
forall s. Normed s => s -> s
norm a
x2, a -> a
forall s. Normed s => s -> s
norm a
x3, a -> a
forall s. Normed s => s -> s
norm a
x4)
  {-# INLINE norm #-}

-- | @since 0.1
instance (Normed a) => Normed (a, a, a, a, a) where
  norm :: (a, a, a, a, a) -> (a, a, a, a, a)
norm (a
x1, a
x2, a
x3, a
x4, a
x5) = (a -> a
forall s. Normed s => s -> s
norm a
x1, a -> a
forall s. Normed s => s -> s
norm a
x2, a -> a
forall s. Normed s => s -> s
norm a
x3, a -> a
forall s. Normed s => s -> s
norm a
x4, a -> a
forall s. Normed s => s -> s
norm a
x5)
  {-# INLINE norm #-}

-- | @since 0.1
instance (Normed a) => Normed (a, a, a, a, a, a) where
  norm :: (a, a, a, a, a, a) -> (a, a, a, a, a, a)
norm (a
x1, a
x2, a
x3, a
x4, a
x5, a
x6) =
    ( a -> a
forall s. Normed s => s -> s
norm a
x1,
      a -> a
forall s. Normed s => s -> s
norm a
x2,
      a -> a
forall s. Normed s => s -> s
norm a
x3,
      a -> a
forall s. Normed s => s -> s
norm a
x4,
      a -> a
forall s. Normed s => s -> s
norm a
x5,
      a -> a
forall s. Normed s => s -> s
norm a
x6
    )
  {-# INLINE norm #-}

-- | @since 0.1
instance (Normed a) => Normed (a, a, a, a, a, a, a) where
  norm :: (a, a, a, a, a, a, a) -> (a, a, a, a, a, a, a)
norm (a
x1, a
x2, a
x3, a
x4, a
x5, a
x6, a
x7) =
    ( a -> a
forall s. Normed s => s -> s
norm a
x1,
      a -> a
forall s. Normed s => s -> s
norm a
x2,
      a -> a
forall s. Normed s => s -> s
norm a
x3,
      a -> a
forall s. Normed s => s -> s
norm a
x4,
      a -> a
forall s. Normed s => s -> s
norm a
x5,
      a -> a
forall s. Normed s => s -> s
norm a
x6,
      a -> a
forall s. Normed s => s -> s
norm a
x7
    )
  {-# INLINE norm #-}

-- | @since 0.1
instance (Normed a) => Normed (a, a, a, a, a, a, a, a) where
  norm :: (a, a, a, a, a, a, a, a) -> (a, a, a, a, a, a, a, a)
norm (a
x1, a
x2, a
x3, a
x4, a
x5, a
x6, a
x7, a
x8) =
    ( a -> a
forall s. Normed s => s -> s
norm a
x1,
      a -> a
forall s. Normed s => s -> s
norm a
x2,
      a -> a
forall s. Normed s => s -> s
norm a
x3,
      a -> a
forall s. Normed s => s -> s
norm a
x4,
      a -> a
forall s. Normed s => s -> s
norm a
x5,
      a -> a
forall s. Normed s => s -> s
norm a
x6,
      a -> a
forall s. Normed s => s -> s
norm a
x7,
      a -> a
forall s. Normed s => s -> s
norm a
x8
    )
  {-# INLINE norm #-}

-- | @since 0.1
instance (Normed a) => Normed (a, a, a, a, a, a, a, a, a) where
  norm :: (a, a, a, a, a, a, a, a, a) -> (a, a, a, a, a, a, a, a, a)
norm (a
x1, a
x2, a
x3, a
x4, a
x5, a
x6, a
x7, a
x8, a
x9) =
    ( a -> a
forall s. Normed s => s -> s
norm a
x1,
      a -> a
forall s. Normed s => s -> s
norm a
x2,
      a -> a
forall s. Normed s => s -> s
norm a
x3,
      a -> a
forall s. Normed s => s -> s
norm a
x4,
      a -> a
forall s. Normed s => s -> s
norm a
x5,
      a -> a
forall s. Normed s => s -> s
norm a
x6,
      a -> a
forall s. Normed s => s -> s
norm a
x7,
      a -> a
forall s. Normed s => s -> s
norm a
x8,
      a -> a
forall s. Normed s => s -> s
norm a
x9
    )
  {-# INLINE norm #-}