"Fossies" - the Fresh Open Source Software Archive

Member "KASH3-lib-archindep-2008-07-31/lib/locFact.g" (3 Sep 2008, 65470 Bytes) of package /linux/misc/old/KASH3-lib-archindep-2008-07-31.tar.gz:


As a special service "Fossies" has tried to format the requested text file into HTML format (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.


    1 #_f2:= X^4 - +3*X^3-X^2 + 7;
    2 #_k:= pAdicField(2,30);
    3 #_g:= X^2 + 2*X + 2;
    4 #_ek:= TotallyRamifiedExtension(_k,_g);
    5 #_ekx:= PolynomialAlgebra(_ek);
    6 # _f2:= Coerce(_ekx,_f2);
    7 dd_realPrec:=20;
    8 
    9 
   10 
   11 
   12 #_Z2q:= Quotient(pAdicRing(2,30),2^30);
   13 #_Z2qx:= PolynomialAlgebra(_Z2q);
   14 #_x:= _Z2qx.1;
   15 #_f:= _x^6+6*_x^4+2^5*_x^3+12*_x^2-3*2^6*_x+33*2^3;
   16 
   17 #_Z3:= pAdicRing(3,30);
   18 #_Z3q:= Quotient(_Z3,3^30);
   19 #_Z3qx:= PolynomialAlgebra(_Z3q);
   20 #_y:= _Z3qx.1;
   21 #_g:= _y^8+4*_y^6+6*_y^4+7*_y^2+9*_y+13;
   22 
   23 
   24 #//freeze;
   25 
   26 #/////////////////////////////////////////////////////////////////////////////
   27 #// Automorphisms are in class_field.m now
   28 #/////////////////////////////////////////////////////////////////////////////
   29 #/*
   30 #declare attributes Map:LocalAutoGenerators;
   31 #declare attributes Map:LocalRingMap;
   32 
   33 #function eval_automorphism(x, gens, pos)
   34 #    if pos eq #gens then
   35 #	return x;
   36 #    end if;
   37 
   38 #   R := Parent(x);
   39 #    P := PolynomialAlgebra(R);
   40 #    return Evaluate(
   41 #	P ! [eval_automorphism(i, gens, pos + 1) : i in Eltseq(x)], gens[pos]
   42 #    );
   43 #end function;
   44 
   45 #intrinsic Automorphisms(L::RngPad) -> SeqEnum
   46 #{Return the automorphisms of the local ring L. Automorphisms are returned as a sequence of maps}
   47 #    if L eq PrimeRing(L) then
   48 #	curr_gens := [L ! 1];
   49 #	curr := map<L -> L | x :-> eval_automorphism(x, curr_gens, 1)>;
   50 #	curr`LocalAutoGenerators := curr_gens;
   51 #	return [curr];
   52 #    end if;
   53 
   54 #    R := BaseRing(L);
   55 #    maps := Automorphisms(R);
   56 #    f := DefiningPolynomial(L);
   57 
   58 #    res := [];
   59 #    if IsEisenstein(f) then
   60 #	P := PolynomialAlgebra(L);
   61 #	for m in maps do
   62 #	    gens := ChangeUniverse(m`LocalAutoGenerators, L);
   63 #	    for r in Roots(P ! [m(x) : x in Eltseq(f)]) do
   64 #		curr_gens := Insert(gens, 1, r[1]);
   65 #		curr := map<L -> L | x :-> eval_automorphism(x, curr_gens, 1)>;
   66 #		curr`LocalAutoGenerators := curr_gens;
   67 #		Append(~res, curr);
   68 #	    end for;
   69 #	end for;
   70 #    elif IsInertial(f) then
   71 #	for m in maps do
   72 #	    gens := ChangeUniverse(m`LocalAutoGenerators, L);
   73 #	    r := L.1;
   74 #	    for i in [1..Degree(L)] do
   75 #		curr_gens := Insert(gens, 1, r);
   76 #		curr := map<L -> L | x :-> eval_automorphism(x, curr_gens, 1)>;
   77 #		curr`LocalAutoGenerators := curr_gens;
   78 #		Append(~res, curr);
   79 #		r := GaloisImage(r, 1);
   80 #	    end for;
   81 #	end for;
   82 #    else
   83 #	error "Error: Unsupported defining polynomial";
   84 #    end if;
   85 
   86 #    return res;
   87 #end intrinsic;
   88 
   89 #function eval_field_automorphism(x, m)
   90 #    F := Parent(x);
   91 #    R := RingOfIntegers(F);
   92 #    pi := UniformizingElement(F);
   93 
   94 #    xv := Valuation(x);
   95 #    xu := ShiftValuation(x, -xv);
   96 #    return (F ! m(UniformizingElement(R)))^xv * F ! m(R ! xu);
   97 #end function;
   98 
   99 #function construct_field_map(L, m)
  100 #    res := map<L -> L | x :-> eval_field_automorphism(x, m)>;
  101 #    res`LocalRingMap := m;
  102 #    return res;
  103 #end function;
  104 
  105 #intrinsic Automorphisms(L::FldPad) -> SeqEnum
  106 #{Return the automorphisms of the local ring L. Automorphisms are returned as a sequence of maps}
  107 #    maps := Automorphisms(RingOfIntegers(L));
  108 #    return [construct_field_map(L, m) : m in maps];
  109 #end intrinsic;
  110 
  111 #function auto_eq(m1, m2)
  112 #    return m1`LocalAutoGenerators eq m2`LocalAutoGenerators;
  113 #end function;
  114 
  115 #function auto_mult(m1, m2)
  116 #    gens1 := m1`LocalAutoGenerators;
  117 #    gens2 := m2`LocalAutoGenerators;
  118 #    gens := [];
  119 #    for i in [1..#gens1] do
  120 #	Append(~gens, eval_automorphism(gens1[i], gens2, 1));
  121 #    end for;
  122 
  123 #    L := Universe(gens1);
  124 #    m := map<L -> L | x :-> eval_automorphism(x, gens, 1)>;
  125 #    m`LocalAutoGenerators := gens;
  126 #    return m;
  127 #end function;
  128 
  129 #intrinsic AutomorphismGroup(L::RngPad) -> GrpPerm
  130 #{Return the automorphism group of L as a permutation group}
  131 #    maps := Automorphisms(L);
  132 
  133 #    G, m1 := GenericGroup(
  134 #	maps : Mult := auto_mult, Eq := auto_eq, Id := maps[1]
  135 #    );
  136 #    m2, G2 := CosetAction(G, sub<G|>);
  137 #    m := Inverse(m2) * m1;
  138 #    return
  139 #	G2,
  140 #	map<
  141 #	    G2 -> PowerStructure(Map) | g :-> m(g), h :-> h @@ m
  142 #	>;
  143 #end intrinsic;
  144 
  145 #intrinsic AutomorphismGroup(L::FldPad) -> GrpPerm
  146 #{Return the automorphism group of L as a permutation group}
  147 #    G, m := AutomorphismGroup(RingOfIntegers(L));
  148 
  149 #    return
  150 #	G,
  151 #	map<
  152 #	    G -> PowerStructure(Map) |
  153 #	    g :-> construct_field_map(L, m(g)),
  154 #	    h :-> h`LocalRingMap @@ m
  155 #	>;
  156 #end intrinsic;
  157 #
  158 #///////////////////////////////////////////////////////////////////////
  159 #// general functions
  160 #//////////////////////////////////////////////////////////////////////
  161 
  162 #intrinsic BaseRing(L::FldPad) -> FldPad
  163 #{The base field of L}
  164 #  return BaseField(L);
  165 #end intrinsic;
  166 
  167 
  168 #//---------------------------------------------------------------------
  169 #// FACTORIZATION
  170 #//---------------------------------------------------------------------
  171 
  172 # default precision
  173 _realPrec := 10;
  174 
  175 #///////////////////////////////////////////////////////////////////////
  176 #// some functions for polynomials that probably should be somewhere
  177 #// else
  178 
  179 _ChangePrecisionCoeff:= function(PR,n)
  180   local Co,Co2;
  181   Co:= CoefficientRing(PR);
  182   Co2:= ChangePrecision(Co,n);
  183   return PolynomialAlgebra(Co2);
  184 end;
  185 
  186 
  187 
  188 
  189 IsMonic:= function(f)
  190     return LeadingCoefficient(f)= One(CoefficientRing(Parent(f)));
  191 end;
  192 
  193 #Computes a polynomial g such that g mod Lm[i] = La[i], Lm and La are lists of Polynomials
  194 ChineseRemainder:= function(Lm,La)
  195 local PR,Mod,CR,i,gcd,e2,e1;
  196 
  197 PR := Parent(Lm[1]);
  198 Mod := Lm[1];
  199 CR := La[1];
  200 for i in [2..Length(Lm)] do
  201     gcd := XGCD(Mod,Lm[i]);
  202 
  203     if Base(gcd)<> One(PR) then
  204        return Error( "Error, ChineseRemainderTheorem: modules must be coprime.");
  205     fi;
  206 
  207     e2 := Mod*(gcd.ext1);
  208     e1 := Lm[i]*(gcd.ext2);
  209 
  210     Mod := Mod*Lm[i];
  211     CR := (e1*CR+e2*La[i]) mod Mod;
  212   od;
  213   return CR;
  214 end;
  215 
  216 PGcd:=function(f,g)
  217   local PR,R,pi,prec,S,H,L,h,loss,l,i,H,p,k;
  218 #Print("PGcd g: ",g,"\nf ",f,"\n");
  219 #// only works for quotient rings.
  220   if Degree(f) < 0 or Degree(g) < 0 then return [One(Parent(f)),0]; fi;
  221 #  ////////////////assert IsMonic(f) or IsMonic(g);
  222   #Print("f: ",f);
  223   #Print("\ng: ",g,"\n");
  224   PR := Parent(f);
  225   R:= CoefficientRing(PR);
  226   pi:= UniformizingElement(R);
  227   prec := Precision(R);
  228   S := SylvesterMatrix(f,g);
  229   H := EchelonForm(S);
  230 #Print("\nPGcd HNF",H,"\n");
  231   H:=H.base;
  232   L := ElementToSequence(H[Rank(H)]);
  233 #Print("L ",L);
  234   h := Coerce(PR,Reverse(L));
  235   l := ElementToSequence(h);
  236   k:= [];
  237   for i in [1..Length(l)] do
  238       k[i]:= Valuation(l[i]);
  239   od;
  240   loss:=Minimum(k);
  241   H:= ElementToSequence(h);
  242   p:= pi^loss;
  243   for i in [1..Length(H)] do
  244       H[i]:= Div(H[i],p);
  245   od;
  246   h := Coerce(PR,H);
  247 #Print("\nPGcd ",h," loss ",loss,"\n");  
  248   return [h, loss];
  249 end;
  250 
  251 
  252 #///////////////////////////////////////////////////////
  253 
  254 is_squarefree:= function(f)
  255    local val,df,L,gcd,loss;
  256   if Degree(f) <= 0 then
  257     return [true, f];
  258   fi;
  259 
  260  # vprint RoundFour,4:" -- disc";
  261  # vtime RoundFour,4:
  262  if Is(Type(f),elt-alg^pol/res^pad) or Is(Type(f),elt-alg^pol/ord^pad) then 
  263  val :=  Valuation(Discriminant(f));
  264   if val < Precision(CoefficientRing(Parent(f))) then
  265     #vprint RoundFour,3:" -- polynomial is squarefree by discriminant";
  266    return [true, f, 0];
  267   fi;
  268   fi;
  269   df := Derivative(f);
  270   #vprint  RoundFour,4: " -- gcd";
  271   #vtime RoundFour,4:
  272   L := PGcd(f,df);
  273   gcd:= L[1];
  274   loss:= L[2];
  275   if Degree(gcd) < 1 then
  276     #vprint RoundFour,3:" -- polynomial is squarefree by gcd";
  277     return [true, f, loss];
  278   else
  279     return [false,Div(f,gcd), loss];
  280   fi;
  281 
  282 end;
  283 
  284 #//TODO ???
  285 #//intrinsic IsSquareFree(f::RngUPolElt[RngPadResExtElt])
  286 #//{return
  287 #//  is_squarefree(f)
  288 
  289 
  290 
  291 #///////////////////////////////////////////////////////
  292 #// functions for handling polynomials with denominators
  293 
  294 #/////////////////////////////////////////////////////////////
  295 #// in the round four elements are represented by polynomials
  296 #// and the exponent of pi in the denomiantor
  297 #// we also store additional information in the structure
  298 #theta has to be a record with .elt and .denval components
  299 
  300 # 'cancels out' powers of the uniformizer pi in the polynomial
  301 # and its denominator.
  302 
  303 elt_reduce := function(theta)
  304 local seq,vallist,i,minval,pi;
  305   if theta.elt = Coerce(Parent(theta.elt),0) then
  306     theta.denval:= 0;
  307     return theta;
  308   elif theta.elt<>"null" then
  309     seq := ElementToSequence(theta.elt);
  310     vallist:= [];
  311     for i in [1..Length(seq)] do
  312         vallist[i]:= Valuation(seq[i]);
  313     od;
  314     minval := Minimum(vallist);
  315     if minval > 0 and theta.denval>= minval then
  316       pi := UniformizingElement(CoefficientRing(Parent(theta.elt)));
  317       theta.elt := Div(theta.elt,pi^minval);
  318       theta.denval := theta.denval - minval;
  319     fi;
  320   fi;
  321 return theta;
  322 end;
  323 
  324 # constructor
  325 eltRec := function(phi, denval)
  326 local theta;
  327  #   ELT :=    recformat
  328    #           <elt:RngUPolElt,       // the numerator of the element
  329   #             denval:IntegerRing(),   // the denominator of elt is pi^den,
  330    #            chi:RngUPolElt,       // its characteristic polynomial
  331      #          passes_hensel_test,   // true if it passes the hensel test
  332     #           nu:RngUPolElt,        // irreducible factor of chi mod pi
  333       #         f:IntegerRing(),         // deg(nu)
  334        #        res_fact,             // factorization of chi mod pi
  335         #       passes_newton_test,   // true if it passes the newton test
  336          #      v_star,               // v_star valuations of elt
  337           #     e:IntegerRing()          // numerator of vstar
  338            #   >;
  339     theta := rec(elt := phi, denval:= denval, chi:="null", passes_hensel_test:="null", nu:="null",f:="null", res_fact:="null",passes_newton_test:="null",v_star:="null",e:="null");
  340     theta :=elt_reduce(theta);
  341     return theta;
  342 
  343 end;
  344 
  345 #//////////////////////////////////////////////////
  346 #// Find the inverse of some (invertible) element theta modulo Phi.
  347 #// the inverse is given as res/pi^denval
  348 elt_inverse := function(theta, Phi)
  349 
  350 local pi,P,R,M,L,E,T,res2,gcd,denval,uni;
  351     pi := UniformizingElement(CoefficientRing(Parent(Phi)));
  352     P := Parent(theta.elt);
  353     R := CoefficientRing(P);
  354     M := SylvesterMatrix(theta.elt, Phi);
  355     L:=EchelonForm(M);
  356     E:= L.base;
  357     T:= L.ext1;
  358     res2 := (Coerce(P,Reverse(ElementToSequence(ExtractBlock(T, NumberOfRows(T), 1,1,Degree(Phi)))))) mod Phi;
  359     gcd := Coerce(CoefficientRing(E),E[NumberOfRows(E)][NumberOfColumns(E)]);
  360     denval := Valuation(gcd);
  361     uni := Div(gcd,pi^denval);
  362     res2 := Div(res2,uni);
  363     denval := denval - theta.denval;
  364     if denval < 0 then
  365       res2 := res2*pi^(-denval);
  366       denval := 0;
  367     fi;
  368     return eltRec(res2,denval);
  369 end;
  370 
  371 #//////////////////////////////////////////////////
  372 # compute the v_star valuation from a given characteristic polynomial f
  373 v_star := function(f)
  374 local coeffs,L,i, res2;
  375     if IsMonic(f)= false then
  376        Print("f not monic\n");
  377        return;
  378     fi;
  379     coeffs := Reverse(ElementToSequence(f));
  380     Butfirst_(coeffs);
  381     L:=[];
  382     for i in [1..Length(coeffs)] do
  383         L[i]:= (Valuation(coeffs[i]))/i;
  384     od;
  385     res2 := Minimum(L);
  386     return res2;
  387 end;
  388 
  389 
  390 #////////////////////////////////////////////
  391 #// computation of characteristic polynomials
  392 
  393 #////////////////////////////////////////////////////////////////
  394 #// compute the characteristic polynomials using newton relations
  395 #// (cohen 1, p 161)
  396 #// the traces_from_poly of tyhe reference polynomials Phi are
  397 #// precomputed and applied in th computation of char polys wrt
  398 #// Phi.
  399 
  400 traces_from_poly := function(Phi)
  401 local n,R,L,inc,tmp_R,tmp_PR,tmp_Phi,t,S,k,Sk,i,char;
  402   n := Degree(Phi);
  403   R := CoefficientRing(Parent(Phi));
  404   if Is(Type(R),ord^ser) or Is(Type(R),res^ser) then
  405      char := Coerce(R,Characteristic(CoefficientRing(R)));
  406   else char:= -1;
  407   fi;
  408   #// precision loss occurs in poly_from_traces by division
  409   if n > 0 then
  410     L:=[];
  411     for i in [1..n] do
  412         if Coerce(R,i) = char then
  413            L[i]:= 0;
  414         else L[i]:= Valuation(Coerce(R,i));
  415         fi;
  416     od;
  417     inc := Maximum(L);
  418     inc := inc^2;
  419   else
  420     inc := 0;
  421   fi;
  422   if not Precision(R)=INFTY then
  423   tmp_R := ChangePrecision(R,Precision(R)+inc);
  424   else tmp_R:= R;
  425   fi;
  426   tmp_PR := PolynomialAlgebra(tmp_R);
  427   tmp_Phi := Coerce(tmp_PR,Phi);
  428 
  429   t := function(i)
  430     if i < 0 then
  431       return 0;
  432     else
  433       return Coefficient(tmp_Phi,i);
  434     fi;
  435   end;
  436 
  437   S := [];
  438 
  439   for k in [1..n] do
  440     Sk := -k*t(n-k);
  441     for i in [1..Minimum(n,k-1)] do
  442       Sk := Sk - t(n-i)*S[k-i];
  443     od;
  444     Append_(S,[Sk]);
  445   od;
  446   return S;
  447 end;
  448 
  449 
  450 poly_from_traces := function(S)
  451 local n,Tn,k,Tnk,i;
  452   n := Length(S);
  453   Tn := [];
  454 
  455   for k in [1..n] do
  456     Tnk := -S[k];
  457     for i in[1..k-1] do
  458       Tnk := Tnk - Tn[i]*S[k-i];
  459     od;
  460     Tnk := Div(Tnk,k);
  461     Append_(Tn,[Tnk]);
  462   od;
  463   Tn := Reverse(Tn);
  464   Append_(Tn,[Coerce(Parent(S[1]),1)]);
  465   return Coerce(PolynomialAlgebra(Parent(S[1])),Tn);
  466 end;
  467 
  468 
  469 chi := function(Phi, traces_Phi, theta)
  470 local ret,k, L,tmp_PR,tmp_theta,tmp_Phi,n,S,pow2,i,Si,j,M,S,li,T,nu;
  471 
  472   tmp_PR := PolynomialAlgebra(Parent(traces_Phi[1]));
  473   #L:= ElementToSequence(theta);
  474   #Print(theta,"\n");
  475   #Print(L,"\n",Type(L[2]),"\n");
  476  #M:= [];
  477      # for i in [1..Length(L)] do
  478 	 #    nu:= ElementToSequence(L[i]);
  479              
  480 	  #   if Length(nu)>1 then
  481 	  #      li:= false;
  482 	   #     for j in [2..Length(nu)] do
  483 		#    if nu[j] <>0 then
  484 	#	       li:= true;
  485 		#    fi;
  486 		# od;
  487 	      #  if li then
  488 	      #     T:= [];
  489 	      #     for j in [1..Length(nu)] do
  490 	     #         T[j]:=Coerce(IntegerRing(),nu[j]);
  491 	    #       od;
  492 	      #     M[i]:= Element(CoefficientRing(tmp_PR),T);
  493 	     #   else
  494               #     M[i]:=Coerce(IntegerRing(),L[i]);
  495 		#fi;
  496 	    # else
  497 	   #  	     M[i]:=Coerce(IntegerRing(),L[i]);
  498 	#  fi;
  499       #od;
  500 
  501   tmp_theta := Coerce(tmp_PR,theta);
  502   tmp_Phi := Coerce(tmp_PR,Phi);
  503 #Print("tmp_PR: ",tmp_PR,"\nCoefficientRing(tmp_PR): ",CoefficientRing(tmp_PR),"\nType(theta): ",Type(theta),"\nCoefficientRing(Parent(theta)): ",CoefficientRing(Parent(theta)),"\n");
  504   n := Degree(Phi);
  505   S := [];
  506   pow2 := 1;
  507   for i in [1..n] do
  508     pow2 := pow2*tmp_theta mod tmp_Phi;
  509 
  510     Si := 0;
  511     Si := n*Coefficient(pow2,0);
  512     for j in [1..Degree(pow2)] do
  513       if Coefficient(pow2,j) <> 0 then
  514         Si :=Si+traces_Phi[j]*Coefficient(pow2,j);
  515       fi;
  516     od;
  517     Append_(S,[Si]);
  518   od;
  519   ret :=  Coerce(Parent(Phi),poly_from_traces(S));
  520   return ret;
  521 end;
  522 
  523 pow_chi:= function(Phi,theta)
  524 local A2,chi,L,j,A,chir,a,b, elseq,pi,poly,prec,n,i,j,E,ech,phi,pa,T,nu,ra,k,loss,p,inv,denv,mult;
  525 phi:= theta.elt;
  526 denv:= theta.denval;
  527 pa:= Parent(Phi);
  528 prec:= Precision(CoefficientRing(pa));
  529 pi:= UniformizingElement(CoefficientRing(pa));
  530 n:= Degree(Phi);
  531 A:= [];
  532 for i in [1..n+1] do
  533     a:= pi^(denv*(n-i+1));
  534     b:= phi^(i-1);
  535     a:= Coerce(Parent(b),a);
  536     elseq:= ElementToSequence(a*b mod Phi);
  537     for  j in [Length(elseq)+1..n+1] do
  538          Append_(elseq,[Coerce(CoefficientRing(pa),0)]);
  539     od;
  540     A:=Append(A,elseq);
  541 od;
  542 for i in [1..n+1] do
  543     L:=[];
  544     for j in [1..n+1] do
  545         if i = j then 
  546            L[j]:= pi^prec;
  547         else L[j]:= Coerce(pa,0);
  548         fi;
  549     od;
  550     A:=Append(A,L);
  551 od;
  552 A:= Matrix(CoefficientRing(pa),2*(n+1),n+1,A);
  553 ech:= EchelonForm(A);
  554 E:= ech.base;
  555 T:= ech.ext1;
  556 ra:= Rank(E);
  557 for i in [ra..2*(n+1)] do
  558     nu:= true;
  559     for j in [1..Length(E[i])] do
  560         if E[i][j]<> Coerce(Parent(E[i][j]),0) then
  561            nu:=false;
  562            j:= Length(E[i]);
  563         fi; 
  564    od;
  565 if nu then chi:= Coerce(Parent(Phi),List(T[i]));
  566    if chi <> Element(Parent(Phi),0) then
  567        chir:=chi;
  568    fi;
  569 fi;
  570 od;
  571 elseq:= ElementToSequence(chir);
  572 k:= [];
  573 poly:=[];
  574   for i in [1..Length(elseq)] do
  575       poly[i]:= elseq[i];
  576       k[i]:= Valuation(poly[i]);
  577   od;
  578 loss:=Minimum(k);
  579 p:= pi^loss;
  580 chir:= Element(Parent(Phi),poly);
  581 chir:= Div(chir,p);
  582 inv:= IsInvertible(LeadingCoefficient(chir));
  583 if inv.base then
  584    inv:= inv.ext1;
  585 else return Error("pow_chi not monic");
  586 fi;
  587 chir:= chir*Coerce(pa,inv);
  588 return [chir,loss];
  589 end;    
  590 
  591 
  592 #{Find char poly of theta * pi^-theta_denval}
  593 elt_chi := function(Phi, traces_Phi, theta)
  594 local PR,R,tmp_R,tmp_PR,res2,pi;
  595      if Is(Type(Phi),elt-alg^pol/ord^ser) or Is(Type(Phi),elt-alg^pol/res^ser) then
  596        return  pow_chi(Phi,theta)[1];
  597     fi;
  598     #vprint RoundFour,5:" -- char poly";
  599     #vprint RoundFour,6:" -- of",theta`elt;
  600     #vprint RoundFour,6:" -- with denominator pi ^",theta`denval;
  601     PR := Parent(Phi);
  602     R := CoefficientRing(Parent(Phi));
  603     if not Precision(R)=INFTY then
  604     tmp_R := ChangePrecision(R,Precision(R)+4*theta.denval*Degree(Phi));
  605     else tmp_R:= R;
  606     fi;
  607     tmp_PR := PolynomialAlgebra(tmp_R);
  608     #vtime RoundFour,5:
  609     #Print("Phi: ",Phi,"\nCoefficientRing(Parent(Phi)):",CoefficientRing(Parent(Phi)),"\n");
  610     #Print("traces_Phi: ",traces_Phi,"\nType(traces_Phi[1]): ",Type(traces_Phi[1]),"\n");
  611     #Print("theta.elt:",theta.elt,"\nCoefficientRing(Parent(theta.elt)):",CoefficientRing(Parent(theta.elt)),"\n\n");
  612     res2 := chi(Phi, traces_Phi, theta.elt);
  613     #//"vstar",v_star(res);
  614     #//"denval",theta`denval;
  615     if v_star(res2) < theta.denval then
  616       return Error("Factorization:Insufficient precision in characteristic polynomial computation");
  617     fi;
  618     res2 := Coerce(tmp_PR,res2);
  619     pi := UniformizingElement(tmp_R);
  620     res2 := Evaluate(res2, pi^theta.denval * tmp_PR.1);
  621     res2:= Div(res2,LeadingCoefficient(res2));
  622     res2 := Coerce(PR,res2);
  623      if IsMonic(res2)= false then
  624        return Error("f not monic at elt_chi\n");
  625        return;
  626     fi;
  627 #Print(" testing chi(theta)", elt_evaluate(Phi,eltRec(Coerce(PR,res2),0),theta),"\n");
  628     return Coerce(PR,res2);
  629 end;
  630 
  631 
  632 #// compute invariants of elt, war eigentlich procedure, die phi veraenderte
  633 elt_invariants:= function(Phi, traces_Phi, phi)
  634 local res_chi,fact,K,pc;
  635 
  636   if phi.chi="null" then
  637     if Is(Type(Phi),elt-alg^pol/ord^ser) or Is(Type(Phi),elt-alg^pol/res^ser) then
  638        pc:= pow_chi(Phi,phi);
  639        phi.chi:= pc[1];
  640        phi.chi:= Coerce(PolynomialAlgebra(ChangePrecision(CoefficientRing(Parent(pc[1])),Precision(CoefficientRing(Parent(pc[1])))+pc[2])),phi.chi);
  641     else
  642     phi.chi := elt_chi(Phi, traces_Phi, phi);
  643     fi;
  644   fi;
  645   phi.v_star := v_star(phi.chi);
  646   #Print("v_star:",phi.v_star,"    chi:",phi.chi,"\n");
  647   #Print("CoefficientRing(Parent(chi)): ", CoefficientRing(Parent(phi.chi)),"\n");
  648   phi.passes_newton_test :=
  649     phi.v_star = Valuation(TrailingCoefficient(phi.chi)) / Degree(phi.chi);
  650   phi.e := Denominator(phi.v_star);
  651   if phi.passes_newton_test or phi.v_star = 0 then
  652     if phi.res_fact = "null" then
  653       if IsField(CoefficientRing(Parent(phi.chi))) then
  654          K:=ResidueClassField(IntegerRing(CoefficientRing(Parent(phi.chi))));
  655       else
  656           K := ResidueClassField(CoefficientRing(Parent(phi.chi)));
  657       fi;
  658 
  659       #Print("K: ",K,"phi.chi: ", phi.chi,"\n");
  660       res_chi := Coerce(PolynomialAlgebra(K),phi.chi);
  661      # Print("Parent(res_chi): ",Parent(res_chi),"res_chi: ",res_chi,"\n");
  662       fact := Factorization(res_chi);
  663       #Print("fact: ",fact," Parent(fact[1][1]): ",Parent(fact[1][1]),"\n");
  664       phi.res_fact := fact;
  665     fi;
  666     phi.passes_hensel_test := (Length(phi.res_fact) = 1);
  667     if phi.passes_hensel_test then
  668       phi.nu := Coerce(Parent(phi.chi),phi.res_fact[1][1]);
  669       phi.f := Degree(phi.nu);
  670    fi;
  671   else
  672     phi.passes_hensel_test := true;
  673   fi;
  674  return phi;
  675 end;
  676 
  677 #// ??? !!! TODO ft(k2,L[14][3]);
  678 
  679 #// returns theta`elt(tau`elt/pi^tau`denval)/pi^theta`denval mod Phi
  680 elt_evaluate := function(Phi, theta, tau)
  681 local PR,R,inc,tmp_R,tmp_PR,pi,tmp_Phi,tmp_theta,tmp_tau,res2,L,se,i,res_denval;
  682   PR := Parent(Phi);
  683   R := CoefficientRing(PR);
  684   inc := Degree(theta.elt)*tau.denval;
  685   if not Precision(R)=INFTY then
  686   tmp_R := ChangePrecision(R,Precision(R)+inc);
  687   else tmp_R:= R;
  688   fi;
  689   tmp_PR := PolynomialAlgebra(tmp_R);
  690   pi := UniformizingElement(tmp_R);
  691   tmp_Phi := Coerce(tmp_PR,Phi);
  692   tmp_theta :=Coerce(tmp_PR,theta.elt);
  693   tmp_tau := Coerce(tmp_PR,tau.elt);
  694 
  695 
  696   res2 := tmp_theta*pi^inc;
  697   L:= [];
  698   se:= ElementToSequence(res2);
  699   for i in [1..Degree(res2)+1] do
  700         L[i]:= Div(se[i],pi^(tau.denval*(i-1)));
  701   od;
  702   res2 := Coerce(tmp_PR,L);
  703   res2 := Evaluate(res2, tmp_tau) mod tmp_Phi;
  704   res_denval := theta.denval+inc;
  705   return eltRec(Coerce(PR,res2), res_denval);
  706 end;
  707 
  708 #// elt_evaluate
  709 #// and transfer invariants
  710 #// useful when changing reference polynomial
  711 elt_evaluate_trans := function(Phi, traces_Phi, theta, tau)
  712 local res2;
  713 
  714   res2 := elt_evaluate(Phi, theta, tau);
  715   if theta.chi <> "null" then
  716     res2.chi := theta.chi;
  717   fi;
  718   if theta.res_fact <>"null" then
  719     res2.res_fact := theta.res_fact;
  720   fi;
  721   res2:=elt_invariants(Phi, traces_Phi, res2);
  722   return res2;
  723 end;
  724 
  725 
  726 
  727 #//////////////////////////////////////////////////////////////////////////
  728 #//
  729 #// returns a list of exponents res such that
  730 #// v*(pi^res[1]*pool[1]^res[2]*...*pool[m]^res[m+1]) eq val
  731 #// where res[i]<ceils[i-1] (for i>=2) and
  732 #// Denominator(val) | E
  733 calculate_exponents := function(pool, ceils, val, E)
  734 local res2,rem_val,len,now,d,tmpval,tmpool,mud,rcr,sol;
  735   res2 := [];
  736   rem_val := val;
  737   len := Length(pool);
  738   now := len;
  739 
  740   d := E;
  741 
  742   while now > 0 do
  743 
  744     d := d/(ceils[now]);
  745     tmpval := rem_val * d;
  746     tmpool := pool[now] *d;
  747     mud := Denominator(tmpool);
  748     rcr := ResidueClassRing(Coerce(IntegerRing(),mud));
  749     tmpval := tmpval * mud;
  750     tmpool := tmpool * mud;
  751     sol := Coerce(IntegerRing(),((Coerce(rcr,tmpval))/(Coerce(rcr,tmpool))));
  752 
  753     rem_val := rem_val - sol * pool[now];
  754     Append_(res2, [sol]);
  755 
  756     now := now - 1;
  757 
  758   od;
  759 
  760   Reverse_(res2);
  761   Insert_(res2,rem_val,1);
  762   return res2;
  763 end;
  764 
  765 #//{Returns an element poly, such that
  766 #// poly has v_star valuation vstar}
  767 elt_with_v_star := function(Phi, P, P_v_star, S, E, vstar)
  768 local exps,poly_val,poly,i,pi;
  769 
  770 	exps := calculate_exponents(P_v_star, S, vstar, E);
  771 	poly_val := Coerce(IntegerRing(),exps[1]);
  772 	poly := Coerce(Parent(Phi),1);
  773 	if Length(P) <> 0 then
  774 	    for i in [1..Length(P)] do
  775 		 poly:= poly*P[i] ^ exps[i + 1];
  776 	    od;
  777 	fi;
  778 
  779 
  780         if poly_val > 0 then
  781           pi := UniformizingElement(CoefficientRing(Parent(Phi)));
  782           poly := poly*pi^poly_val;
  783           poly_val := 0;
  784         fi;
  785         return eltRec(poly, -poly_val);
  786 end;
  787 
  788 #//////////////////////////////////////////////////////////////////////////
  789 #// the denominator of theta is pi^theta`denval
  790 #// if theta`chi is not assigned or theta`denval gt 0 then chi_theta is computed
  791 
  792 hensel_lift_factorization_sub := function(Phi, theta)
  793 local PR,R,tmp_R,tmp_PR,K,P,pi,tmp_Phi,traces_tmp,Phi,tmp_theta,facts,i,j,lifted_facts,lf,                 eval_facts,res2,traces_tmp_Phi,elm,L,elmi;
  794     PR := Parent(Phi);
  795     R := CoefficientRing(Parent(Phi));
  796     if not Precision(R) =INFTY then
  797     tmp_R := ChangePrecision(R,Precision(R)+Degree(Phi)*(theta.denval));
  798     else tmp_R:= R;
  799     fi;
  800     tmp_PR := PolynomialAlgebra(tmp_R);
  801     K := ResidueClassField(tmp_R);
  802     P := PolynomialAlgebra(K);
  803     pi := UniformizingElement(tmp_R);
  804     tmp_Phi := Coerce(tmp_PR,Phi);
  805     traces_tmp_Phi := traces_from_poly(tmp_Phi);
  806     tmp_theta := theta;
  807     if theta.denval <> 0 or theta.chi ="null" then
  808       tmp_theta.chi := elt_chi(tmp_Phi, traces_tmp_Phi, tmp_theta);
  809     fi;
  810 #Print(" testing chi(theta)", elt_evaluate(tmp_Phi,eltRec(tmp_theta.chi,0),tmp_theta),"\n");
  811     if theta.res_fact <>"null" then
  812       tmp_theta.res_fact := theta.res_fact;
  813     fi;
  814     tmp_theta := elt_invariants(tmp_Phi, traces_tmp_Phi,tmp_theta);
  815     facts:=[];
  816     if tmp_theta.res_fact<>"null" then
  817         for i in [1..Length(tmp_theta.res_fact)] do
  818      facts[i]:=Coerce(tmp_PR,Coerce(P,(tmp_theta.res_fact[i][1]^tmp_theta.res_fact[i][2])));
  819         od;
  820     fi;
  821     if Length(facts)=1 then
  822       if facts[1] = tmp_theta.chi then
  823          L:=[];
  824          L[1]:= [tmp_theta.chi,0];
  825          return L;
  826       else
  827       facts:=Append(facts,[Coerce(Parent(facts[1]),1)]);
  828       fi;
  829     fi;
  830     #Print(facts);
  831     lifted_facts := HenselLift(tmp_theta.chi, facts);
  832     lf:=lifted_facts[1];
  833     for i in [2..Length(lifted_facts)] do
  834         lf:= lf*lifted_facts[i];
  835     od;
  836     if Is(Type(R),ord^ser) or Is(Type(R),res^ser) then
  837        # assuming precision 20
  838        elm:=(ElementToSequence(lf-tmp_theta.chi));
  839         if elm <> [] then
  840         for i in [1..Length(elm)] do
  841             elmi:=ElementToSequence(elm[i]);
  842                 for j in [1.._realPrec] do
  843                    if elmi[j]<>Element(Parent(elmi[i]),0) then return Error("assertion violated\n");fi;
  844                 od;
  845         od;
  846         fi;
  847     else if (lf- tmp_theta.chi)<>0 then return Error("assertion violated\n"); fi;
  848     fi;
  849 
  850     eval_facts:= [1..Length(lifted_facts)];
  851 #Print("henseltest lifted_facts ",lifted_facts);
  852     Apply_(eval_facts,x->elt_evaluate(tmp_Phi,eltRec(lifted_facts[x],0),tmp_theta));
  853 #Print("henseltest eval_facts ",eval_facts,"\n");
  854     #vprint  RoundFour,4: " -- gcd";
  855     #vtime RoundFour,4:
  856     res2:=[1..Length(eval_facts)];
  857     Apply_(res2,x->PGcd(Phi,Coerce(PR,(eval_facts[x].elt))));
  858     return res2;
  859 end;
  860 
  861 
  862 #// the denominator of theta is pi^theta_denval
  863 #// if chi_theta eq 0 or theta_denval gt 0 then chi_theta is computed
  864 hensel_lift_factorization_chi2 := function(Phi, theta)
  865 local flag,PR,R,res2,inc,resProd,i,tmp_R,tmp_theta,res2,tmp_PR,re;
  866     #Print("hensel_lift_factorization_chi2");
  867     flag := 1;
  868 
  869     PR := Parent(Phi);
  870     R := CoefficientRing(Parent(Phi));
  871    # vprint RoundFour,5:" == Hensel lifting to precision", Precision(R),"...";
  872     res2 := hensel_lift_factorization_sub (Phi, theta);
  873     #// if the precion was not sufficient, repeat this step with a higher
  874     #// precision.
  875     inc := 1;
  876     resProd:= res2[1][1];
  877        while (IsList(resProd)) do
  878            resProd:= resProd[1];
  879        od;
  880     for i in[2..Length(res2)] do
  881         if IsList(res2[i]) then
  882         re:=res2[i][1];
  883 	while IsList(re) do
  884 	    re:= re[1];
  885 	od;
  886         resProd:= resProd*re;
  887         fi;
  888     od;
  889 #Print("\nResProd ",resProd,"\n");
  890     while (flag = 1 and Element(Parent(Phi),0) <>((resProd)-Phi)) do
  891       #Print("difference: ",resProd-Phi,"\n");
  892       #//print inc;
  893       if not Precision(R) =INFTY then
  894       tmp_R := ChangePrecision(R,Precision(R)+4*Degree(Phi)*inc);
  895       else tmp_R:= R;
  896       fi;
  897       #vprint RoundFour,5:" == ... trying Hensel lift again, precision increased by",
  898        #                  4*Degree(Phi)*inc,"...";
  899       tmp_PR := PolynomialAlgebra(tmp_R);
  900       tmp_theta := eltRec(Coerce(tmp_PR,theta.elt), theta.denval);
  901 
  902       if theta.res_fact<>"null" then
  903 
  904         tmp_theta.res_fact := theta.res_fact;
  905       fi;
  906       #Print("henselLift: prec ",Precision(tmp_R));
  907       res2:= hensel_lift_factorization_sub(Coerce(tmp_PR,Phi),tmp_theta);
  908       for i in [1..Length(res2)] do
  909          res2[i][1] := [Coerce(PR,res2[i][1])];
  910       od;
  911       resProd:= res2[1][1];
  912       while (IsList(resProd)) do
  913            resProd:= resProd[1];
  914        od;
  915       for i in[2..Length(res2)] do
  916          re:=res2[i][1];
  917 	 while(IsList(re)) do
  918 	    re:= re[1];
  919 	 od;
  920          resProd:= resProd*re;
  921       od;
  922       inc :=inc+ 1;
  923     od;
  924     #vprint RoundFour,5:" == ... done";
  925     return res2;
  926 end;
  927 
  928 
  929 newton_lift_factorization_chi2 := function(Phi, theta)
  930 local rs,gamma;
  931 # //print "newton theta",theta,theta_denval;
  932 #//"theta",theta;
  933   if theta.v_star = 0 and theta.passes_hensel_test=FALSE then
  934     #//print "newton_lift_factorization_chi2 hensel";
  935     return hensel_lift_factorization_chi2(Phi, theta);
  936   fi;
  937 
  938   rs := theta.v_star;
  939   #vprint RoundFour,5:" == flattening Newton polygon slope from",rs,"to 0";
  940   gamma := eltRec(Coerce(Parent(Phi),(theta.elt^Denominator(rs)) mod Phi),
  941                Numerator(rs)+theta.denval*Denominator(rs));
  942   return hensel_lift_factorization_chi2(Phi, gamma);
  943 
  944 end;
  945 
  946 #/////////////////////////////////////////////////////////////////////////////////
  947 
  948 #//{Find a polynomial delta with Degree(delta)<Degree(nu_phi)
  949 #// and v_star(delta-gamma)>0}
  950 #// returns:
  951 #// true, delta, xxx
  952 #//   if such an element delta has been found
  953 #// false, xxx, rho
  954 #//   if during the search for delta an element that fails the
  955 #//   hensel test has occured.
  956 
  957 res_field_rep := function (Phi, traces_Phi, nu, gamma)
  958 local pi,K,P,nur,F,PF,facts,i,a,b,delta,rho,Co,p,prec,g,L,M,S,T,j,U,li;
  959 
  960    if Degree(gamma.nu) = 1 then
  961      return [true, -TrailingCoefficient(gamma.nu), 0];
  962    fi;
  963 
  964    if gamma.denval = 0 then
  965      return [true, gamma mod nu, 0];
  966    fi;
  967    Co:= CoefficientRing(Parent(Phi));
  968 
  969   # if Is(Type(Co),res^pad) then
  970    #   p:= Size(ResidueClassField(Co).base);
  971     #  prec:= Coerce(IntegerRing(),(Precision(Co)/RamificationDegree(Co)));
  972     #  g:= DefiningPolynomial(Co);
  973     #  Co:= pAdicRing(p,prec);
  974     #  Co:= TotallyRamifiedExtension(Co,g);
  975     #  L:= ElementToSequence(g);
  976 
  977     #  M:= [];
  978     #  for i in [1..Length(L)] do
  979     #	     S:= ElementToSequence(L[i]);
  980 #	     if Length(S)>1 then
  981 #	        li:= false;
  982 #	        for i in [2..Length(S)] do
  983 #		    if S[i] <>0 then
  984 #		       li:= true;
  985 #		    fi;
  986 #		 od;
  987 #	        if li then
  988 #	           T:= [];
  989 #	           for j in [1..Length(S)] do
  990 #	              T[i]:=Coerce(IntegerRing(),S[i]);
  991 #	           od;
  992 #	           M[i]:= Element(Co,T);
  993 #	        else
  994 #                   M[i]:=Coerce(IntegerRing(),L[i]);
  995 #		fi;
  996 #	     else M[i]:=Coerce(IntegerRing(),L[i]);
  997 #	  fi;
  998 #     od;
  999 #      gamma.elt:= Coerce(PolynomialAlgebra(Co),M);
 1000 #   fi;
 1001    pi := UniformizingElement(Co);
 1002    K := ResidueClassField(Co);
 1003    P := PolynomialAlgebra(K);
 1004    nur := Coerce(P,nu);
 1005    F := Extension(K,nur);
 1006    PF:= PolynomialAlgebra(F);
 1007    facts := Roots(Coerce(PF,(Coerce(P,gamma.nu))));
 1008    for i  in [1..Length(facts)] do
 1009      a := ElementToSequence(facts[i][1]);
 1010      b := Coerce(PF,a);
 1011      delta := Coerce(PolynomialAlgebra(Co),b);
 1012      rho := eltRec(gamma.elt-Coerce(Parent(gamma.elt),pi)^gamma.denval*delta,gamma.denval);
 1013      rho:=elt_invariants(Phi, traces_Phi, rho);
 1014      if rho.passes_hensel_test=FALSE then
 1015        return [false, 0, rho];
 1016      fi;
 1017      if rho.v_star > 0 then
 1018        return [true, Coerce(Parent(Phi),delta), 0];
 1019      fi;
 1020    od;
 1021    return Error ("Factorization: Round Four Panic, no representing element found.");
 1022 end;
 1023 
 1024 #// x gives a residue class field extension of degree F_x
 1025 #// gamma/pi^gamma_denval gives a residue class field extension of
 1026 #// degree F_gamma
 1027 #// find a poltynomial that gives a residue class field extension of
 1028 #// degree LCM(F_x,F_gamma)
 1029 #  //print "kappa",kappa,"/",pi^kappa_denval;
 1030 
 1031 ff_composition_gen := function(Phi, x, F_x, gamma)
 1032 local kappa,PR,R,denval,tmp_R,tmp_PR,x,pi,tmp_Phi,traces_tmp_Phi,tmp_gamma,K,F,pow,pow2,coeff,li,y,i;
 1033   if gamma.f = LCM(F_x,gamma.f) then
 1034     kappa := gamma;
 1035     return kappa;
 1036   fi;
 1037 
 1038   #//print "gamma",gamma;
 1039   PR := Parent(Phi);
 1040   R := CoefficientRing(Parent(Phi));
 1041   denval := gamma.denval*gamma.f;
 1042   if not Precision(R) = INFTY then
 1043   tmp_R := ChangePrecision(R,Precision(R)+denval);
 1044   else tmp_R:= R;
 1045   fi;
 1046   #//tmp_R := pAdicQuotientRing(Prime(R),Precision(R)+denval);
 1047   tmp_PR := PolynomialAlgebra(tmp_R);
 1048   y:=tmp_PR.1;
 1049   pi := UniformizingElement(tmp_R);
 1050   tmp_Phi := Coerce(tmp_PR,Phi);
 1051   traces_tmp_Phi := traces_from_poly(tmp_Phi);
 1052   tmp_gamma := Coerce(tmp_PR,gamma.elt);
 1053 
 1054   K := ResidueClassField(tmp_R);
 1055 
 1056   F := LCM(F_x,gamma.f);
 1057   pow:=[1..F_x];
 1058   Apply_(pow,x->(pi^(denval)*y^(x-1)) mod (pi^denval*tmp_Phi));
 1059   pow2:=[1..gamma.f];
 1060   Apply_(pow2,x->pi^(denval-(gamma.denval*(x-1)))*tmp_gamma^(x-1)mod (pi^denval*tmp_Phi));
 1061   pow := Concatenation(pow,pow2);
 1062 
 1063   repeat
 1064     coeff:=[1..Length(pow)];
 1065     Apply_(coeff,x->Coerce(tmp_R,Random(K)));
 1066     #//"coeff",coeff;
 1067     li:= [1..Length(pow)];
 1068     Apply_(li,x->coeff[x]*pow[x]);
 1069     kappa:= li[1];
 1070     for i in [2..Length(li)] do
 1071        kappa := kappa+li[i];
 1072     od;
 1073     kappa:= eltRec(kappa mod tmp_Phi,denval);
 1074     kappa:= elt_invariants(tmp_Phi, traces_tmp_Phi,kappa);
 1075   until kappa.f = F;
 1076 
 1077   kappa.elt := Coerce(PR,kappa.elt);
 1078 
 1079   return kappa;
 1080 
 1081 end;
 1082 
 1083 
 1084 
 1085 
 1086 #////////////////////////////////////////////////////////////////////////
 1087 
 1088 
 1089 #//-------------------------
 1090 round_four := function(Phi, with_certificates)
 1091 local PR,K,pi,Phihat,traces_Phi,traces_Phihat,P,S,P_v_star,E,phi_old_v_star,phi,F,kappa,nu,Pi,theta,
 1092        s,Gamma,BETA,phis,poly,psi,poly_inv,gamma,beta,newPhi,r_L,rho_passes_hensel_test,delta,rho,         deltapsi,further_factorization;
 1093 #//-------------------------
 1094 #// the algorithm used is a hybrid between
 1095 #// pauli: factoring polynomials over local fields
 1096 #// and
 1097 #// ford-pauli-roblot: a fast algorithm for factoring polynomials over Qp
 1098 #//
 1099 #// step g) [extend the ground field] in the pauli algorithm is replaced by
 1100 #// by the combination of step 12 in algorithm 5.1 and step 2,3 in 5.2 in
 1101 #// ford-pauli-roblot
 1102 #//
 1103 #// if certificates is false the information needed for the certificates is not
 1104 #// computed
 1105 
 1106 
 1107 
 1108  #   vprint RoundFour,1:"R4: factoring Phi with deg(Phi) =",Degree(Phi);
 1109  #  vprint RoundFour,3:"R4: Phi =",Phi;
 1110 
 1111  #   FACTOR := recformat
 1112  #             <factor:RngUPolElt,
 1113  #              multiplicity:IntegerRing(),
 1114  #              F:IntegerRing(),              // inertia deg
 1115  #              Gamma:RngUPolElt,          // unramified
 1116  #              Gamma_denval:IntegerRing(),   // certificate
 1117  #              E:IntegerRing(),              // ram index
 1118  #              Pi:RngUPolElt,             // ramified
 1119  #              Pi_denval:IntegerRing(),      // certificate
 1120  #              IdealGen1,                 // two element representation
 1121  #              IdealGen2                  // of the prime ideal
 1122  #             >;
 1123 
 1124 further_factorization := function(factors, with_certificates)
 1125 local L,i,certs,j,fact;
 1126   L := [];
 1127   for i in [1..Length(factors)] do
 1128       fact:=factors[i][1];
 1129       while IsList(fact) do
 1130            fact:= fact[1];
 1131       od;
 1132       certs:=round_four(fact, with_certificates);
 1133     for j in [1..Length(certs)] do
 1134       Append_(L,[certs[j]]);
 1135     od;
 1136   od;
 1137   return L;
 1138 end;
 1139 
 1140     PR := Parent(Phi);
 1141     K := CoefficientRing(PR);
 1142     pi := UniformizingElement(K);
 1143 
 1144   #  vprint RoundFour,4:"R4: over",K;
 1145 
 1146     if Degree(Phi) <= 1 then
 1147       return [rec(factor:=Phi,multiplicity:= 1, F:=1,Gamma:=Coerce(PR,1),Gamma_denval:=0, E:=1,Pi:=Coerce(PR,pi),Pi_denval:=0)];
 1148     fi;
 1149 
 1150 
 1151     Phihat := Phi;
 1152     traces_Phi := traces_from_poly(Phi);
 1153     traces_Phihat := traces_Phi;
 1154     #//////////////////////////// RAMIFIED DATA
 1155     P := [];                  #// list of polynomials that allows
 1156                               #// construction of polynomials with
 1157                               #// v_star valuation with den up to E
 1158     S := [];                  #// list of maximal exponents to be used
 1159                               #// for the polynomials in P
 1160     P_v_star := [];           #// list of v_star valuations of the elements
 1161                               #// of P
 1162     E := 1;                   #// highest known ramification index
 1163     phi_old_v_star := 0;      #// old v* valuation of phi, used to check
 1164                               #// that valuation of phi increases
 1165     #////////////////////////////
 1166     BETA := eltRec(PR.1,0);      #// we record the change of the reference
 1167                               #// polynomial Phihat in BETA/pi^BETA_denval
 1168     #////////////////////////////
 1169 
 1170 #//////////////////////////////////////////////////////////////////////////
 1171 
 1172 
 1173 
 1174 
 1175 
 1176     phi := eltRec(PR.1,0);
 1177     phi.chi := Phihat;
 1178     phi:=elt_invariants(Phihat, traces_Phihat, phi);
 1179 
 1180     if phi.passes_newton_test=FALSE or phi.passes_hensel_test=FALSE then
 1181         #vprint RoundFour,1:"R4: x fails Newton or Hensel test -- factoring";
 1182         return further_factorization(newton_lift_factorization_chi2(Phi, phi), with_certificates);
 1183     fi;
 1184 
 1185     #///////////////////// UNRAMIFIED DATA
 1186     F     := phi.f;    #// highest known inertia degree
 1187     kappa := phi;      #// generator of the unramified extension of degree F
 1188     nu    := kappa.nu; #// generating polynomial of the unramified
 1189     #///////////////////// extension of degree F
 1190 
 1191     phi   := eltRec(phi.nu,0);
 1192     phi:=elt_invariants(Phihat, traces_Phihat,phi);
 1193 
 1194     #vprint RoundFour,1:"R4: initializing E to",E,"and F to",F;
 1195     #vprint RoundFour,3:"R4: inertia element:",BETA`elt;
 1196 
 1197     if F = Degree(Phi) then
 1198       #vprint RoundFour,1:"R4: F =",F,"= deg(Phi)  =>  Phi is irreducible";
 1199       #//vprint RoundFour,1:"R4: computing 2 element certificate";
 1200       return [rec(factor:=Phi,multiplicity:=1,F:=F,Gamma:=PR.1,Gamma_denval:=0,E:=1, Pi:=Coerce(PR,pi), Pi_denval:= 0)];
 1201     fi;
 1202 
 1203     #//print "nu_phi",nu_phi;
 1204 
 1205 
 1206     #// main loop
 1207     while true do
 1208        # vprint RoundFour,2:"R4| phi =",phi`elt;
 1209        #vprint RoundFour,1:"R4| deg(phi) =", Degree(phi`elt),"and v*(phi) =", phi`v_star;
 1210        # vprint RoundFour,2:"R4| E =",E,"and F =",F;
 1211         #/* Step a ***************************************************************/
 1212 	#Print(phi.v_star," ",phi_old_v_star,"\n");
 1213         if  phi.v_star <= phi_old_v_star then
 1214           return Error ("Factorization: Insufficient precision in Round Four main loop");
 1215         fi;
 1216         if Degree(phi.elt) > E*F then
 1217           return Error ("Factorization: Degree of phi too large in Round Four main loop");
 1218         fi;
 1219 
 1220         if phi.passes_newton_test=FALSE then
 1221 	    #vprint RoundFour,1:"R4a phi fails Newton test -- factoring";
 1222             theta := elt_evaluate_trans(Phi,traces_Phi,phi,BETA);
 1223 	    return further_factorization(newton_lift_factorization_chi2
 1224                               (Phi, theta),with_certificates);
 1225 	    #vprint RoundFour,4:"R4a phi passes Newton test";
 1226 	fi;
 1227 
 1228 	#/* Step b [increase E] **************************************************/
 1229         if E mod phi.e <> 0 then
 1230 	    Append_(P, [phi.elt]);
 1231 	    Append_(P_v_star, [v_star(chi(Phihat, traces_Phihat, phi.elt))]);
 1232 	    s := Div(LCM(E, phi.e),E);
 1233 	    Append_(S, [s]);
 1234             #vprint RoundFour,1:"R4b increasing E from",E,"to",s*E;
 1235             #vprint RoundFour,4:"R4b list of polynomials giving ramification",P;
 1236             #vprint RoundFour,4:"R4b with v* valuations",P_v_star;
 1237             #vprint RoundFour,4:"R4b and maximal exponents",S;
 1238 	    E := s * E;
 1239 
 1240             if E*F = Degree(Phihat) then #// Phi is irreducible
 1241               #vprint RoundFour,1:"R4b E * F =",E,"*",F,"= deg(Phi) =",Degree(Phihat),
 1242                #                  "  =>   Phi is irreducible";
 1243               if with_certificates then
 1244                 #vprint RoundFour,1:"R4b computing 2 element certificate";
 1245                 #//vprint RoundFour,5:"R4b computing ramified certificate";
 1246                 Pi := elt_with_v_star(Phihat, P, P_v_star, S, E, 1/E);
 1247                 Pi := elt_evaluate(Phi, Pi, BETA);
 1248                 Pi:=elt_invariants(Phi, traces_Phi, Pi);
 1249                 if Pi.v_star <> 1/E then
 1250                   return Error ("Factorization: Insufficient precision in computation of ramified certificate");
 1251                 fi;
 1252                 #//vprint RoundFour,5:"R4b computing unramified certificate";
 1253                 if F = 1 then
 1254                   Gamma := eltRec(Coerce(Parent(Phi),1),0);
 1255                 else
 1256                   Gamma := BETA;
 1257                 fi;
 1258                 Gamma:=elt_invariants(Phi, traces_Phi, Gamma);
 1259                 #//print "F",F;
 1260                 if Gamma.f <> F then
 1261                   return Error ("Factorization: Insufficient precision in computation of unramified certificate");
 1262                 fi;
 1263                 return [rec(factor:=Phi, multiplicity:=1,F:=F, Gamma:=Gamma.elt, Gamma_denval:=Gamma.denval, E:=E, Pi:=Pi.elt,Pi_denval:=Pi.denval)];
 1264               else #// no certificates
 1265                 return [rec( factor:=Phi, multiplicity:= 1,F:=F,E:=E)];
 1266               fi;
 1267 
 1268            else #// continue in main loop
 1269                  #// increase valuation of phi, such that deg(phi)=E*F
 1270               phis := eltRec((phi.elt)^s,0); phis.v_star := s*phi.v_star;
 1271               phi := phis;
 1272               #vprint RoundFour,2:"R4b phi =",phi`elt;
 1273               #vprint RoundFour,1:"R4b deg(phi) =", Degree(phi`elt),
 1274                #                  "and v*(phi) =", phi`v_star;
 1275            fi;
 1276 	fi;
 1277 
 1278 	#/* Step c **************************************************************/
 1279         #vprint RoundFour,5:"R4c find psi with v*(psi) = v*(phi) =",phi`v_star;
 1280         poly := elt_with_v_star(Phi, P, P_v_star, S, E, phi.v_star);
 1281         psi := poly.elt * pi^-poly.denval;
 1282 
 1283         #/* Step d *************************************************************/
 1284         #vprint RoundFour,5:"R4d gamma := phi/psi";
 1285         poly_inv := elt_inverse(poly, Phihat);
 1286 
 1287         gamma := eltRec((phi.elt * poly_inv.elt) mod Phihat, poly_inv.denval-poly.denval);
 1288         gamma.elt := gamma.elt mod pi^(gamma.denval+1);
 1289         gamma:=elt_invariants(Phihat, traces_Phihat, gamma);
 1290 
 1291         if gamma.v_star <> 0 then
 1292           #//print vstar_phi,old_vstar_phi;
 1293           return Error ("Factorization: Insufficient precision in Round Four main loop");
 1294         fi;
 1295 
 1296         #/* Step e *************************************************************/
 1297 	if gamma.passes_hensel_test=FALSE then
 1298 	    #vprint RoundFour,1:"R4e gamma fails Hensel test -- factoring";
 1299             theta := elt_evaluate_trans(Phi,traces_Phi,gamma,BETA);
 1300 	    return further_factorization(hensel_lift_factorization_chi2
 1301                                          (Phi, theta), with_certificates);
 1302         #else
 1303            #Print ("RoundFour,4:R4e gamma passes Hensel test");
 1304 	fi;
 1305 
 1306 	#/* Step f ************************************************************/
 1307         #//vprint RoundFour,5:"R4f new inertia by gamma ?";
 1308         if F mod gamma.f <> 0 then #// increase F
 1309           #// change reference polynomial Phihat, such that
 1310           #//   F_x = LCM(F,F_gamma)
 1311           #// start the main loop again with  Step a
 1312           kappa := ff_composition_gen(Phihat, PR.1, F, gamma);
 1313           if E * LCM(F, gamma.f) = Degree(Phihat) then #// Phi is irreducible
 1314              F := LCM(F, gamma.f);
 1315              #vprint RoundFour,1:"R4f E * lcm(F,F_gamma) =",E,"*",F,"= deg(Phi) =",Degree(Phihat),
 1316               #               "  =>   Phi is irreducible";
 1317              if with_certificates then
 1318 		#vprint RoundFour,1:"R4f computing 2 element certificate";
 1319                 Pi := elt_with_v_star(Phihat, P, P_v_star, S, E, 1/E);
 1320                 Pi := elt_evaluate(Phi, Pi, BETA);
 1321                 Pi:=elt_invariants(Phi, traces_Phi, Pi);
 1322                 if Pi.v_star <> 1/E then
 1323                   return Error ("Factorization: Insufficient precision in computation of ramified certificate");
 1324                 fi;
 1325                 Gamma := elt_evaluate(Phi, kappa, BETA);
 1326                 Gamma:=elt_invariants(Phi, traces_Phi, Gamma);
 1327                 #//print "F",F;
 1328                 if Gamma.f <> F then
 1329                   return Error ("Factorization: Insufficient precision in computation of unramified certificate");
 1330                 fi;
 1331 
 1332                 return [rec(factor := Phi, multiplicity := 1,
 1333                             F:=F, Gamma := Gamma.elt, Gamma_denval := Gamma.denval,
 1334                             E:=E, Pi := Pi.elt, Pi_denval := Pi.denval)];
 1335              else
 1336                return [rec(factor := Phi, multiplicity := 1,F:=F,E:=E)];
 1337              fi;
 1338 	  #/* Step g ************************************************************/
 1339          else #// find a new reference polynomial Phihat
 1340             F := LCM(F, gamma.f);
 1341 	    #vprint RoundFour,1:"R4 increasing F from",F,"to", F, "and resetting E to 1";
 1342 #//"kappa",kappa;
 1343             beta := kappa;
 1344             #//beta`elt := beta`elt+pi^(beta`denval+1)*PR.1;
 1345             #vprint RoundFour,5:"R4g searching beta with F_beta = F =",F,
 1346              #                  "and chi_beta irreducible of Degree deg(Phi) =",Degree(Phi);
 1347             newPhi := elt_chi(Phihat, traces_Phihat, beta);
 1348             #//while not is_squarefree(newPhi) do
 1349             if Discriminant(Phihat) <> 0 then
 1350               #// we can use the discriminant for testing whether newPhi is
 1351               #// squarefree
 1352               while Discriminant(newPhi)= 0 do
 1353                 #// assure that the new reference polynomial is squarefree
 1354                 #// then it generates the same extension as Phi
 1355                 #vprint RoundFour,5:"R4g beta := beta + pi*x";
 1356                 beta.elt := beta.elt+pi^(beta.denval+1)*PR.1;
 1357                 newPhi := elt_chi(Phihat, traces_Phihat, beta);
 1358               od;
 1359             else
 1360               #// better also use the gcd for testing whether newPhi is
 1361               #// squarefree as we have a precion problem with the discriminant
 1362               #// already
 1363               while is_squarefree(newPhi)=FALSE do
 1364                 #vprint RoundFour,5:"R4g beta := beta + pi*x";
 1365                 beta.elt := beta.elt+pi^(beta.denval+1)*PR.1;
 1366                 newPhi := elt_chi(Phihat, traces_Phihat, beta);
 1367               od;
 1368             fi;
 1369 
 1370             Phihat := newPhi;
 1371             traces_Phihat := traces_from_poly(Phihat);
 1372 
 1373             #// reinitialize
 1374             E := 1;
 1375             P := [];
 1376             S := [];
 1377             P_v_star := [];
 1378             phi_old_v_star := 0;
 1379 
 1380             BETA := elt_evaluate(Phi, beta, BETA);
 1381             #vprint RoundFour,4:"R4g new inertia element beta =",BETA`elt;
 1382             #vprint RoundFour,4:"R4g with denominator pi ^",BETA`denval;
 1383 
 1384             phi := eltRec(PR.1,0);
 1385 	    phi.chi := Phihat;
 1386             phi:=elt_invariants(Phihat,traces_Phihat,phi);
 1387             if (phi.passes_newton_test and phi.passes_hensel_test) =FALSE then
 1388               #vprint RoundFour,1:"R4g Newton test or Hensel test failed -- factoring";
 1389               theta := elt_evaluate_trans(Phi,traces_Phi,phi,BETA);
 1390               return further_factorization(newton_lift_factorization_chi2
 1391                        (Phi, theta), with_certificates);
 1392             fi;
 1393 
 1394             nu := phi.nu;
 1395             phi:= eltRec(phi.nu,0);
 1396 	    phi:=elt_invariants(Phihat,traces_Phihat,phi);
 1397 	  fi;
 1398 	else
 1399           #// no increase of F
 1400           #// continue in main loop
 1401         #/* Step h *************************************************************/
 1402          # vprint RoundFour,5:
 1403           #"R4h find integral delta with chi(delta)=chi(gamma) mod (pi) and deg(delta)<F";
 1404           r_L:= res_field_rep(Phihat,traces_Phihat,nu,gamma);
 1405 	  rho_passes_hensel_test:=r_L[1];
 1406 	  delta:= r_L[2];
 1407 	  rho:= r_L[3];
 1408           if rho_passes_hensel_test=FALSE then
 1409 	    #vprint RoundFour,1:"R4h rho fails Hensel test -- factoring";
 1410             theta := elt_evaluate_trans(Phi,traces_Phi,rho,BETA);
 1411 	    return further_factorization(hensel_lift_factorization_chi2
 1412                    (Phi, theta),with_certificates);
 1413           fi;
 1414           #vprint RoundFour,3:"R4h delta =",delta;
 1415         #/* Step i *************************************************************/
 1416          # vprint RoundFour,5:"R4i phi := phi - delta * psi";
 1417 	  deltapsi := delta * psi;
 1418           #//print "deg", Degree(deltapsi);
 1419           phi_old_v_star := phi.v_star;
 1420           phi := eltRec(phi.elt-deltapsi,0);
 1421 	  phi:=elt_invariants(Phihat,traces_Phihat,phi);
 1422         fi; #// increase F
 1423     od;
 1424 end;
 1425 
 1426 
 1427 
 1428 #////////////////////////////////////////////////////////
 1429 #// auxilary functions for factorization.
 1430 
 1431 #// return true, g, dival, uni, exp such that
 1432 #// g := uni*pi^multval*f(pi^exp*x) has integral coefficients and is monic
 1433 #// g is over the quotient ring !
 1434 #// if because of insuffient precision such elements cannot be computed, return
 1435 #// false, 0, 0, required precision, exp
 1436 
 1437 #  // if f is monic and integral do nothing
 1438 #  //if IsMonic(f) and Minimum([Valuation(a) : a in Eltseq(f)]) ge 0 then
 1439 #  //
 1440 #  //return
 1441 
 1442 make_monic_and_integral := function(f)
 1443 local PK,K,overfield,R,PR,elseq,vallist,minval,divi,g,multval,PR,pi,lead,vallead,exp,expmult,gList,prec,QR,PQR,uni,SList;
 1444   PK := Parent(f);
 1445   K  := CoefficientRing(PK);
 1446   overfield := IsField(K);
 1447   if overfield then
 1448     R := IntegerRing(K);
 1449     PR := PolynomialAlgebra(R);
 1450     elseq:= ElementToSequence(f);
 1451     vallist:= [1..Length(elseq)];
 1452     Apply_(vallist,x->Valuation(elseq[x]));
 1453     minval := Minimum(vallist);
 1454     divi := UniformizingElement(K)^(minval);
 1455     g := Coerce(PR,(f/divi));
 1456     multval := -minval;
 1457   else
 1458     R := K;
 1459     PR := PK;
 1460     elseq:= ElementToSequence(f);
 1461     vallist:=[1..Length(elseq)];
 1462     Apply_(vallist,x->Valuation(elseq[x]));
 1463     minval := Minimum(vallist);
 1464     divi := UniformizingElement(K)^(minval);
 1465     g := Coerce(PR,(Div(f,divi)));
 1466     multval := -minval;
 1467   fi;
 1468   #//print g;
 1469   PR := PolynomialAlgebra(R);
 1470   pi := UniformizingElement(R);
 1471   lead := LeadingCoefficient(g);
 1472   vallead := Valuation(lead);
 1473   elseq := ElementToSequence(g);
 1474   exp := -1;
 1475   if Degree(g) > 0 then
 1476     repeat
 1477       exp :=exp+1;
 1478       expmult := Degree(g)*exp-vallead;
 1479       #//print "expmult",expmult;
 1480       vallist:= [2..Length(elseq)];
 1481       Apply_(vallist,i->Valuation(elseq[i])-exp*(i-1)+expmult);
 1482       minval:= Minimum(vallist);
 1483     until (expmult >= 0 and minval >= 0);
 1484     if vallead+expmult >= Precision(R) or exp*Degree(g) >= Precision(R) then
 1485       return [false, 0, 0, vallead+expmult+exp*Degree(g), exp];
 1486     fi;
 1487   else
 1488     exp := 0;
 1489     expmult := - vallead;
 1490   fi;
 1491   g := g * pi^expmult;
 1492   #//print "exp",exp;
 1493   #//print g;
 1494   SList:= ElementToSequence(g);
 1495   gList:=[1..(Degree(g)+1)];
 1496   Apply_(gList,i->Div(SList[i],pi^(exp*(i-1))));
 1497   #//print g;
 1498   multval := multval+expmult;
 1499   if not Is (Type(R),res^pad) and not Is (Type(R),res^ser) then
 1500      if Precision(R)=INFTY then prec:= _realPrec;
 1501      else prec:= Precision(R);
 1502      fi;
 1503      if Is(Type(R),ord^ser) or Is(Type(R),ord^pow) then
 1504         QR := Quotient(PowerSeriesRing(CoefficientRing(R)),prec);
 1505      else
 1506      QR := Quotient(R,pi^prec);
 1507      fi;
 1508   else
 1509     QR := R;
 1510   fi;
 1511   PQR:= PolynomialAlgebra(QR);
 1512   g := Coerce(PQR,g);
 1513   uni := LeadingCoefficient(g);
 1514   #//print uni;
 1515   g := Div(g,uni);
 1516   if IsMonic(g)=FALSE then return Error("g not monic"); fi;
 1517   return [true, g, uni, multval, exp];
 1518 end;
 1519 
 1520 #// make the reverse changes made to f by make_monic_and_integral to h
 1521 #// actually only the exp part, the rest goes into the scalar returned
 1522 #// with the polynomial factorization.
 1523 undo_monic_and_integral := function(f,exp,h)
 1524 local g,PK,K,pi,g;
 1525   g := h;#//*uni;
 1526 
 1527   PK := Parent(f);
 1528   K := CoefficientRing(PK);
 1529   pi := UniformizingElement(K);
 1530 
 1531   g := Coerce(PK,g);
 1532   g := Evaluate(g,pi^exp*PK.1);
 1533 
 1534   return g;
 1535 end;
 1536 
 1537 
 1538 
 1539 #/////////////////////////////////////////////////////////////////////
 1540 
 1541 #{For a polynomial f over a local ring or field return a precision at which
 1542 # the factorization of f as given by Factorization(f) will be Hensel liftable
 1543 # to the correct factorization.}
 1544 
 1545 
 1546 SuggestedPrecision:= function(f)
 1547 local max,seq,vallist,tmp_R,tmpi,mo,ok,h,uni,multval,exp,mmai_prec,PK,PR,P,valList,newloss,loss,gcd,
 1548       old_P,dh,old_gcd,pgcd,done,good,hh,val;
 1549   #// the trivial cases
 1550   if Degree(f) = 0 then
 1551     max := Maximum([2,Valuation(TrailingCoefficient(f))+1]);
 1552     return max;
 1553   elif Degree(f) = -1 then
 1554     return 1;
 1555   fi;
 1556 
 1557   #// monic and integral
 1558   seq:= ElementToSequence(f);
 1559   vallist:=[1..Length(seq)];
 1560   Apply_(vallist,x->Valuation(seq[x]));
 1561   if ((IsUnit(LeadingCoefficient(f)) and
 1562        not IsField(CoefficientRing(Parent(f)))) or
 1563       IsMonic(f)) and
 1564       Minimum(vallist) >= 0 then
 1565     #// make sure it is also squarefree
 1566     if Valuation(Discriminant(f)) <
 1567       Precision(CoefficientRing(Parent(f)))
 1568       and Precision(CoefficientRing(Parent(f))) < INFTY then
 1569       max := Maximum([2*RamificationDegree(CoefficientRing(Parent(f))),
 1570                       2*Valuation(Discriminant(f))]);
 1571       return max;
 1572     fi;
 1573   fi;
 1574   tmp_R := CoefficientRing(Parent(f));
 1575   tmpi:=UniformizingElement(tmp_R);
 1576   if Is(Type(tmp_R),ord^ser) or Is(Type(tmp_R),res^ser) then
 1577      f := Coerce(PolynomialAlgebra( Quotient(tmp_R,(2*Precision(tmp_R)))),f);
 1578   else
 1579      f := Coerce(PolynomialAlgebra( Quotient(tmp_R,tmpi^(2*Precision(tmpi)))) ,f);
 1580   fi;
 1581   mo:=make_monic_and_integral(f);
 1582   ok:= mo[1];
 1583   h:= mo[2];
 1584   uni:=mo[3];
 1585   multval:= mo[4];
 1586   exp:= mo[5];
 1587   mmai_prec := Valuation(LeadingCoefficient(f))+multval+exp*Degree(f);
 1588   if not ok then
 1589     #//print "increasing prec";
 1590     mmai_prec := multval+exp*Degree(f);
 1591     PK := PolynomialAlgebra(ChangePrecision(CoefficientRing(Parent(f)),
 1592                                          mmai_prec));
 1593     mo :=make_monic_and_integral(Coerce(PK,f));
 1594     good:= mo[1];
 1595     h:= mo[2];
 1596     uni:= mo[3];
 1597     multval:= mo[4];
 1598     exp:= mo[5];
 1599     if not good then
 1600       return Error ("I cannot suggest a precision.");
 1601     fi;
 1602   fi;
 1603 
 1604   PR := Parent(h);
 1605   P := CoefficientRing(Parent(h));
 1606 
 1607   #//print h;
 1608 
 1609    # // correct the precision for the derivative
 1610     seq := ElementToSequence(h);
 1611     valList:=[2..Length(seq)];
 1612     Apply_(valList,x->Valuation(seq[x])+Valuation(Coerce(P,(x-1))));
 1613     max := Maximum(valList);
 1614     #//print "precision increase derivative",max-Precision(P);
 1615     newloss := Maximum([max-Precision(P),0]);
 1616 #//RamificationDegree(P) eq 1 and InertiaDegree(P) eq 1 then
 1617     repeat #// loop for the valuation of the discriminant
 1618        loss := 0;
 1619        gcd := 0;
 1620        repeat
 1621          old_P := P;
 1622 	 if not Precision(P) =INFTY then
 1623          P := ChangePrecision(P,Precision(P)+(newloss));
 1624 	 fi;
 1625          #//print "precision",Precision(P);
 1626          PK := PolynomialAlgebra(ChangePrecision(CoefficientRing(Parent(f)),
 1627                                          Precision(P)));
 1628 	 mo:=make_monic_and_integral(Coerce(PK,f));
 1629          good:= mo[1];
 1630          h:= mo[2];
 1631          uni:=mo[3];
 1632          multval:= mo[4];
 1633          exp:= mo[5];
 1634          #//print "new h",h;
 1635          if not good then
 1636             return Error ("I cannot suggest a precision.");
 1637          fi;
 1638          h := Coerce(PolynomialAlgebra(P),h);
 1639          dh := Derivative(h);
 1640          old_gcd := gcd;
 1641          #//print "h",h;
 1642          #//print "dh",dh;
 1643          #vprint  RoundFour,4: "R4: gcd";
 1644 	 pgcd:=PGcd(h,dh);
 1645          gcd:= pgcd[1]; newloss := pgcd[2];
 1646          #//print "newloss",newloss;
 1647          loss := loss + newloss;
 1648          #//print "gcd",gcd, newloss;
 1649          #//print "h mod gcd",h mod gcd;
 1650          #//print "h div gcd",h div gcd;
 1651        until (old_gcd = Coerce(PolynomialAlgebra(old_P),gcd) and h mod gcd = 0);
 1652        hh := Div(h,gcd);
 1653        #//print hh;
 1654        if RamificationDegree(P) = 1 and InertiaDegree(P) = 1 then
 1655          val := Valuation(Discriminant(Coerce(PolynomialAlgebra(RationalField()),hh)),
 1656                           Prime(P));
 1657          done := val.base <> INFTY;
 1658          #//print val;
 1659        else
 1660          val := Valuation(Discriminant(Coerce(PolynomialAlgebra(P),hh)));
 1661          done := val < Precision(P);
 1662        fi;
 1663        #//print "val",2*val,loss,mmai_prec;
 1664     until done and newloss < Precision(P);
 1665     max := Maximum([2*val+loss,mmai_prec+loss,2,Precision(P)]);
 1666     return max;
 1667 end;
 1668 
 1669 #{Factorization of a polynomial f over a local ring or a local field into monic irreducible
 1670 # factors together with the appropriate scalar and certificates for the irreducibility of the
 1671 # factors if requested }
 1672 
 1673 LocalFactorization:= function(f,Certificates,IsSquarefree,Ideals,Extensions)
 1674 local with_certificates,mo,ok,h,uni,multval,exp,PQR,QR,sqrfr,is_sq_free,sq_free_part,loss,r4,res1,g,        i,hh,rem,zero,done,sequ,fa,valList,a,j,PR,R,pi,min,sca,K,PK,Kpi,cert,poly,copoly,gcd,G,C,D,Phi,        traces_Phi,Rho,U,PU,Pi,tmp_U,g2,tmp_PU,fact,T,eltseq,vallist,res2,qr,prec,un,tmpPR,tmpf;
 1675     with_certificates := Certificates or Ideals or Extensions;
 1676 
 1677     if Precision(CoefficientRing(Parent(f))) = INFTY and
 1678        Extensions then
 1679       return Error ("Factorization: 'Extensions' can only be used over finite precision rings/fields");
 1680     fi;
 1681 
 1682     #//print "Factorization",f;
 1683     mo:=make_monic_and_integral(f);
 1684     ok:= mo[1];
 1685     h:=mo[2];
 1686     uni:=mo[3];
 1687     multval:=mo[4];
 1688     exp := mo[5];
 1689     if not ok then
 1690       return Error ("Factorization: Insufficient precision");
 1691     fi;
 1692     #//print h;
 1693     PQR := Parent(h);
 1694     QR := CoefficientRing(PQR);
 1695 
 1696     sqrfr:= is_squarefree(h);
 1697     is_sq_free:= sqrfr[1];
 1698     sq_free_part:=sqrfr[2];
 1699     loss:=sqrfr[3];
 1700     if is_sq_free then
 1701      
 1702       r4 := round_four(h,with_certificates);
 1703       res1:=[1..Length(r4)];
 1704       Apply_(res1,x->Tuple([undo_monic_and_integral(f, exp, r4[x].factor),1]));
 1705     else
 1706       if loss>0 and not Is(Type(f),elt-alg^pol/ord^ser) or Is(Type(f),elt-alg^pol/res^ser) then
 1707          if Precision(QR) <>INFTY then
 1708             tmpPR:= _ChangePrecisionCoeff(PQR,Precision(QR)+loss);
 1709          else 
 1710             tmpPR:= _ChangePrecisionCoeff(PQR,_realPrec+loss);
 1711          fi;
 1712          tmpf:= Coerce(tmpPR,f);
 1713          h:= make_monic_and_integral(tmpf)[2];
 1714          sqrfr:= is_squarefree(h);
 1715          sq_free_part:=sqrfr[2];
 1716       fi;
 1717       g := sq_free_part;
 1718       fa:= 1;
 1719 #//"h",h;
 1720 #//"g",g;
 1721       while IsMonic(g)=false do
 1722          # Print("no mo\n");
 1723          #mo:= make_monic_and_integral(g)[2];
 1724          fa:= fa*LeadingCoefficient(g);
 1725          mo := g*(IsInvertible(LeadingCoefficient(g)).ext1);
 1726          g:= is_squarefree(mo)[2];
 1727       od;
 1728       r4 := round_four(g,with_certificates);
 1729       if loss>0 and not Is(Type(f),elt-alg^pol/ord^ser) or Is(Type(f),elt-alg^pol/res^ser) then
 1730          for i in [1..Length(r4)[1]] do
 1731              if Precision(QR)<>INFTY then
 1732                 r4[1][i].factor:= Coerce(PQR,r4[1][i].factor);
 1733              else tmpPR:= _ChangePrecisionCoeff(PQR,_realPrec);
 1734                 r4[1][i].factor:= Coerce(tmpPR,r4[1][i].factor);
 1735                 r4[1][i].factor:= Coerce(PQR,r4[1][i].factor);
 1736              fi;
 1737          od;
 1738       fi;
 1739       res1:=[1..Length(r4)];
 1740       Apply_(res1,x->Tuple([r4[x].factor,0]));
 1741       #//hh := h;
 1742       for i in[1..Length(res1)] do
 1743         hh := h;
 1744         repeat
 1745           #//print "hh pre",hh;
 1746           hh := Div(hh,res1[i][1]);
 1747           rem := hh mod res1[i][1];
 1748 #Print(" = hh mod res ",rem,"\n");
 1749           res1[i][2] := res1[i][2]+1;
 1750           #//print "hh post",hh;
 1751           zero := (rem = Coerce(Parent(rem),0));
 1752           done := false;
 1753           if not zero then
 1754 	    sequ:= ElementToSequence(rem);
 1755 	    valList:=[1..Length(sequ)];
 1756 	    Apply_(valList,x->Valuation(sequ[x]));
 1757             done := Minimum(valList) < Precision(QR)-loss;
 1758           fi;
 1759         until done;
 1760       od;
 1761       #//print res;
 1762 #//print "exp sum", &+[a[2]*Degree(a[1]) : a in res],"=?=",Degree(f);
 1763  #     //print res;
 1764        a:= res1[1][2]*Degree(res1[1][1]);
 1765        for j in [2..Length(res1)] do
 1766            a:= a+res1[j][2]*Degree(res1[j][1]);
 1767        od;
 1768       if a<> Degree(f) then
 1769         Print("a=",a);
 1770 #//"res",res;
 1771 #//"f",f;
 1772  return Error ("Factorization: Insufficient precision in factorization of a non-squarefree polynomial.");
 1773       fi;
 1774       res2:= [1..Length(res1)];
 1775       Apply_(res2,x->Tuple([undo_monic_and_integral(f, exp, res1[x][1]), res1[x][2]]));
 1776       res1:= res2;
 1777     #//print res;
 1778     fi; #// squarefee by gcd
 1779 #//  end if;  // is_squarefree_easy
 1780 
 1781     PR := Parent(f);
 1782     R := CoefficientRing(PR);
 1783     pi := UniformizingElement(R);
 1784     if not IsField(R) then  #// distribute the scalar factor 1/pi^multval
 1785       for i in [1..Length(res1)] do #// over the factors
 1786         eltseq:= ElementToSequence(res1[i][1]);
 1787 	vallist:=[1..Length(eltseq)];
 1788 	Apply_(vallist,x->Valuation(eltseq[x]));
 1789         min :=  Minimum(vallist);
 1790         res1[i][1]:=Div( res1[i][1],pi^min);
 1791         multval := multval -res1[i][2]*min;
 1792       od;
 1793       if multval > 0 then
 1794         return Error ("Factorization: Something went wrong when trying to factor a non-monic Polynomial.");
 1795       fi;
 1796     fi;
 1797     sca := Coerce(R,uni) * pi^(-multval);
 1798 
 1799    # //==========================================
 1800     if with_certificates then
 1801    #   CERT := recformat<F:IntegerRing(),   // inertia deg
 1802    #                     Rho:RngUPolElt, // unramified certificate
 1803    #                     E:IntegerRing(),   // ram index
 1804    #                     Pi:RngUPolElt,  // ramified certificate
 1805    #                     IdealGen1,      // 2 element representation of
 1806    #                     IdealGen2:RngUPolElt,// the corresponding global ideal
 1807    #                     Extension>;     // extension of R given by the
 1808                                     #    // factor
 1809       if not IsField(R) then
 1810         #if Is(Type(R),res^pad) then
 1811 	   #K:= pAdicField(Coerce(Z,UniformizingElement(R)),Precision(R));
 1812 	#else
 1813            K := FieldOfFractions(R);
 1814 	#fi;
 1815         PK := PolynomialAlgebra(K);
 1816       else
 1817         K := R;
 1818         PK := PR;
 1819       fi;
 1820 
 1821 
 1822       Kpi := UniformizingElement(K);
 1823       cert:=[1..Length(r4)];
 1824       Apply_(cert,x->rec(F:= r4[x].F, Rho:=Coerce(PK,((r4[x].Gamma))/Kpi^r4[x].Gamma_denval),
 1825                          E:=r4[x].E,  Pi:=Coerce(PK,Coerce(PK,r4[x].Pi)/Kpi^r4[x].Pi_denval)));
 1826 
 1827       #//-----------------------------------------
 1828       if Ideals then
 1829         for i in [1..Length(res1)] do
 1830           cert[i].IdealGen1 := pi;
 1831           poly := Coerce(PK,res1[i][1]);
 1832           copoly := 1;
 1833           for j in [1..Length(res1)] do
 1834             if j <> i then
 1835               copoly := copoly *Coerce(PK,res1[j][1]);
 1836             fi;
 1837           od;
 1838 	  gcd:=XGCD(poly,copoly);
 1839           G := gcd.base;
 1840 	  C:= gcd.ext1;
 1841 	  D:= gcd.ext2;
 1842           cert[i].IdealGen2 := cert[i].Pi*D*copoly+poly*C;
 1843         od;
 1844       fi;
 1845       #//-----------------------------------------
 1846       if Extensions then
 1847         #vprint RoundFour,1:" -- computing local extensions";
 1848         for i in [1..Length(res1)] do
 1849             Phi := r4[i].factor;
 1850             #//print "Phi",Phi;
 1851             traces_Phi := traces_from_poly(Phi);
 1852             if cert[i].F > 1 then
 1853               Rho := eltRec(r4[i].Gamma, r4[i].Gamma_denval);
 1854               Rho:=elt_invariants(Phi, traces_Phi, Rho);
 1855              # //print "Gamma",r4[i]`Gamma, r4[i]`Gamma_denval;
 1856              # //print "chi_Rho",chi_Rho;
 1857               if not Rho.passes_hensel_test then
 1858                return Error ("Factorization: something went wrong with the unramified certificate");
 1859               fi;
 1860               if Rho.f <> cert[i].F then return Error("Error in Extensions");fi;
 1861               U := UnramifiedExtension(R,Rho.nu);
 1862             else
 1863               U := R;
 1864             fi;
 1865             if cert[i].E > 1 then
 1866               Pi := eltRec(r4[i].Pi, r4[i].Pi_denval);
 1867               Pi:=elt_invariants(Phi, traces_Phi, Pi);
 1868               PU := PolynomialAlgebra(U);
 1869               #// unfortunately the precison used to factor f must noty be
 1870               #// sufficient for factoring chi_Pi
 1871               tmp_U := U;
 1872               #//tmp_U := ChangePrecision(U,
 1873               #//    Maximum([2*Valuation(Discriminant(chi_Pi)),Precision(R)]));
 1874               tmp_PU := PolynomialAlgebra(tmp_U);
 1875               #//vtime RoundFour,4:
 1876               fact := LocalFactorization(Coerce(tmp_PU,(Coerce(PU,(Coerce(PR,Pi.chi))))),false,false,false,false);
 1877               #//"fact4",fact;
 1878 	      if Degree(fact[1][1][1]) <> Div(Degree(Phi),cert[i].F) then
 1879 	         return Error("Degree");
 1880 	      fi;
 1881               if (2*Valuation(Discriminant(fact[1][1][1]))+cert[i].E)/cert[i].E
 1882                  > Precision(U) then
 1883                   return Error ("Factorization: The Precision was not high enough",
 1884                        "to assure that the ramified extension is unique");
 1885               fi;
 1886               T := TotallyRamifiedExtension(U,Coerce(PU,fact[1][1][1]));
 1887             else
 1888               T := U;
 1889             fi;
 1890             cert[i].Extension := T;
 1891         od;
 1892       fi;
 1893       return [res1,sca, cert];
 1894     #//===========================================
 1895     else
 1896       return [res1,sca];
 1897     fi;
 1898 end;
 1899 
 1900 
 1901 
 1902 #{True iff f is irreducible}
 1903 IsIrreducible:= function(f)
 1904 local F;
 1905     F := Factorization(f);
 1906     return Length(F) = 1;
 1907 end;
 1908 
 1909 
 1910 #{Factorization of a polynomial f over a local ring or a local field into monic irreducible
 1911 # factors together with the appropriate scalar and certifcates for the irreducibility of the
 1912 # factors if requested }
 1913 
 1914 #Factorization:= function(f,Certificates,IsSquarefree,Ideals,Extensions)
 1915 #    return LocalFactorization(
 1916 #	f ,Certificates, IsSquarefree ,Ideals,Extensions);
 1917 #end;
 1918 
 1919 InstallMethod(
 1920 rec(
 1921 name := "Factorization",
 1922 kind := "FUNCTION",
 1923 sin := [[elt-alg^pol/any^loc,"Phi"]],
 1924 sou := [[list]],
 1925 opt := [[elt-alg^boo,"Certificates",
 1926          "If TRUE two element certificates for the irreducibilty of factors are returned.", rec(Default:=FALSE)],
 1927         [elt-alg^boo,"IsSquarefree",
 1928          "If TRUE the polynomial is assumed to be squarefree",rec(Default:=FALSE)],
 1929         [elt-alg^boo,"Ideals","",rec(Default:=FALSE)],
 1930         [elt-alg^boo,"Extensions",
 1931          "If TRUE the extensions generated by the irreducible factors are returned",
 1932 	 rec(Default:=FALSE)]],
 1933 short := "The factorization of a polynomial over a p-adic field or a "+
 1934 " p-adic ring.  The algorithm used is a combinantion of the algorithms by "+
 1935 "Ford-Pauli-Roblot and by Pauli."
 1936 ),
 1937 function(arg)
 1938   local opt;
 1939 #Print("arg",arg,"\n");
 1940   opt := Optarg(arg,
 1941                 ["Certificates", "IsSquarefree", "Ideals", "Extensions"],
 1942                 [FALSE,FALSE,FALSE,FALSE]);
 1943    
 1944 #Print("opt",opt,"\n");
 1945 #Print("call",arg[1],opt.Certificates, 
 1946 #                              opt.IsSquarefree, 
 1947 #                              opt.Ideals,
 1948 #                              opt.Extensions,"\n");
 1949   return LocalFactorization(arg[1],opt.("Certificates"), 
 1950                               opt.("IsSquarefree"), 
 1951                               opt.("Ideals"),
 1952                               opt.("Extensions"));
 1953 #  return LocalFactorization(arg[1],TRUE,FALSE,FALSE,FALSE);
 1954 end
 1955 );
 1956 
 1957 #q3 := pAdicRing(3,30);
 1958 #q3x := PolynomialRing(q3);
 1959 #f := (q3x.1^3+3)*(q3x.1^3+6);
 1960 #LocalFactorization(f,FALSE,FALSE,FALSE,FALSE);
 1961 #ReadLib("locFact");
 1962 #Factorization(f);
 1963 #q3 := pAdicRing(3,30);
 1964 #q3x := PolynomialRing(q3);
 1965