{-# LANGUAGE CPP               #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MagicHash         #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DefaultSignatures #-}
{-# OPTIONS_GHC -fno-prof-auto #-}
module Basement.Numerical.Additive
    ( Additive(..)
    ) where

#include "MachDeps.h"

import           Basement.Compat.Base
import           Basement.Compat.C.Types
import           Basement.Compat.Natural
import           Basement.Numerical.Number
import qualified Prelude
import           GHC.Types
import           GHC.Prim
import           GHC.Int
import           GHC.Word
import           Basement.Bounded
import           Basement.Nat
import           Basement.Types.Word128 (Word128)
import           Basement.Types.Word256 (Word256)
import qualified Basement.Types.Word128 as Word128
import qualified Basement.Types.Word256 as Word256

#if WORD_SIZE_IN_BITS < 64
import           GHC.IntWord64
#endif

-- | Represent class of things that can be added together,
-- contains a neutral element and is commutative.
--
-- > x + azero = x
-- > azero + x = x
-- > x + y = y + x
--
class Additive a where
    {-# MINIMAL azero, (+) #-}
    azero :: a           -- the identity element over addition
    (+)   :: a -> a -> a -- the addition

    scale :: IsNatural n => n -> a -> a -- scale: repeated addition
    default scale :: (Enum n, IsNatural n) => n -> a -> a
    scale = n -> a -> a
forall n a. (Enum n, IsNatural n, Additive a) => n -> a -> a
scaleEnum

scaleEnum :: (Enum n, IsNatural n, Additive a) => n -> a -> a
scaleEnum :: n -> a -> a
scaleEnum n
0 a
_ = a
forall a. Additive a => a
azero
scaleEnum n
1 a
a = a
a
scaleEnum n
2 a
a = a
a a -> a -> a
forall a. Additive a => a -> a -> a
+ a
a
scaleEnum n
n a
a = a
a a -> a -> a
forall a. Additive a => a -> a -> a
+ n -> a -> a
forall n a. (Enum n, IsNatural n, Additive a) => n -> a -> a
scaleEnum (n -> n
forall a. Enum a => a -> a
pred n
n) a
a -- TODO optimise. define by group of 2.

infixl 6 +

instance Additive Integer where
    azero :: Integer
azero = Integer
0
    + :: Integer -> Integer -> Integer
(+) = Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> Integer -> Integer
scale = n -> Integer -> Integer
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Int where
    azero :: Int
azero = Int
0
    (I# Int#
a) + :: Int -> Int -> Int
+ (I# Int#
b) = Int# -> Int
I# (Int#
a Int# -> Int# -> Int#
+# Int#
b)
    scale :: n -> Int -> Int
scale = n -> Int -> Int
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Int8 where
    azero :: Int8
azero = Int8
0
    (I8# Int#
a) + :: Int8 -> Int8 -> Int8
+ (I8# Int#
b) = Int# -> Int8
I8# (Int# -> Int#
narrow8Int# (Int#
a Int# -> Int# -> Int#
+# Int#
b))
    scale :: n -> Int8 -> Int8
scale = n -> Int8 -> Int8
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Int16 where
    azero :: Int16
azero = Int16
0
    (I16# Int#
a) + :: Int16 -> Int16 -> Int16
+ (I16# Int#
b) = Int# -> Int16
I16# (Int# -> Int#
narrow16Int# (Int#
a Int# -> Int# -> Int#
+# Int#
b))
    scale :: n -> Int16 -> Int16
scale = n -> Int16 -> Int16
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Int32 where
    azero :: Int32
azero = Int32
0
    (I32# Int#
a) + :: Int32 -> Int32 -> Int32
+ (I32# Int#
b) = Int# -> Int32
I32# (Int# -> Int#
narrow32Int# (Int#
a Int# -> Int# -> Int#
+# Int#
b))
    scale :: n -> Int32 -> Int32
scale = n -> Int32 -> Int32
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Int64 where
    azero :: Int64
azero = Int64
0
#if WORD_SIZE_IN_BITS == 64
    (I64# Int#
a) + :: Int64 -> Int64 -> Int64
+ (I64# Int#
b) = Int# -> Int64
I64# (Int#
a Int# -> Int# -> Int#
+# Int#
b)
#else
    (I64# a) + (I64# b) = I64# (a `plusInt64#` b)
#endif
    scale :: n -> Int64 -> Int64
scale = n -> Int64 -> Int64
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Word where
    azero :: Word
azero = Word
0
    (W# Word#
a) + :: Word -> Word -> Word
+ (W# Word#
b) = Word# -> Word
W# (Word#
a Word# -> Word# -> Word#
`plusWord#` Word#
b)
    scale :: n -> Word -> Word
scale = n -> Word -> Word
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Natural where
    azero :: Natural
azero = Natural
0
    + :: Natural -> Natural -> Natural
(+) = Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> Natural -> Natural
scale = n -> Natural -> Natural
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Word8 where
    azero :: Word8
azero = Word8
0
    (W8# Word#
a) + :: Word8 -> Word8 -> Word8
+ (W8# Word#
b) = Word# -> Word8
W8# (Word# -> Word#
narrow8Word# (Word#
a Word# -> Word# -> Word#
`plusWord#` Word#
b))
    scale :: n -> Word8 -> Word8
scale = n -> Word8 -> Word8
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Word16 where
    azero :: Word16
azero = Word16
0
    (W16# Word#
a) + :: Word16 -> Word16 -> Word16
+ (W16# Word#
b) = Word# -> Word16
W16# (Word# -> Word#
narrow16Word# (Word#
a Word# -> Word# -> Word#
`plusWord#` Word#
b))
    scale :: n -> Word16 -> Word16
scale = n -> Word16 -> Word16
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Word32 where
    azero :: Word32
azero = Word32
0
    (W32# Word#
a) + :: Word32 -> Word32 -> Word32
+ (W32# Word#
b) = Word# -> Word32
W32# (Word# -> Word#
narrow32Word# (Word#
a Word# -> Word# -> Word#
`plusWord#` Word#
b))
    scale :: n -> Word32 -> Word32
scale = n -> Word32 -> Word32
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Word64 where
    azero :: Word64
azero = Word64
0
#if WORD_SIZE_IN_BITS == 64
    (W64# Word#
a) + :: Word64 -> Word64 -> Word64
+ (W64# Word#
b) = Word# -> Word64
W64# (Word#
a Word# -> Word# -> Word#
`plusWord#` Word#
b)
#else
    (W64# a) + (W64# b) = W64# (int64ToWord64# (word64ToInt64# a `plusInt64#` word64ToInt64# b))
#endif
    scale :: n -> Word64 -> Word64
scale = n -> Word64 -> Word64
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Word128 where
    azero :: Word128
azero = Word128
0
    + :: Word128 -> Word128 -> Word128
(+) = Word128 -> Word128 -> Word128
(Word128.+)
    scale :: n -> Word128 -> Word128
scale = n -> Word128 -> Word128
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Word256 where
    azero :: Word256
azero = Word256
0
    + :: Word256 -> Word256 -> Word256
(+) = Word256 -> Word256 -> Word256
(Word256.+)
    scale :: n -> Word256 -> Word256
scale = n -> Word256 -> Word256
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum

instance Additive Prelude.Float where
    azero :: Float
azero = Float
0.0
    (F# Float#
a) + :: Float -> Float -> Float
+ (F# Float#
b) = Float# -> Float
F# (Float#
a Float# -> Float# -> Float#
`plusFloat#` Float#
b)
    scale :: n -> Float -> Float
scale = n -> Float -> Float
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Prelude.Double where
    azero :: Double
azero = Double
0.0
    (D# Double#
a) + :: Double -> Double -> Double
+ (D# Double#
b) = Double# -> Double
D# (Double#
a Double# -> Double# -> Double#
+## Double#
b)
    scale :: n -> Double -> Double
scale = n -> Double -> Double
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive Prelude.Rational where
    azero :: Rational
azero = Rational
0.0
    + :: Rational -> Rational -> Rational
(+) = Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> Rational -> Rational
scale = n -> Rational -> Rational
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum

instance (KnownNat n, NatWithinBound Word64 n) => Additive (Zn64 n) where
    azero :: Zn64 n
azero = Word64 -> Zn64 n
forall (n :: Nat).
(KnownNat n, NatWithinBound Word64 n) =>
Word64 -> Zn64 n
zn64 Word64
0
    + :: Zn64 n -> Zn64 n -> Zn64 n
(+) = Zn64 n -> Zn64 n -> Zn64 n
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> Zn64 n -> Zn64 n
scale = n -> Zn64 n -> Zn64 n
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance KnownNat n => Additive (Zn n) where
    azero :: Zn n
azero = Natural -> Zn n
forall (n :: Nat). KnownNat n => Natural -> Zn n
zn Natural
0
    + :: Zn n -> Zn n -> Zn n
(+) = Zn n -> Zn n -> Zn n
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> Zn n -> Zn n
scale = n -> Zn n -> Zn n
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum

instance Additive CChar where
    azero :: CChar
azero = CChar
0
    + :: CChar -> CChar -> CChar
(+) = CChar -> CChar -> CChar
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CChar -> CChar
scale = n -> CChar -> CChar
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CSChar where
    azero :: CSChar
azero = CSChar
0
    + :: CSChar -> CSChar -> CSChar
(+) = CSChar -> CSChar -> CSChar
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CSChar -> CSChar
scale = n -> CSChar -> CSChar
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CUChar where
    azero :: CUChar
azero = CUChar
0
    + :: CUChar -> CUChar -> CUChar
(+) = CUChar -> CUChar -> CUChar
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CUChar -> CUChar
scale = n -> CUChar -> CUChar
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CShort where
    azero :: CShort
azero = CShort
0
    + :: CShort -> CShort -> CShort
(+) = CShort -> CShort -> CShort
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CShort -> CShort
scale = n -> CShort -> CShort
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CUShort where
    azero :: CUShort
azero = CUShort
0
    + :: CUShort -> CUShort -> CUShort
(+) = CUShort -> CUShort -> CUShort
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CUShort -> CUShort
scale = n -> CUShort -> CUShort
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CInt where
    azero :: CInt
azero = CInt
0
    + :: CInt -> CInt -> CInt
(+) = CInt -> CInt -> CInt
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CInt -> CInt
scale = n -> CInt -> CInt
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CUInt where
    azero :: CUInt
azero = CUInt
0
    + :: CUInt -> CUInt -> CUInt
(+) = CUInt -> CUInt -> CUInt
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CUInt -> CUInt
scale = n -> CUInt -> CUInt
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CLong where
    azero :: CLong
azero = CLong
0
    + :: CLong -> CLong -> CLong
(+) = CLong -> CLong -> CLong
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CLong -> CLong
scale = n -> CLong -> CLong
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CULong where
    azero :: CULong
azero = CULong
0
    + :: CULong -> CULong -> CULong
(+) = CULong -> CULong -> CULong
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CULong -> CULong
scale = n -> CULong -> CULong
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CPtrdiff where
    azero :: CPtrdiff
azero = CPtrdiff
0
    + :: CPtrdiff -> CPtrdiff -> CPtrdiff
(+) = CPtrdiff -> CPtrdiff -> CPtrdiff
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CPtrdiff -> CPtrdiff
scale = n -> CPtrdiff -> CPtrdiff
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CSize where
    azero :: CSize
azero = CSize
0
    + :: CSize -> CSize -> CSize
(+) = CSize -> CSize -> CSize
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CSize -> CSize
scale = n -> CSize -> CSize
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CWchar where
    azero :: CWchar
azero = CWchar
0
    + :: CWchar -> CWchar -> CWchar
(+) = CWchar -> CWchar -> CWchar
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CWchar -> CWchar
scale = n -> CWchar -> CWchar
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CSigAtomic where
    azero :: CSigAtomic
azero = CSigAtomic
0
    + :: CSigAtomic -> CSigAtomic -> CSigAtomic
(+) = CSigAtomic -> CSigAtomic -> CSigAtomic
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CSigAtomic -> CSigAtomic
scale = n -> CSigAtomic -> CSigAtomic
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CLLong where
    azero :: CLLong
azero = CLLong
0
    + :: CLLong -> CLLong -> CLLong
(+) = CLLong -> CLLong -> CLLong
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CLLong -> CLLong
scale = n -> CLLong -> CLLong
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CULLong where
    azero :: CULLong
azero = CULLong
0
    + :: CULLong -> CULLong -> CULLong
(+) = CULLong -> CULLong -> CULLong
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CULLong -> CULLong
scale = n -> CULLong -> CULLong
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CIntPtr where
    azero :: CIntPtr
azero = CIntPtr
0
    + :: CIntPtr -> CIntPtr -> CIntPtr
(+) = CIntPtr -> CIntPtr -> CIntPtr
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CIntPtr -> CIntPtr
scale = n -> CIntPtr -> CIntPtr
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CUIntPtr where
    azero :: CUIntPtr
azero = CUIntPtr
0
    + :: CUIntPtr -> CUIntPtr -> CUIntPtr
(+) = CUIntPtr -> CUIntPtr -> CUIntPtr
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CUIntPtr -> CUIntPtr
scale = n -> CUIntPtr -> CUIntPtr
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CIntMax where
    azero :: CIntMax
azero = CIntMax
0
    + :: CIntMax -> CIntMax -> CIntMax
(+) = CIntMax -> CIntMax -> CIntMax
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CIntMax -> CIntMax
scale = n -> CIntMax -> CIntMax
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CUIntMax where
    azero :: CUIntMax
azero = CUIntMax
0
    + :: CUIntMax -> CUIntMax -> CUIntMax
(+) = CUIntMax -> CUIntMax -> CUIntMax
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CUIntMax -> CUIntMax
scale = n -> CUIntMax -> CUIntMax
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CClock where
    azero :: CClock
azero = CClock
0
    + :: CClock -> CClock -> CClock
(+) = CClock -> CClock -> CClock
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CClock -> CClock
scale = n -> CClock -> CClock
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CTime where
    azero :: CTime
azero = CTime
0
    + :: CTime -> CTime -> CTime
(+) = CTime -> CTime -> CTime
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CTime -> CTime
scale = n -> CTime -> CTime
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CUSeconds where
    azero :: CUSeconds
azero = CUSeconds
0
    + :: CUSeconds -> CUSeconds -> CUSeconds
(+) = CUSeconds -> CUSeconds -> CUSeconds
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CUSeconds -> CUSeconds
scale = n -> CUSeconds -> CUSeconds
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CSUSeconds where
    azero :: CSUSeconds
azero = CSUSeconds
0
    + :: CSUSeconds -> CSUSeconds -> CSUSeconds
(+) = CSUSeconds -> CSUSeconds -> CSUSeconds
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CSUSeconds -> CSUSeconds
scale = n -> CSUSeconds -> CSUSeconds
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive COff where
    azero :: COff
azero = COff
0
    + :: COff -> COff -> COff
(+) = COff -> COff -> COff
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> COff -> COff
scale = n -> COff -> COff
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum

instance Additive CFloat where
    azero :: CFloat
azero = CFloat
0
    + :: CFloat -> CFloat -> CFloat
(+) = CFloat -> CFloat -> CFloat
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CFloat -> CFloat
scale = n -> CFloat -> CFloat
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum
instance Additive CDouble where
    azero :: CDouble
azero = CDouble
0
    + :: CDouble -> CDouble -> CDouble
(+) = CDouble -> CDouble -> CDouble
forall a. Num a => a -> a -> a
(Prelude.+)
    scale :: n -> CDouble -> CDouble
scale = n -> CDouble -> CDouble
forall a n. (Num a, IsNatural n) => n -> a -> a
scaleNum

scaleNum :: (Prelude.Num a, IsNatural n) => n -> a -> a
scaleNum :: n -> a -> a
scaleNum n
n a
a = (Natural -> a
forall a b. (Integral a, Num b) => a -> b
Prelude.fromIntegral (Natural -> a) -> Natural -> a
forall a b. (a -> b) -> a -> b
$ n -> Natural
forall a. IsNatural a => a -> Natural
toNatural n
n) a -> a -> a
forall a. Num a => a -> a -> a
Prelude.* a
a