diff --git a/doc/ref/algfld.xml b/doc/ref/algfld.xml
index 3df63aec9e..69c5ca6693 100644
--- a/doc/ref/algfld.xml
+++ b/doc/ref/algfld.xml
@@ -95,6 +95,15 @@ gap> m^2;
<#Include Label="IsAlgebraicElement">
+
+
+
+
+
+Finding Subfields
+
+<#Include Label="IdealDecompositionsOfPolynomial">
+
diff --git a/doc/ref/groups.xml b/doc/ref/groups.xml
index 648d59ef5c..61106f32fb 100644
--- a/doc/ref/groups.xml
+++ b/doc/ref/groups.xml
@@ -587,7 +587,6 @@ see .
-
Tests for the Availability of Methods
@@ -601,6 +600,14 @@ see .
<#Include Label="CanComputeIsSubset">
<#Include Label="KnowsHowToDecompose">
+
+
+
+
+Specific functions for Normalizer calculation
+
+<#Include Label="NormalizerViaRadical">
+
diff --git a/lib/algfld.gd b/lib/algfld.gd
index 7c50c7facb..366843adf5 100644
--- a/lib/algfld.gd
+++ b/lib/algfld.gd
@@ -188,3 +188,45 @@ DeclareGlobalFunction("AlgExtEmbeddedPol");
DeclareGlobalFunction("AlgExtSquareHensel");
+#############################################################################
+##
+#F IdealDecompositionsOfPolynomial( [:"onlyone"] ) finds ideal decompositions of rational f
+##
+## <#GAPDoc Label="IdealDecompositionsOfPolynomial">
+##
+##
+##
+##
+## Let f be a univariate, rational, irreducible, polynomial. A
+## pair g,h of polynomials of degree strictly
+## smaller than that of f, such that f(x)|g(h(x)) is
+## called an ideal decomposition. In the context of field
+## extensions, if \alpha is a root of f in a suitable extension
+## and Q the field of rational numbers. Such decompositions correspond
+## to (proper) subfields Q\lt Q(\beta)\lt Q(\alpha), where g is the
+## minimal polynomial of \beta.
+## This function determines such decompositions up to equality of the subfields
+## Q(\beta), thus determining subfields of a given algebraic extension.
+## It returns a list of pairs [g,h] (and an empty list if no such
+## decomposition exists). If the option onlyone is given it returns at
+## most one such decomposition (and performs faster).
+## x:=X(Rationals,"x");;pol:=x^8-24*x^6+144*x^4-288*x^2+144;;
+## gap> l:=IdealDecompositionsOfPolynomial(pol);
+## [ [ x^2+72*x+144, x^6-20*x^4+60*x^2-36 ],
+## [ x^2-48*x+144, x^6-21*x^4+84*x^2-48 ],
+## [ x^2+288*x+17280, x^6-24*x^4+132*x^2-288 ],
+## [ x^4-24*x^3+144*x^2-288*x+144, x^2 ] ]
+## gap> List(l,x->Value(x[1],x[2])/pol);
+## [ x^4-16*x^2-8, x^4-18*x^2+33, x^4-24*x^2+120, 1 ]
+## gap> IdealDecompositionsOfPolynomial(pol:onlyone);
+## [ [ x^2+72*x+144, x^6-20*x^4+60*x^2-36 ] ]
+## ]]>
+## In this example the given polynomial is regular with Galois group
+## Q_8, as expected we get four proper subfields.
+##
+##
+## <#/GAPDoc>
+##
+DeclareGlobalFunction("IdealDecompositionsOfPolynomial");
+DeclareSynonym("DecomPoly",IdealDecompositionsOfPolynomial);
diff --git a/lib/algfld.gi b/lib/algfld.gi
index 9cf4f5a8bc..25a398c86e 100644
--- a/lib/algfld.gi
+++ b/lib/algfld.gi
@@ -172,7 +172,8 @@ if Length(extra)>0 and IsString(extra[1]) then
SetCharacteristic(fam,Characteristic(f));
fam!.indeterminateName:=nam;
colf:=CollectionsFamily(fam);
- e:=Objectify(NewType(colf,IsAlgebraicExtensionDefaultRep),
+ e:=Objectify(NewType(colf,
+ IsAlgebraicExtensionDefaultRep and IsAlgebraicExtension),
rec());
fam!.wholeField:=e;
@@ -2193,13 +2194,14 @@ end);
#############################################################################
##
-#F DecomPoly( [,"all"] ) finds (all) ideal decompositions of rational f
+#F IdealDecompositionsOfPolynomial( [,"onlyone"] ) finds ideal decompositions of rational f
## This is equivalent to finding subfields of K(alpha).
##
-DecomPoly := function(arg)
-local f,n,e,ff,p,ffp,ffd,roots,allroots,nowroots,fm,fft,comb,combi,k,h,i,j,
- gut,avoid,blocks,g,m,decom,z,R,scale,allowed,hp,hpc,a,kfam;
- f:=arg[1];
+InstallGlobalFunction(IdealDecompositionsOfPolynomial,function(f)
+local n,e,ff,p,ffp,ffd,roots,allroots,nowroots,fm,fft,comb,combi,k,h,i,j,
+ gut,avoid,blocks,g,m,decom,z,R,scale,allowed,hp,hpc,a,kfam,only;
+
+ only:=ValueOption("onlyone")=true;
n:=DegreeOfUnivariateLaurentPolynomial(f);
if IsPrime(n) then
return [];
@@ -2255,9 +2257,9 @@ local f,n,e,ff,p,ffp,ffd,roots,allroots,nowroots,fm,fft,comb,combi,k,h,i,j,
fft:=ff{combi};
ffp:=List(fft,i->AlgebraicPolynomialModP(kfam,i,fm[1],p));
roots:=Filtered(fm,i->ForAny(ffp,j->Value(j,i)=Zero(k)));
- if Length(roots)<>Sum(ffd{combi}) then
- Error("serious error");
- fi;
+ if Length(roots)<>Sum(ffd{combi}) then
+ Error("serious error");
+ fi;
allroots:=Union(roots,[fm[1]]);
gut:=true;
j:=1;
@@ -2270,9 +2272,7 @@ local f,n,e,ff,p,ffp,ffd,roots,allroots,nowroots,fm,fft,comb,combi,k,h,i,j,
if gut then
Info(InfoPoly,2,"block found");
Add(blocks,combi);
- if Length(arg)>1 then
- gut:=false;
- fi;
+ if only<>true then gut:=false; fi;
fi;
h:=h+1;
od;
@@ -2328,15 +2328,12 @@ local f,n,e,ff,p,ffp,ffd,roots,allroots,nowroots,fm,fft,comb,combi,k,h,i,j,
#h:=Value(h,X(Rationals)*z);
Add(decom,[g,h]);
od;
- if Length(arg)=1 then
- decom:=decom[1];
- fi;
return decom;
else
Info(InfoPoly,2,"primitive");
return [];
fi;
-end;
+end);
#############################################################################
##
diff --git a/lib/grp.gd b/lib/grp.gd
index 602778f3f2..d54a47c0fb 100644
--- a/lib/grp.gd
+++ b/lib/grp.gd
@@ -4528,6 +4528,38 @@ DeclareGlobalFunction("GroupEnumeratorByClosure");
DeclareOperation( "LowIndexSubgroups",
[ IsGroup, IsPosInt ] );
+#############################################################################
+##
+#F NormalizerViaRadical(,)
+##
+## <#GAPDoc Label="NormalizerViaRadical">
+##
+##
+##
+##
+## This function implements a particular approach, following the
+## SolvableRadical paradigm, for calculating the
+## normalizer of a subgroup S in G. It is at the moment
+## provided only as a separate function, and not as method for the operation
+## Normalizer, as it can often be slower than other built-in routines.
+## In certain hard cases (non-solvable groups with nontrivial radical), however
+## its performance is substantially superior.
+## The function thus is provided as a
+## non-automated tool for advanced users.
+## g:=TransitiveGroup(30,2030);;
+## gap> s:=SylowSubgroup(g,5);;
+## gap> Size(NormalizerViaRadical(g,s));
+## 28800
+## ]]>
+## Note that this example only demonstrates usage, but that in this case
+## in fact the ordinary Normalizer routine performs faster.
+##
+##
+## <#/GAPDoc>
+##
+DeclareGlobalFunction("NormalizerViaRadical");
+
#############################################################################
##
#E
diff --git a/lib/norad.gi b/lib/norad.gi
index 4181ed421a..e7acb6b247 100644
--- a/lib/norad.gi
+++ b/lib/norad.gi
@@ -378,7 +378,7 @@ local expandvec,bassrc,basimg,transl,getbasimg,gettransl,myact2;
end);
# main normalizer routine
-BindGlobal("NormalizerViaRadical",function(G,U)
+InstallGlobalFunction(NormalizerViaRadical,function(G,U)
local sus,ser,len,factorhom,uf,n,d,up,mran,nran,mpcgs,pcgs,pcisom,nf,ng,np,sub,
central,f,ngm,npm,no2pcgs,part,stb,mods,famo,part0,nopcgs,uff,ufg,prev,
famo2,ufr,dims,vecs,ovecs,vecsz,l,prop,properties,clusters,clusterspaces,