{-# 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.Compat.Primitive
import           Basement.Numerical.Number
import qualified Prelude
import           GHC.Types (Float(..), Double(..))
import           GHC.Prim (plusWord#, plusFloat#, (+#), (+##))
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#
a Int# -> Int# -> Int#
`plusInt8#` 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#
a Int# -> Int# -> Int#
`plusInt16#` 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#
a Int# -> Int# -> Int#
`plusInt32#` 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#
a Word# -> Word# -> Word#
`plusWord8#` 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#
a Word# -> Word# -> Word#
`plusWord16#` 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#
a Word# -> Word# -> Word#
`plusWord32#` 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