module Algebra.Field.Galois (GF'(), IsGF', modPoly, modVec,
withIrreducible, linearRepGF, linearRepGF',
reifyGF', generateIrreducible,
withGF', GF, ConwayPolynomial(..),
Conway, primitive, conway,
conwayFile, addConwayPolynomials) where
import Algebra.Field.Finite
import Algebra.Field.Galois.Conway
import Algebra.Internal
import Algebra.Prelude.Core hiding (varX)
import Algebra.Ring.Polynomial.Univariate
import Control.Lens (imap)
import Control.Monad (replicateM)
import Control.Monad.Loops (iterateUntil)
import Control.Monad.Random (MonadRandom)
import Control.Monad.Random (uniform)
import qualified Data.Foldable as F
import qualified Data.Ratio as Rat
import Data.Reflection (Reifies (..), reify)
import Data.Singletons.Prelude.Enum (SEnum (..))
import Data.Singletons.TypeLits (withKnownNat)
import qualified Data.Sized.Builtin as SV
import qualified Data.Traversable as T
import qualified Data.Vector as V
import qualified GHC.TypeLits as TL
import qualified Numeric.Algebra as NA
import Numeric.Domain.Euclidean (Euclidean)
import Numeric.Domain.GCD (GCDDomain, gcd)
import Numeric.Semiring.ZeroProduct (ZeroProductSemiring)
import qualified Prelude as P
data GF' p (n :: TL.Nat) (f :: *) = GF' { runGF' :: Sized n (F p) }
deriving instance Reifies p Integer => Eq (GF' p n f)
type GF (p :: TL.Nat) n = GF' p n (Conway p n)
modPoly :: forall p n f. (KnownNat n, Reifies p Integer) => Unipol (F p) -> GF' p n f
modPoly = GF' . polyToVec
modVec :: Sized n (F p) -> GF' p n f
modVec = GF'
instance (Reifies p Integer, Show (F p)) => Show (GF' p n f) where
showsPrec d (GF' (v :< vs)) =
if F.all isZero vs
then showsPrec d v
else showChar '<' . showString (showPolynomialWith (singleton "ΞΎ") 0 $ vecToPoly $ v :< vs) . showChar '>'
showsPrec _ _ = showString "0"
instance (Reifies p Integer, Show (F p)) => PrettyCoeff (GF' p n f)
varX :: CoeffRing r => Unipol r
varX = var [od|0|]
vecToPoly :: (CoeffRing r)
=> Sized n r -> Unipol r
vecToPoly v = sum $ imap (\i c -> injectCoeff c * varX^fromIntegral i) $ F.toList v
polyToVec :: forall n r. (CoeffRing r, KnownNat n) => Unipol r -> Sized n r
polyToVec f = unsafeFromList' [ coeff (leadingMonomial $ (varX ^ i) `asTypeOf` f) f
| i <- [0..fromIntegral (fromSing (sing :: SNat n))]]
instance Reifies p Integer => Additive (GF' p n f) where
GF' v + GF' u = GF' $ SV.zipWithSame (+) v u
instance (Reifies p Integer, KnownNat n) => Monoidal (GF' p n f) where
zero = GF' $ SV.replicate' zero
instance Reifies p Integer => LeftModule Natural (GF' p n f) where
n .* GF' v = GF' $ SV.map (n .*) v
instance Reifies p Integer => RightModule Natural (GF' p n f) where
GF' v *. n = GF' $ SV.map (*. n) v
instance Reifies p Integer => LeftModule Integer (GF' p n f) where
n .* GF' v = GF' $ SV.map (n .*) v
instance Reifies p Integer => RightModule Integer (GF' p n f) where
GF' v *. n = GF' $ SV.map (*. n) v
instance (KnownNat n, Reifies p Integer) => Group (GF' p n f) where
negate (GF' v) = GF' $ SV.map negate v
GF' u GF' v = GF' $ SV.zipWithSame () u v
instance (Reifies p Integer) => Abelian (GF' p n f)
instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer)
=> Multiplicative (GF' p n f) where
GF' u * GF' v =
let t = (vecToPoly u * vecToPoly v) `rem` reflect (Proxy :: Proxy f)
in GF' $ polyToVec t
instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer) => Unital (GF' p n f) where
one =
case zeroOrSucc (sing :: SNat n) of
IsZero -> GF' NilL
IsSucc k -> withKnownNat k $ GF' $ one :< SV.replicate' zero
instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer) => Semiring (GF' p n f)
instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer) => Rig (GF' p n f) where
fromNatural n =
case zeroOrSucc (sing :: SNat n) of
IsZero -> GF' SV.empty
IsSucc k -> withKnownNat k $ GF' $ fromNatural n :< SV.replicate' zero
instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer) => Commutative (GF' p n f)
instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer) => Ring (GF' p n f) where
fromInteger n =
case zeroOrSucc (sing :: SNat n) of
IsZero -> GF' NilL
IsSucc k -> withKnownNat k $ GF' $ fromInteger n :< SV.replicate' zero
instance (KnownNat n, Reifies p Integer) => DecidableZero (GF' p n f) where
isZero (GF' sv) = F.all isZero sv
instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) => DecidableUnits (GF' p n f) where
isUnit (GF' sv) = not $ F.all isZero sv
recipUnit a | isZero a = Nothing
| otherwise = Just $ recip a
instance (Reifies p Integer, Reifies f (Unipol (F p)), KnownNat n)
=> Characteristic (GF' p n f) where
char _ = char (Proxy :: Proxy (F p))
instance (Reifies p Integer, Reifies f (Unipol (F p)), KnownNat n)
=> Division (GF' p n f) where
recip f =
let p = reflect (Proxy :: Proxy f)
(_,_,r) = P.head $ euclid p $ vecToPoly $ runGF' f
in GF' $ polyToVec $ r `rem` p
instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p)))
=> DecidableAssociates (GF' p n f) where
isAssociate p n =
(isZero p && isZero n) || (not (isZero p) && not (isZero n))
instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p)))
=> ZeroProductSemiring (GF' p n f)
instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p)))
=> UnitNormalForm (GF' p n f)
instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p)))
=> IntegralDomain (GF' p n f)
instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p)))
=> GCDDomain (GF' p n f)
instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p)))
=> UFD (GF' p n f)
instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p)))
=> PID (GF' p n f)
instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p)))
=> Euclidean (GF' p n f)
instance (Reifies p Integer, Reifies f (Unipol (F p)), KnownNat n) => P.Num (GF' p n f) where
(+) = (NA.+)
() = (NA.-)
negate = NA.negate
(*) = (NA.*)
fromInteger = NA.fromInteger
abs = error "not defined"
signum = error "not defined"
instance (Reifies p Integer, Reifies f (Unipol (F p)), KnownNat n) => P.Fractional (GF' p n f) where
fromRational u = fromInteger (Rat.numerator u) / fromInteger (Rat.denominator u)
(/) = (/)
recip = recip
generateIrreducible :: (MonadRandom m, FiniteField k, Eq k)
=> proxy k -> Natural -> m (Unipol k)
generateIrreducible p n =
iterateUntil (\f -> all (\i -> one == gcd (varX^(order p^i) varX) f ) [1.. n `div` 2]) $ do
cs <- replicateM (fromIntegral n) $ uniform (elements p)
let f = varX^n + sum [ injectCoeff c * (varX^i) | c <- cs | i <- [0..n P.- 1]]
return f
withIrreducible :: forall p a. KnownNat p
=> Unipol (F p)
-> (forall f (n :: Nat). (Reifies f (Unipol (F p))) => Proxy (GF' p n f) -> a)
-> a
withIrreducible r f =
case toSing (fromIntegral $ totalDegree' r) of
SomeSing sn ->
withKnownNat sn $
reify r (f. proxyGF' (Proxy :: Proxy (F n)) sn)
reifyGF' :: MonadRandom m => Natural -> Natural
-> (forall (p :: TL.Nat) (f :: *) (n :: TL.Nat) . (Reifies p Integer, Reifies f (Unipol (F p)))
=> Proxy (GF' p n f) -> a)
-> m a
reifyGF' p n f = reifyPrimeField (P.toInteger p) $ \pxy -> do
mpol <- generateIrreducible pxy n
case toSing (fromIntegral p) of
SomeSing sp -> return $ withKnownNat sp $ withIrreducible mpol f
linearRepGF :: GF' p n f -> V.Vector (F p)
linearRepGF = SV.unsized . runGF'
linearRepGF' :: GF' p n f -> V.Vector Integer
linearRepGF' = V.map naturalRepr . linearRepGF
withGF' :: MonadRandom m
=> Natural -> Natural
-> (forall (p :: TL.Nat) f (n :: TL.Nat) . (Reifies p Integer, Reifies f (Unipol (F p)))
=> GF' p n f)
-> m (V.Vector Integer)
withGF' p n f = reifyGF' p n $ V.map naturalRepr . linearRepGF . asProxyTypeOf f
proxyGF' :: Proxy (F p) -> SNat n -> Proxy f -> Proxy (GF' p n f)
proxyGF' _ _ Proxy = Proxy
class (KnownNat n, KnownNat p, Reifies f (Unipol (F p))) => IsGF' p n f
instance (KnownNat n, KnownNat p, Reifies f (Unipol (F p))) => IsGF' p n f
instance (KnownNat n, IsGF' p n f) => ZeroProductSemiring (GF' p n f)
instance (KnownNat n, IsGF' p n f) => FiniteField (GF' p n f) where
power _ = fromIntegral $ fromSing (sing :: SNat n)
elements _ =
let sn = sing :: SNat n
in P.map GF' $ T.sequence $
SV.replicate sn $ elements Proxy
primitive :: forall p n f. (IsGF' p n f) => GF' p (n + 1) f
primitive = withKnownNat (sSucc (sing :: SNat n)) $ GF' $ polyToVec $ var [od|0|]
conway :: forall p n. ConwayPolynomial p n
=> SNat p -> SNat n -> Unipol (F p)
conway = conwayPolynomial