finite-field-0.7.0: src/Data/FiniteField/PrimeField.hs
{-# LANGUAGE ScopedTypeVariables, MultiParamTypeClasses, DeriveDataTypeable, TemplateHaskell, BangPatterns #-}
{-# OPTIONS_GHC -Wall #-}
-----------------------------------------------------------------------------
-- |
-- Module : Data.FiniteField.PrimeField
-- Copyright : (c) Masahiro Sakai 2013
-- License : BSD-style
--
-- Maintainer : masahiro.sakai@gmail.com
-- Stability : provisional
-- Portability : non-portable (ScopedTypeVariables, MultiParamTypeClasses, DeriveDataTypeable, TemplateHaskell, BangPatterns)
--
-- Finite field of prime order p, Fp = Z/pZ.
--
-- References:
--
-- * <http://en.wikipedia.org/wiki/Finite_field>
--
-----------------------------------------------------------------------------
module Data.FiniteField.PrimeField
( PrimeField
, toInteger
-- * Template haskell utilities
-- $TH
, primeField
) where
import Prelude hiding (toInteger)
import Control.DeepSeq
import Data.Hashable
import Data.Ratio (denominator, numerator)
import Data.Typeable
import qualified Language.Haskell.TH as TH
import qualified Numeric.Algebra as Alg
import qualified TypeLevel.Number.Nat as TL
import Data.FiniteField.Base
-- | Finite field of prime order p, Fp = Z/pZ.
--
-- NB: Primality of @p@ is assumed, but not checked.
newtype PrimeField p = PrimeField Integer deriving (Eq, Typeable)
-- | conversion to 'Integer'
toInteger :: PrimeField p -> Integer
toInteger (PrimeField a) = a
toInt :: Integral a => PrimeField p -> a
toInt = fromInteger . toInteger
instance Show (PrimeField p) where
showsPrec n (PrimeField x) = showsPrec n x
instance TL.Nat p => Read (PrimeField p) where
readsPrec n s = [(fromInteger a, s') | (a,s') <- readsPrec n s]
instance NFData (PrimeField p) where
rnf (PrimeField a) = rnf a
instance TL.Nat p => Num (PrimeField p) where
PrimeField a + PrimeField b = fromInteger $ a+b
PrimeField a * PrimeField b = fromInteger $ a*b
PrimeField a - PrimeField b = fromInteger $ a-b
negate (PrimeField a) = fromInteger $ negate a
abs a = a
signum _ = 1
fromInteger a = PrimeField $ a `mod` TL.toInt (undefined :: p)
instance TL.Nat p => Fractional (PrimeField p) where
fromRational r = fromInteger (numerator r) / fromInteger (denominator r)
-- recip a = a ^ (TL.toInt (undefined :: p) - 2 :: Integer)
recip (PrimeField a) =
case exgcd a p of
(_, r, _) -> fromInteger r
where
p :: Integer
p = TL.toInt (undefined :: p)
instance TL.Nat p => Bounded (PrimeField p) where
minBound = PrimeField 0
maxBound = PrimeField (TL.toInt (undefined :: p) - 1)
instance TL.Nat p => Enum (PrimeField p) where
toEnum x
| toInt (minBound :: PrimeField p) <= x && x <= toInt (maxBound :: PrimeField p) = fromIntegral x
| otherwise = error "PrimeField.toEnum: bad argument"
fromEnum = toInt
instance Ord (PrimeField p) where
PrimeField a `compare` PrimeField b = a `compare` b
PrimeField a `max` PrimeField b = PrimeField (a `max` b)
PrimeField a `min` PrimeField b = PrimeField (a `min` b)
instance TL.Nat p => FiniteField (PrimeField p) where
order _ = TL.toInt (undefined :: p)
char _ = TL.toInt (undefined :: p)
pthRoot a = a
allValues = [minBound .. maxBound]
instance TL.Nat p => Hashable (PrimeField p) where
hashWithSalt s (PrimeField a) =
s `hashWithSalt` (TL.toInt (undefined :: p) :: Int) `hashWithSalt` a
-- | Extended GCD algorithm
exgcd :: (Eq a, Integral a) => a -> a -> (a, a, a)
exgcd f1 f2 = f $ go f1 f2 1 0 0 1
where
go !r0 !r1 !s0 !s1 !t0 !t1
| r1 == 0 = (r0, s0, t0)
| otherwise = go r1 r2 s1 s2 t1 t2
where
(q, r2) = r0 `divMod` r1
s2 = s0 - q*s1
t2 = t0 - q*t1
f (g,u,v)
| g < 0 = (-g, -u, -v)
| otherwise = (g,u,v)
-- ---------------------------------------------------------------------------
instance TL.Nat p => Alg.Multiplicative (PrimeField p) where
(*) = (*)
instance TL.Nat p => Alg.Commutative (PrimeField p)
instance TL.Nat p => Alg.Unital (PrimeField p) where
one = 1
instance TL.Nat p => Alg.Division (PrimeField p) where
recip = recip
instance TL.Nat p => Alg.Additive (PrimeField p) where
(+) = (+)
instance TL.Nat p => Alg.Abelian (PrimeField p)
instance TL.Nat p => Alg.Semiring (PrimeField p)
instance TL.Nat p => Alg.LeftModule Alg.Natural (PrimeField p) where
n .* a = fromIntegral n * a
instance TL.Nat p => Alg.RightModule Alg.Natural (PrimeField p) where
a *. n = a * fromIntegral n
instance TL.Nat p => Alg.Monoidal (PrimeField p) where
zero = 0
instance TL.Nat p => Alg.LeftModule Integer (PrimeField p) where
n .* a = fromIntegral n * a
instance TL.Nat p => Alg.RightModule Integer (PrimeField p) where
a *. n = a * fromIntegral n
instance TL.Nat p => Alg.Group (PrimeField p) where
negate = negate
instance TL.Nat p => Alg.Rig (PrimeField p)
instance TL.Nat p => Alg.Ring (PrimeField p)
instance TL.Nat p => Alg.Characteristic (PrimeField p) where
char _ = TL.toInt (undefined :: p)
instance TL.Nat p => Alg.Field (PrimeField p)
-- ---------------------------------------------------------------------------
-- | Create a PrimeField type
primeField :: Integer -> TH.TypeQ
primeField n
| n <= 0 = error "primeField: negative value"
| otherwise = [t| PrimeField $(TL.natT n) |]
-- $TH
-- Here is usage example for primeField:
--
-- > a :: $(primeField 15485867)
-- > a = 1