module Group.Field
( module Group
, module Group.Field
) where
import Protolude
import Control.Monad.Random (Random(..))
import GaloisField (GaloisField(..))
import Test.Tasty.QuickCheck (Arbitrary(..), suchThatMap)
import Text.PrettyPrint.Leijen.Text (Pretty(..))
import Group (Group(..))
-------------------------------------------------------------------------------
-- Types
-------------------------------------------------------------------------------
-- | Field groups.
class GaloisField k => FGroup k where
{-# MINIMAL g_, q_, r_, x_ #-}
g_ :: Element k -- ^ Group generator.
q_ :: Element k -> Integer -- ^ Group characteristic.
r_ :: Element k -> Integer -- ^ Group order.
x_ :: k -- ^ Group element.
-- | Field elements.
newtype Element k = F k
deriving (Eq, Functor, Generic, NFData, Read, Show)
-------------------------------------------------------------------------------
-- Operations
-------------------------------------------------------------------------------
-- Field elements are groups.
instance FGroup k => Group (Element k) where
add = (<>)
{-# INLINABLE add #-}
dbl = join (<>)
{-# INLINABLE dbl #-}
def (F x) = x /= 0
{-# INLINABLE def #-}
gen = g_
{-# INLINABLE gen #-}
id = mempty
{-# INLINABLE id #-}
inv (F x) = F (recip x)
{-# INLINABLE inv #-}
mul' (F x) n = F (pow x n)
{-# INLINABLE mul' #-}
order = r_
{-# INLINABLE order #-}
-- Field elements are monoids.
instance FGroup k => Monoid (Element k) where
mempty = F 1
{-# INLINABLE mempty #-}
-- Field elements are semigroups.
instance FGroup k => Semigroup (Element k) where
F x <> F y = F (x * y)
{-# INLINABLE (<>) #-}
-------------------------------------------------------------------------------
-- Instances
-------------------------------------------------------------------------------
-- Field elements are arbitrary.
instance FGroup k => Arbitrary (Element k) where
arbitrary = suchThatMap arbitrary defX
where
defX 0 = Nothing
defX x = Just (F x)
{-# INLINABLE arbitrary #-}
-- Field elements are pretty.
instance FGroup k => Pretty (Element k) where
pretty (F x) = pretty x
-- Field elements are random.
instance FGroup k => Random (Element k) where
random g = case random g of
(0, g') -> random g'
(x, g') -> (F x, g')
{-# INLINABLE random #-}
randomR = panic "not implemented."