Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/pkg/standardff/lib/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 13.8.2023 mit Größe 7 kB image not shown  

Quelle  StandardCyc.gi   Sprache: unbekannt

 
#############################################################################
##
#A  StandardCyc.gi                                               Frank Lübeck
##  
##  The files StandardCyc.g{i,d} contain code to compute standard generators
##  of cyclic subgroups of multiplicative groups in standard finite fields.
##  


# p, r: prime numbers
# bound: multiple of order of p mod r^k
# returns standard generator of order r^k in \bar GF(p) as Steinitz pair
InstallGlobalFunction(StdCycGen, function(p, r, k, bound)
  local F, cgens, res, l, m, t, K, count, st, a, am, pl, b, 
        z, bb, aa, e, c, j, min, nn, s;
  # we cache the results
  F := GF(p);
  if not IsBound(F!.prcycgens) then
    F!.prcycgens := [];
  fi;
  cgens := F!.prcycgens;
  res := First(cgens, a-> a[1]=r and a[2]=k);
  if res <> fail then
    return res[3];
  fi;
  # trivial case
  if r = 2 and k = 1 and p mod 4 = 3 then
    pl := [1, p-1]; # -1
    Add(cgens, [2,1,pl]);
    return pl;
  fi;
  # smallest degree containing r-elements
  if r = 2 and p mod 4 = 3 then
    # exception, here l = 2 is the base case
    # (compatibility with l=1 case is always fulfilled)
    l := 2;
  else
    l := OrderModBound(p, r, bound);
  fi;
  m := (p^l-1)/r;
  t := 1;
  while m mod r = 0 do
    m := m/r;
    t := t+1;
  od;
  if t = k then
    # easy case:
    # we search for element whose m-th power has order p^t,
    # testing pseudo random elements  
    K := StandardFiniteField(p, l);
    # we use standard affine shift for pseudo random sequence
    count := 1;
    st := StandardAffineShift(Size(K), count);
    a := ElementSteinitzNumber(K, st);
    am := a^m;
    while IsZero(am) or IsOne(am^(r^(t-1))) do
      Info(InfoStandardFF, 2, "!\c");      
      count := count+1;
      st := StandardAffineShift(Size(K), count);
      a := ElementSteinitzNumber(K, st);
      am := a^m;
    od;
    pl := SteinitzPair(K, am);
    Add(cgens, [r, k, pl]);
    return pl;
  elif t > k then
    # just take power of element of order r^t
    K := StandardFiniteField(p, l);
    a := ElementSteinitzNumber(K, 
              SteinitzNumber(K, StdCycGen(p, r, t, bound)));
    am := a^(r^(t-k));
    pl := SteinitzPair(K, am);
    Add(cgens, [r, k, pl]);
    return pl;
  else # k > t
    # expensive case:
    # have to compute an r-th root of standard element of order r^(k-1)
    l := OrderModBound(p, r^k, bound);
    K := StandardFiniteField(p, l);
    # this element generates a subfield of index r
    b := ElementSteinitzNumber(K, 
                    SteinitzNumber(K, StdCycGen(p, r, k-1, bound)));
    # find random element of order r^k
    m := (Size(K)-1)/r^k;
    a := Random(K)^m;
    while IsZero(a) or IsOne(a^(r^(k-1))) do
      a := Random(K)^m;
    od;
    # r-th root of one
    z := a^(r^(k-1));
    # find e with a^e is r-th root of b
    # by dicrete logarithm: (a^r)^e =  b
    # We use Pohlig-Hellman algorithm 
    # (the j below are the coefficients of e in base r)
    bb := b;
    aa := a^r;
    e := 0;
    for s in [0..k-2] do
      c := bb^(r^(k-s-2));
      j := DLogShanks(z, c, r);
      e := e + j*r^s;
      bb := bb / aa^(j*r^s);
    od;
    a := a^e;
    # now a is an r-th root of b, we choose the one with smallest Steinitz
    # number
    aa := a;
    min := [aa, SteinitzNumber(K, aa)];
    for j in [1..r-1] do
      aa := aa*z;
      nn := SteinitzNumber(K, aa);
      if nn < min[2] then
        min := [aa, nn];
      fi;
    od;
    pl := SteinitzPair(K, min[1]);
    Add(cgens, [r, k, pl]);
    return pl;
  fi;
end);

##  <#GAPDoc Label="StandardCyclicGenerator">
##  <ManSection>
##  <Oper Name="StandardCyclicGenerator" Arg="F[, m]"/>
##  <Attr Name="StandardPrimitiveRoot" Arg="F"/>
##  <Returns>an element of <A>F</A> or <K>fail</K> </Returns>
##  <Description>
##  The  argument  <A>F</A>  must  be   a  standard  finite  field  (see  <Ref
##  Func="FF"/>) and <A>m</A> a positive  integer. If <A>m</A> does not divide
##  <M>|<A>F</A>|  -  1</M>  the  function returns  <K>fail</K>.  Otherwise  a
##  standardized element <M>x_{<A>m</A>}</M> of order <A>m</A> is returned, as
##  described above.
##  <P/> 
##  The  argument <A>m</A>  is optional,  if not  given its  default value  is
##  <M>|<A>F</A>|  -  1</M>. In  this  case  <M>x_{<A>m</A>}</M> can  also  be
##  computed with the attribute <Ref Attr="StandardPrimitiveRoot"/>.
##  <Example>gap> F := FF(67, 18); # Conway polynomial was hard to compute
##  FF(67, 18)
##  gap> x := PrimitiveElement(F);
##  ZZ(67,18,[0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])
##  gap> xprim := StandardPrimitiveRoot(F);;
##  gap> k := (Size(F)-1) / Order(x);
##  6853662165340556076084083497526
##  gap> xm := StandardCyclicGenerator(F, Order(x));;
##  gap> xm = xprim^k;
##  true
##  gap> F := FF(23, 201); # factorization of (|F| - 1) not known 
##  FF(23, 201)
##  gap> m:=79*269*67939;
##  1443771689
##  gap> (Size(F)-1) mod m;
##  0
##  gap> OrderMod(23, m);
##  201
##  gap> xm := StandardCyclicGenerator(F, m);;
##  gap> IsOne(xm^m);
##  true
##  gap> ForAll(Factors(m), r-> not IsOne(xm^(m/r)));
##  true
##  gap> F := FF(7,48);
##  FF(7, 48)
##  gap> K := FF(7,12);
##  FF(7, 12)
##  gap> emb := Embedding(K, F);;
##  gap> x := StandardPrimitiveRoot(F);;
##  gap> y := StandardPrimitiveRoot(K);;
##  gap> y^emb = x^((Size(F)-1)/(Size(K)-1));
##  true
##  gap> v := Indeterminate(FF(7,1), "v");
##  v
##  gap> px := MinimalPolynomial(FF(7,1), x, v);;
##  gap> py := MinimalPolynomial(FF(7,1), y, v);;
##  gap> Value(py, PowerMod(v, (Size(F)-1)/(Size(K)-1), px)) mod px;
##  0*Z(7)
##  </Example>
##  </Description>
##  </ManSection>
##  <#/GAPDoc>
##  
GAPInfo.tmpfun := function(K, ord)
  local p, n, fac, ppgens, res, num;
  if ord = 1 then
    return One(K);
  fi;
  p := Characteristic(K);
  n := DegreeOverPrimeField(K);
  if (p^n-1) mod ord <> 0 then
    return fail;
  fi;
  fac := Collected(Factors(ord));
  # standard generators of prime power order
  ppgens := List(fac, a-> StdCycGen(p, a[1], a[2], n));
  # map Steinitz pairs to Steinitz numbers
  ppgens := List(ppgens, a-> SteinitzNumber(K, a));
  # and now to elements in K
  ppgens := List(ppgens, a-> ElementSteinitzNumber(K, a));

  # product has correct order, we take power to find element corresponding
  # to 1/ord
  res := Product(ppgens);
  num := Sum(fac, a-> 1/a[1]^a[2]) * ord;
  res := res^(1/num mod ord);
  return res;
end;
InstallMethod(StandardCyclicGenerator, 
     ["IsStandardFiniteField", "IsPosInt"], GAPInfo.tmpfun);
InstallOtherMethod(StandardCyclicGenerator, 
     ["IsStandardPrimeField", "IsPosInt"], GAPInfo.tmpfun);


GAPInfo.tmpfun := function(K)
  return StandardCyclicGenerator(K, Size(K)-1);
end;
InstallMethod(StandardPrimitiveRoot, ["IsStandardFiniteField"],
GAPInfo.tmpfun);
InstallOtherMethod(StandardPrimitiveRoot, ["IsStandardPrimeField"],
GAPInfo.tmpfun);
Unbind(GAPInfo.tmpfun);
InstallMethod(PrimitiveRoot, ["IsStandardFiniteField"], StandardPrimitiveRoot);


InstallOtherMethod(StandardCyclicGenerator, ["IsStandardFiniteField"],
  StandardPrimitiveRoot);

# Log with respect to standard primitive root
InstallOtherMethod(Log, ["IsStandardFiniteFieldElement"], function(x)
  local F;
  F := FamilyObj(x)!.wholeField;
  return DLog(StandardPrimitiveRoot(F), x, Factors(Size(F)-1));
end);
# using order of F^\times
InstallOtherMethod(Order, ["IsStandardFiniteFieldElement"], function(x)
  local F, m, fac, res, k, xx, a;
  F := FamilyObj(x)!.wholeField;
  m := Size(F)-1;
  fac := Collected(Factors(m));
  res := m;
  for a in fac do
    k := a[2];
    xx := x^(m/a[1]^a[2]);
    while not IsOne(xx) do
      xx := xx^a[1];
      k := k-1;
    od;
    res := res/a[1]^k;
  od;
  return res;
end);




[ Dauer der Verarbeitung: 0.29 Sekunden  (vorverarbeitet)  ]