module pfacmult; % multivariate modular factorization.

% Author: Herbert Melenk.

% Reduction of multivariate modular factorization to univariate 
% factorization by Kroneckers map.
% See Kaltofen: Factorization of Polynomials, in: Buchberger,
% Collins, Loos: Computer Algebra, Springer, 1982.

% This module should be removed as soon as a multivariate modular 
% factorizer based on Hensel lifting has been written.

fluid '(!*trfac);

symbolic procedure fctrfkronm f;
  begin scalar sub,tra,k,x,xx,x0,y,z,r,q,f0,fl,fs,dmode!*;
       integer d,d0;
    k:=kernels f;
    dmode!*:='!:mod!:;
    for each z in decomposedegr(f,for each x in k collect (x. 0))
         do if cdr z >d then d:=cdr z;
    d:=d+1; d0:=d; x0:=car k;
    for each x in cdr k do
    <<sub:=(x . {'expt,x0,d0}).sub; tra:=(x.d0).tra; d0:=d0*d>>; 
    fs:=numr subf(f,sub);
    if !*trfac then
     <<writepri("Kronecker mapped form:",'first); 
       writepri(mkquote prepf fs,'last)>>;
    fl:=decomposefctrf fs;
    if null cdr fl then return {1,f.1};
    f0:=numr resimp (f ./ 1);
    for each fc in fl do if not domainp f0 then
    <<y:=fctrfmk1(fc,tra);
      y:=numr resimp(y ./ 1);
      x := fctrfmk3 y;
      if x then y:= quotf(y, x);
      if !*trfac then
      <<writepri("test next candidate ",'first); 
	writepri(mkquote prepf y,'last)>>;
     if (q:=quotf(f0,y)) then 
        <<f0:=q; if(z:=assoc(y,r)) then cdr z:=cdr z+1 
		   else r:=(y. 1).r>>>>;
    if null r then return {1,f. 1};
    if domainp f0 then return (f0 .r);
    if !*trfac then
    <<writepri("descend in recursion with",'only);
      writepri(mkquote prepf f0, 'only)>>;
    fl := fctrfkronm f0;
    if !*trfac then
    <<writepri("return from recursion; numeric factor ",'first);
      writepri(mkquote prepf car fl, 'last);
      for each fc in cdr fl do
      <<writepri("polynomial factor: ",'first); 
        writepri(mkquote prepf car fc, nil);
        writepri(" multiplicity ", nil);
        writepri(mkquote prepf cdr fc, 'last)>> >>;
    x := car fl; xx := cdr fl;
    if null cdr xx and cdar xx = 1 and fctrfmk4 x then
    <<y := fctrfmk3 car xx;
      if y then
      <<x := y;
        xx := list(quotf(caar xx, x) . 1);
        if !*trfac then
        <<writepri("number correction; numeric factor ",'first);
          writepri(mkquote x,'last);
          writepri("polynomial factor ",'first);
          writepri(mkquote prepf caar xx,'last)>> >> >>;
    for each fc in xx do
    <<y:=numr resimp(car fc ./ 1);
      if !*trfac then
      <<writepri("next division: ",'first);
        writepri(mkquote prepf y,'last)>>;
        f0:=quotf(f0,y);
        if(z:=assoc(y,r)) then cdr z:=cdr z+cdr fc
                   else r:=(y. cdr fc).r>>;
    x := quotf(x, f0);
    return x . r
  end;

symbolic procedure fctrfmk1(f,tra);
  % Kronecker backtransform.
   if domainp f then f else 
      addf(multf(lc f,fctrfmk2(mvar f,ldeg f,tra)),fctrfmk1(red f,tra));

symbolic procedure fctrfmk2(x,n,tra);
  if n=0 then 1 else
  if null tra then x.**n .* 1 .+ nil else
  if n>=cdar tra then multf(caar tra .** (n/cdar tra) .* 1 .+nil,
            fctrfmk2(x,remainder(n,cdar tra),cdr tra)) 
   else fctrfmk2(x,n,cdr tra);

symbolic procedure fctrfmk3 f;
% Extract the leading coefficient.
  if domainp f then (if fctrfmk4 f then nil else f) else fctrfmk3 lc f;

symbolic procedure fctrfmk4 u;
% Test u=1 in modular mode;
    numberp u and u = 1 or
      not atom u and car u = '!:mod!: and modonep!: u;

endmodule;

end;
