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

import Data.Coerce (coerce)
import Data.Complex (Complex)
import Data.Fixed (Fixed, HasResolution)
import Data.Int (Int16, Int32, Int64, Int8)
import Data.Kind (Constraint, Type)
import Data.Ratio (Ratio)
import Data.Word (Word16, Word32, Word64, Word8)
import Numeric.Algebra.Additive.AMonoid (AMonoid (zero))
import Numeric.Algebra.Deriving
  ( FromFractional (MkFromFractional),
    FromIntegral (MkFromIntegral),
    FromNum (MkFromNum),
  )

-- | Defines an additive group.
--
-- @since 0.1
type AGroup :: Type -> Constraint
class (AMonoid g) => AGroup g where
  -- | @since 0.1
  (.-.) :: g -> g -> g

infixl 6 .-.

-- | @since 0.1
anegate :: (AGroup g) => g -> g
anegate :: forall g. AGroup g => g -> g
anegate g
n = g
forall m. AMonoid m => m
zero g -> g -> g
forall g. AGroup g => g -> g -> g
.-. g
n
{-# INLINE anegate #-}

-- | @since 0.1
deriving via (FromNum a) instance (Num a) => AGroup (FromFractional a)

-- | @since 0.1
deriving via (FromNum a) instance (Num a) => AGroup (FromIntegral a)

-- | @since 0.1
instance (Num a) => AGroup (FromNum a) where
  .-. :: FromNum a -> FromNum a -> FromNum a
(.-.) = forall a b. Coercible a b => a -> b
forall a b. Coercible a b => a -> b
coerce @(a -> a -> a) @(FromNum a -> FromNum a -> FromNum a) (-)
  {-# INLINE (.-.) #-}

-- | @since 0.1
deriving via (FromNum Double) instance AGroup Double

-- | @since 0.1
deriving via (FromNum Float) instance AGroup Float

-- | @since 0.1
deriving via (FromNum Int) instance AGroup Int

-- | @since 0.1
deriving via (FromNum Int8) instance AGroup Int8

-- | @since 0.1
deriving via (FromNum Int16) instance AGroup Int16

-- | @since 0.1
deriving via (FromNum Int32) instance AGroup Int32

-- | @since 0.1
deriving via (FromNum Int64) instance AGroup Int64

-- | @since 0.1
deriving via (FromNum Integer) instance AGroup Integer

-- | @since 0.1
deriving via (FromNum Word) instance AGroup Word

-- | @since 0.1
deriving via (FromNum Word8) instance AGroup Word8

-- | @since 0.1
deriving via (FromNum Word16) instance AGroup Word16

-- | @since 0.1
deriving via (FromNum Word32) instance AGroup Word32

-- | @since 0.1
deriving via (FromNum Word64) instance AGroup Word64

-- | @since 0.1
deriving via (FromNum (Ratio Integer)) instance AGroup (Ratio Integer)

-- | @since 0.1
deriving via (FromNum (Complex a)) instance (RealFloat a) => AGroup (Complex a)

-- | @since 0.1
deriving via (FromNum (Fixed k)) instance (HasResolution k) => AGroup (Fixed k)

-- | @since 0.1
instance (AGroup a) => AGroup (a, a) where
  (a
x1, a
x2) .-. :: (a, a) -> (a, a) -> (a, a)
.-. (a
y1, a
y2) = (a
x1 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y1, a
x2 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y2)
  {-# INLINE (.-.) #-}

-- | @since 0.1
instance (AGroup a) => AGroup (a, a, a) where
  (a
x1, a
x2, a
x3) .-. :: (a, a, a) -> (a, a, a) -> (a, a, a)
.-. (a
y1, a
y2, a
y3) = (a
x1 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y1, a
x2 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y2, a
x3 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y3)
  {-# INLINE (.-.) #-}

-- | @since 0.1
instance (AGroup a) => AGroup (a, a, a, a) where
  (a
x1, a
x2, a
x3, a
x4) .-. :: (a, a, a, a) -> (a, a, a, a) -> (a, a, a, a)
.-. (a
y1, a
y2, a
y3, a
y4) =
    ( a
x1 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y1,
      a
x2 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y2,
      a
x3 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y3,
      a
x4 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y4
    )
  {-# INLINE (.-.) #-}

-- | @since 0.1
instance (AGroup a) => AGroup (a, a, a, a, a) where
  (a
x1, a
x2, a
x3, a
x4, a
x5) .-. :: (a, a, a, a, a) -> (a, a, a, a, a) -> (a, a, a, a, a)
.-. (a
y1, a
y2, a
y3, a
y4, a
y5) =
    ( a
x1 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y1,
      a
x2 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y2,
      a
x3 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y3,
      a
x4 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y4,
      a
x5 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y5
    )
  {-# INLINE (.-.) #-}

-- | @since 0.1
instance (AGroup a) => AGroup (a, a, a, a, a, a) where
  (a
x1, a
x2, a
x3, a
x4, a
x5, a
x6) .-. :: (a, a, a, a, a, a) -> (a, a, a, a, a, a) -> (a, a, a, a, a, a)
.-. (a
y1, a
y2, a
y3, a
y4, a
y5, a
y6) =
    ( a
x1 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y1,
      a
x2 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y2,
      a
x3 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y3,
      a
x4 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y4,
      a
x5 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y5,
      a
x6 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y6
    )
  {-# INLINE (.-.) #-}

-- | @since 0.1
instance (AGroup a) => AGroup (a, a, a, a, a, a, a) where
  (a
x1, a
x2, a
x3, a
x4, a
x5, a
x6, a
x7) .-. :: (a, a, a, a, a, a, a)
-> (a, a, a, a, a, a, a) -> (a, a, a, a, a, a, a)
.-. (a
y1, a
y2, a
y3, a
y4, a
y5, a
y6, a
y7) =
    ( a
x1 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y1,
      a
x2 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y2,
      a
x3 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y3,
      a
x4 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y4,
      a
x5 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y5,
      a
x6 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y6,
      a
x7 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y7
    )
  {-# INLINE (.-.) #-}

-- | @since 0.1
instance (AGroup a) => AGroup (a, a, a, a, a, a, a, a) where
  (a
x1, a
x2, a
x3, a
x4, a
x5, a
x6, a
x7, a
x8) .-. :: (a, a, a, a, a, a, a, a)
-> (a, a, a, a, a, a, a, a) -> (a, a, a, a, a, a, a, a)
.-. (a
y1, a
y2, a
y3, a
y4, a
y5, a
y6, a
y7, a
y8) =
    ( a
x1 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y1,
      a
x2 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y2,
      a
x3 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y3,
      a
x4 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y4,
      a
x5 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y5,
      a
x6 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y6,
      a
x7 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y7,
      a
x8 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y8
    )
  {-# INLINE (.-.) #-}

-- | @since 0.1
instance (AGroup a) => AGroup (a, a, a, a, a, a, a, a, a) where
  (a
x1, a
x2, a
x3, a
x4, a
x5, a
x6, a
x7, a
x8, a
x9) .-. :: (a, a, a, a, a, a, a, a, a)
-> (a, a, a, a, a, a, a, a, a) -> (a, a, a, a, a, a, a, a, a)
.-. (a
y1, a
y2, a
y3, a
y4, a
y5, a
y6, a
y7, a
y8, a
y9) =
    ( a
x1 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y1,
      a
x2 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y2,
      a
x3 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y3,
      a
x4 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y4,
      a
x5 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y5,
      a
x6 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y6,
      a
x7 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y7,
      a
x8 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y8,
      a
x9 a -> a -> a
forall g. AGroup g => g -> g -> g
.-. a
y9
    )
  {-# INLINE (.-.) #-}