diff --git a/lib/ffe.gd b/lib/ffe.gd index b4a37d9835..fd4f65a011 100644 --- a/lib/ffe.gd +++ b/lib/ffe.gd @@ -659,18 +659,19 @@ DeclareAttribute( "AsInternalFFE", IsFFE); ## ## <#GAPDoc Label="RootFFE"> ## -## +## ## ## ## returns a finite field element -## r whose k-th power is z. If no such element exists +## r from whose k-th power is z. +## If no such element exists ## then ## fail is returned. ## ## ## <#/GAPDoc> ## -DeclareOperation( "RootFFE", [ IsFFE, IsObject ] ); +DeclareOperation( "RootFFE", [ IsObject, IsFFE, IsObject ] ); ############################################################################# diff --git a/lib/ffe.gi b/lib/ffe.gi index 6e3b6cc53f..6b007a173b 100644 --- a/lib/ffe.gi +++ b/lib/ffe.gi @@ -1149,17 +1149,33 @@ end); ## #M RootFFE( , ) ## -InstallMethod( RootFFE, "use LogFFE",true,[IsFFE,IsPosInt], -function(z,k) -local q,e; - q:=Characteristic(z)^DegreeFFE(z); +InstallMethod(RootFFE,"use field order",IsCollsElmsX, + [IsField,IsFFE,IsPosInt],0, +function(F,z,k) + return RootFFE(Size(F),z,k); +end); + +InstallOtherMethod(RootFFE,"use LogFFE",true,[IsPosInt,IsFFE,IsPosInt], +function(q,z,k) +local e,m,p,a; + if IsZero(z) or IsOne(z) then return z;fi; + m:=q-1; e:=LogFFE(z,Z(q)); - e:=e/k; - if Gcd(DenominatorRat(e),q-1)=1 then - return Z(q)^(e mod (q-1)); - else - return fail; + p:=GcdInt(m,e); #power for subgroup it is in + k:=k mod m; + a:=GcdInt(m,k); # power for subgroup we want + if p mod a<>0 then + return fail; # element does not lie in subgroup of a-th powers fi; + # k/a is coprime to order of elts in subgroup and elt is an a-th power + a:=(e*(a/k mod (m/p))/a mod m); + return Z(q)^a; +end); + +InstallOtherMethod(RootFFE,"without field",true, + [IsFFE,IsPosInt],0, +function(z,k) + return RootFFE(Characteristic(z)^DegreeFFE(z),z,k); end); diff --git a/lib/zmodnz.gi b/lib/zmodnz.gi index e344e79f9c..51ea368229 100644 --- a/lib/zmodnz.gi +++ b/lib/zmodnz.gi @@ -660,16 +660,28 @@ InstallMethod( LogFFE, ## #M RootFFE( , ) . . . . . . . . . . . . . . . . . . for `IsZmodpZObj' ## -InstallMethod(RootFFE,"for modulus rep, using RootMod",true, - [IsZmodpZObj and IsModulusRep,IsPosInt], -function( z, k ) +InstallOtherMethod(RootFFE,"for modulus rep, using RootMod",true, + [IsPosInt,IsZmodpZObj and IsModulusRep,IsPosInt], +function( A, z, k ) local r,fam; fam:=FamilyObj(z); - r:=RootMod(z![1],k,fam!.Characteristic); + if A<>fam!.Characteristic then + TryNextMethod(); + fi; + if k=1 or z![1]=0 or z![1]=1 then return z;fi; + r:=RootMod(z![1],k,A); if r=fail then return r;fi; return ZmodnZObj(fam,r); end ); +InstallOtherMethod(RootFFE,"for modulus rep",true, + [IsZmodpZObj and IsModulusRep,IsPosInt], +function(z,k) + return RootFFE(FamilyObj(z)!.Characteristic,z,k); +end); + + + ############################################################################# ## diff --git a/tst/testinstall/ffe.tst b/tst/testinstall/ffe.tst index 3f73ab0ff1..e67c614c83 100644 --- a/tst/testinstall/ffe.tst +++ b/tst/testinstall/ffe.tst @@ -119,6 +119,23 @@ gap> Subfields( GF(81) ); [ GF(3), GF(3^2), GF(3^4) ] gap> Subfields( GF(2^6) ); [ GF(2), GF(2^2), GF(2^3), GF(2^6) ] + +# RootFFE +gap> Rochambeau:=function(F) +> local e,i,p,a,r; +> e:=Elements(F); +> for i in [1..2*Size(F)] do +> p:=Set(List(e,x->x^i)); +> for a in e do +> r:=RootFFE(F,a,i); +> if a in p and r=fail then Error("-1"); return -1;fi; +> if r<>fail and a<>r^i then Error("1");return 1;fi; +> od; +> od; +> return 0; +> end;; +gap> ForAll(Filtered([1..256],IsPrimePowerInt),x->Rochambeau(GF(x))=0); +true gap> STOP_TEST( "ffe.tst", 470000); #############################################################################