{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{- |
This number type is intended for tests of functions over fields,
where the field elements need constant space.
This way we can provide a Storable instance.
For 'Rational' this would not be possible.

However, be aware that sums of non-zero elements may yield zero.
Thus division is not always defined, where it is for rational numbers.
-}
module Number.GaloisField2p32m5 where

import qualified Number.ResidueClass as RC
import qualified Algebra.ZeroTestable as ZeroTestable
import qualified Algebra.Module   as Module
import qualified Algebra.Field    as Field
import qualified Algebra.Ring     as Ring
import qualified Algebra.Additive as Additive

import Data.Int (Int64, )
import Data.Word (Word32, Word64, )

import qualified Foreign.Storable.Newtype as SN
import qualified Foreign.Storable as St

import Test.QuickCheck (Arbitrary(arbitrary), )

import NumericPrelude.Base
import NumericPrelude.Numeric


{- $setup
>>> import qualified Number.GaloisField2p32m5 as GF
>>> import qualified Algebra.Laws as Laws
>>> import Test.QuickCheck ((==>))
>>> import NumericPrelude.Numeric
>>> import NumericPrelude.Base
>>> import Prelude ()
>>>
>>> gf :: GF.T -> GF.T
>>> gf = id
-}

{- |
prop> Laws.identity (+) zero . gf
prop> Laws.commutative (+) . gf
prop> Laws.associative (+) . gf
prop> Laws.inverse (+) negate zero . gf
prop> \x -> Laws.inverse (+) (x-) (gf x)
prop> Laws.identity (*) one . gf
prop> Laws.commutative (*) . gf
prop> Laws.associative (*) . gf
prop> \y -> gf y /= zero ==> Laws.inverse (*) recip one y
prop> \y x -> gf y /= zero ==> Laws.inverse (*) (x/) x y
-}
newtype T = Cons {T -> Word32
decons :: Word32}
   deriving T -> T -> Bool
(T -> T -> Bool) -> (T -> T -> Bool) -> Eq T
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: T -> T -> Bool
$c/= :: T -> T -> Bool
== :: T -> T -> Bool
$c== :: T -> T -> Bool
Eq

{-# INLINE appPrec #-}
appPrec :: Int
appPrec :: Int
appPrec  = Int
10

instance Show T where
   showsPrec :: Int -> T -> ShowS
showsPrec Int
p (Cons Word32
x) =
      Int -> Word32 -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
p Word32
x
{-
      showParen (p >= appPrec)
         (showString "GF2p32m5.Cons " . shows x)
-}

instance Arbitrary T where
   arbitrary :: Gen T
arbitrary = (Integer -> T) -> Gen Integer -> Gen T
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Word32 -> T
Cons (Word32 -> T) -> (Integer -> Word32) -> Integer -> T
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Word32
forall a. C a => Integer -> a
fromInteger (Integer -> Word32) -> (Integer -> Integer) -> Integer -> Word32
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Integer -> Integer -> Integer) -> Integer -> Integer -> Integer
forall a b c. (a -> b -> c) -> b -> a -> c
flip Integer -> Integer -> Integer
forall a. C a => a -> a -> a
mod Integer
forall a. C a => a
base) Gen Integer
forall a. Arbitrary a => Gen a
arbitrary

instance St.Storable T where
   sizeOf :: T -> Int
sizeOf = (T -> Word32) -> T -> Int
forall core wrapper.
Storable core =>
(wrapper -> core) -> wrapper -> Int
SN.sizeOf T -> Word32
decons
   alignment :: T -> Int
alignment = (T -> Word32) -> T -> Int
forall core wrapper.
Storable core =>
(wrapper -> core) -> wrapper -> Int
SN.alignment T -> Word32
decons
   peek :: Ptr T -> IO T
peek = (Word32 -> T) -> Ptr T -> IO T
forall core wrapper.
Storable core =>
(core -> wrapper) -> Ptr wrapper -> IO wrapper
SN.peek Word32 -> T
Cons
   poke :: Ptr T -> T -> IO ()
poke = (T -> Word32) -> Ptr T -> T -> IO ()
forall core wrapper.
Storable core =>
(wrapper -> core) -> Ptr wrapper -> wrapper -> IO ()
SN.poke T -> Word32
decons


base :: Ring.C a => a
base :: a
base = a
2a -> Integer -> a
forall a. C a => a -> Integer -> a
^Integer
32a -> a -> a
forall a. C a => a -> a -> a
-a
5


{-# INLINE lift2 #-}
lift2 :: (Word64 -> Word64 -> Word64) -> (T -> T -> T)
lift2 :: (Word64 -> Word64 -> Word64) -> T -> T -> T
lift2 Word64 -> Word64 -> Word64
f (Cons Word32
x) (Cons Word32
y) =
   Word32 -> T
Cons (Word64 -> Word32
forall a b. (C a, C b) => a -> b
fromIntegral (Word64 -> Word64 -> Word64
forall a. C a => a -> a -> a
mod (Word64 -> Word64 -> Word64
f (Word32 -> Word64
forall a b. (C a, C b) => a -> b
fromIntegral Word32
x) (Word32 -> Word64
forall a b. (C a, C b) => a -> b
fromIntegral Word32
y)) Word64
forall a. C a => a
base))

{-# INLINE lift2Integer #-}
lift2Integer :: (Int64 -> Int64 -> Int64) -> (T -> T -> T)
lift2Integer :: (Int64 -> Int64 -> Int64) -> T -> T -> T
lift2Integer Int64 -> Int64 -> Int64
f (Cons Word32
x) (Cons Word32
y) =
   Word32 -> T
Cons (Int64 -> Word32
forall a b. (C a, C b) => a -> b
fromIntegral (Int64 -> Int64 -> Int64
forall a. C a => a -> a -> a
mod (Int64 -> Int64 -> Int64
f (Word32 -> Int64
forall a b. (C a, C b) => a -> b
fromIntegral Word32
x) (Word32 -> Int64
forall a b. (C a, C b) => a -> b
fromIntegral Word32
y)) Int64
forall a. C a => a
base))


instance Additive.C T where
   zero :: T
zero = Word32 -> T
Cons Word32
forall a. C a => a
zero
   + :: T -> T -> T
(+) = (Word64 -> Word64 -> Word64) -> T -> T -> T
lift2 Word64 -> Word64 -> Word64
forall a. C a => a -> a -> a
(+)
--   (-) = lift2 (-)
   T
x- :: T -> T -> T
-T
y = T
x T -> T -> T
forall a. C a => a -> a -> a
+ T -> T
forall a. C a => a -> a
negate T
y
   negate :: T -> T
negate n :: T
n@(Cons Word32
x) =
      if Word32
xWord32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
==Word32
0
        then T
n
        else Word32 -> T
Cons (Word32
forall a. C a => a
baseWord32 -> Word32 -> Word32
forall a. C a => a -> a -> a
-Word32
x)

instance Ring.C T where
   one :: T
one = Word32 -> T
Cons Word32
forall a. C a => a
one
   * :: T -> T -> T
(*) = (Word64 -> Word64 -> Word64) -> T -> T -> T
lift2 Word64 -> Word64 -> Word64
forall a. C a => a -> a -> a
(*)
   fromInteger :: Integer -> T
fromInteger =
      Word32 -> T
Cons (Word32 -> T) -> (Integer -> Word32) -> Integer -> T
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Word32
forall a. C a => Integer -> a
fromInteger (Integer -> Word32) -> (Integer -> Integer) -> Integer -> Word32
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Integer -> Integer -> Integer) -> Integer -> Integer -> Integer
forall a b c. (a -> b -> c) -> b -> a -> c
flip Integer -> Integer -> Integer
forall a. C a => a -> a -> a
mod Integer
forall a. C a => a
base

instance Field.C T where
   / :: T -> T -> T
(/) = (Int64 -> Int64 -> Int64) -> T -> T -> T
lift2Integer (Int64 -> Int64 -> Int64 -> Int64
forall a. C a => a -> a -> a -> a
RC.divide Int64
forall a. C a => a
base)

instance Module.C T T where
   *> :: T -> T -> T
(*>) = T -> T -> T
forall a. C a => a -> a -> a
(*)

instance ZeroTestable.C T where
   isZero :: T -> Bool
isZero T
x  =  T
forall a. C a => a
zero T -> T -> Bool
forall a. Eq a => a -> a -> Bool
== T
x