-- | 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)@.
-- * Sign : @sgn x = 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
-- the relevant typeclasses 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
  -- | Returns the norm.
  --
  -- @since 0.1
  norm :: s -> s

  -- | Sign function. Notice that when 'norm' is 'abs', this is the familiar
  -- 'signum' function i.e.
  --
  -- @
  -- sgn x
  --   | x < 0 = -1
  --   | x == 0 = 0
  --   | x > 0 = 1
  -- @
  --
  -- @since 0.1
  sgn :: s -> s

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

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

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

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

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

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

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

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

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

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

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

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

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

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

-- | @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 #-}
  sgn :: Ratio Integer -> Ratio Integer
sgn = Ratio Integer -> Ratio Integer
forall a. Num a => a -> a
signum
  {-# INLINE sgn #-}

-- | @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 #-}
  sgn :: Ratio Natural -> Ratio Natural
sgn = Ratio Natural -> Ratio Natural
forall a. Num a => a -> a
signum
  {-# INLINE sgn #-}

-- | @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 #-}
  sgn :: Complex a -> Complex a
sgn = Complex a -> Complex a
forall a. Num a => a -> a
signum
  {-# INLINE sgn #-}