123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- module decompos; % Decomposition of polynomials f(x) = g(h(x)).
- % Author: Herbert Melenk <melenk@sc.zib-berlin.de>.
- % Algorithms: 1. univariate case:
- % V.S. Alagar, M.Tanh: Fast Polynomial Decomposition
- % Algorithms, EUROCAL 1985, pp 150-153 (Springer).
- %
- % 2. multivariate lifting:
- % J. von zur Gathen: Functional Decomposition of Polynomials:
- % the Tame Case, J. Symbolic Computation (1990) 9, 281-299.
- % Copyright (c) 1990 ZIB.
- %
- % 1-July-93 Replaced gensym calls by local name generator.
- % Otherwise decompose may produce different results
- % for identical input.
- % 29-Apr.-93: completed normalization of multivariate results:
- % shifting sign and content (field: leading coefficient)
- % and absolute term to the 1st form.
- global '(decomposegensym!*);
- put('decompose,'psopfn,'decomposesf);
- symbolic procedure decomposesf f;
- 'list . reverse decomposef2(simp reval car f,t)
- where !*factor=nil,!*exp=t;
- symbolic procedure decomposef1(f,msg);
- decomposef2(f ./ 1 ,msg);
- symbolic procedure decomposef2(f,msg);
- begin scalar hvars,r,rr,x,y,u,vars,newvars,d;
- decomposegensym!*:=1000;
- vars := decomposesfvars(numr f,nil);
- newvars := for each x in vars collect decomposegensym();
- d := denr f;
- if not domainp d
- then rerror(poly,18,typerr(prepsq f,"polynomial"));
- f := numr subf(numr f,pair(vars,newvars));
- if length vars = 1 then r := decomposesfuni0 f
- else r := decomposesfmulti(f,newvars);
- hvars := '(u v w a b c d e);
- for each x in vars do hvars := delete (x,hvars);
- while r do
- <<if cdr r
- then <<y := x; x := nil;
- while null x do
- if hvars then <<x := car hvars; hvars := cdr hvars;
- if not(x=reval x) then x := nil>>
- else x:=decomposegensym();
- u := prepsq subsq(car r,list(mvar numr car r . x));
- if d neq 1 then<<u:=list('QUOTIENT,u,prepf d);d:=1>>;
- rr := (if y then list('EQUAL,y,u) else u) . rr>>
- else <<u := prepsq car r;
- y := x;
- rr := (if y then list('EQUAL,y,u) else u) . rr>>;
- r := cdr r>>;
- rr := subla(pair(newvars,vars),car rr) . cdr rr;
- return rr
- end;
- symbolic procedure decomposesfvars(f,v);
- % Select the kernels from a standard form.
- if domainp f then v else
- decomposesfvars(red f,
- decomposesfvars(lc f,
- if not member(mvar f,v)
- then append(v,list mvar f) else v));
- symbolic procedure decomposesfuni0 f;
- for each p in decomposesfuni f collect (p ./ 1);
- symbolic procedure decomposesfuni f;
- % Univariate variant.
- begin scalar x,y,res,ddfl,h,testf;
- integer n;
- n := ldeg f;
- if primep n then return list f;
- x := mvar f; y := decomposegensym();
- ddfl := decomposefctrf decomposedf(f,x);
- if length ddfl > 1 then
- for each d in ddfl do
- if null res and 0=remainder(n , (ldeg d + 1)) then
- <<h := numr decomposeint(d,x);
- if null testf then
- testf := addf(f,negf numr subf(f,list(x . y)));
- if quotf (testf,
- addf(h,negf numr subf(h,list(x . y)))) then
- res := list(decomposebacksubstuni(f,h,x),h);
- if res and ldeg car res<2 then res:=nil;
- >>;
- if null res then return list f else
- return for each u in res join decomposesfuni u
- end;
- symbolic procedure decomposefctrf f;
- % Generate all factors of f by combining the prime factors.
- begin scalar u,w,q;
- q := fctrf f; u:= cdr q;
- if length u = 1 and cdar u=1 then return list f;
- % eliminate the two trivial factors.
- w := delete(quotf(f,car q),decomposefctrf1 u);
- w := delete(1,w);
- return w;
- end;
-
- symbolic procedure decomposefctrf1 v;
- % Collect all possible crossproducts from v.
- if null v then '(1) else
- begin scalar r,c,q;
- c:=car v;
- r:=decomposefctrf1 cdr v;
- q:=for i:=1:cdr c collect exptf(car c,i);
- return
- append(r,
- for each u in q join
- for each p in r collect
- multf(u,p) );
- end;
- symbolic procedure decomposebacksubstuni(f,h,x);
- begin scalar c,g,n,p,pars,ansatz,eqs;
- p := 1; n := ldeg f/ldeg h;
- for i:=0:n do
- <<c := mkid('coeff,i);
- pars := c . pars;
- ansatz := addf(multf(numr simp c,p) , ansatz);
- p := multf(p,h);
- >>;
- pars := reverse pars;
- ansatz := addf(f , negf ansatz);
- eqs := decomposecoeff(ansatz,list x);
- eqs := solveeval list('list . for each u in eqs collect prepf u,
- 'list . pars);
- eqs := cdr cadr eqs; % select the only solution.
- for i:= 0:n do
- g := addf(g,numr simp list('times,list('expt,x,i),
- caddr nth(eqs,i+1)));
- return g
- end;
- symbolic procedure decomposedf(f,x);
- % Differentiate a polynomial wrt top-level variable x.
- % Returns a standard form.
- if domainp f or not(mvar f = x) then nil else
- if ldeg f = 1 then lc f else
- mvar f .** (ldeg f - 1) .* multf(lc f,ldeg f)
- .+ decomposedf(red f,x);
- symbolic procedure decomposeint(f,x);
- % Integrate a polynomial (standard form) wrt the (main-)variable x.
- % Returns a standard quotient.
- if null f then nil ./ 1 else
- if domainp f then (x .** 1 .* f .+ nil) ./ 1 else
- addsq(multsq((x .** (ldeg f + 1) .* 1 .+ nil)./ 1 ,
- multsq(lc f./1,1 ./ldeg f+1))
- , decomposeint(red f,x));
- symbolic procedure decomposecoeff(f,vars);
- % Select the coefficients of f wrt vars.
- begin scalar o;
- o := setkorder vars;
- f := reorder f;
- setkorder o;
- return decomposecoeff1(f,vars)
- end;
- symbolic procedure decomposecoeff1(f,vars);
- if domainp f then nil else
- if not member(mvar f,vars) then list f else
- nconc(decomposecoeff1(lc f,vars),decomposecoeff1(red f,vars));
- symbolic procedure decomposetdg f;
- % calculate total degree
- if domainp f then 0 else
- max(ldeg f + decomposetdg lc f, decomposetdg red f);
- symbolic procedure decomposedegr(f,vl);
- if domainp f then vl else
- <<if ldeg f > cdr v then cdr v := ldeg f;
- decomposedegr(lc f,vl);
- decomposedegr(red f,vl);
- vl>> where v = assoc(mvar f,vl);
-
- symbolic procedure compose (u,v);
- % Calculate f(x)=u(v(x)) for standard forms u,v.
- if domainp u then u else
- numr subf(u,list(mvar u . prepf v));
- % Multivariate polynomial decomposition.
- %
- % Technique:
- % select a field as domain (rational),
- % map f to a strongly monic polynomial by variable transform,
- % map f to a univariate image,
- % decompose the univariate polynomial,
- % lift decomposition to multivariate,
- % convert back to original variables,
- % transform back to original domain (if possible).
- symbolic procedure decomposesfmulti(f,vars);
- % Multivariant case: map to field (rationals).
- begin scalar dm,ft,r,rr,a,q,c,p1,p2;
- if null dmode!* or not flagp(dmode!*,'field) then
- <<setdmode('rational,t) where !*msg=nil; dm := t;
- ft := !*q2f resimp !*f2q f>> else ft := f;
- r := decomposesfmulti1(ft,vars);
- if dm then setdmode('rational,nil) where !*msg=nil;
- if null cdr r then return list(f./1);
- % if null dm then return
- % for each p in r collect (p ./ 1);
- % Convert back to integer polynomials.
- rr := for each p in reverse r collect simp prepf p;
- r := nil;
- while rr and cdr rr do
- <<p1 := car rr; p2 := cadr rr;
- % Propagate absolute term and content from p1 to p2.
- q := denr p1; a := numr p1;
- while not domainp a do a := red a;
- p1 := addf(numr p1,negf a);
- c := decomposenormfac p1;
- p1 := multsq(p1 ./ 1, 1 ./ c);
- p2 := subsq(p2,list(mvar numr p2 .
- list('quotient,
- list('plus,list('times,decomposegensym(),prepf c),
- prepf a),
- prepf q)));
- r := p1 . r; rr := p2 . cddr rr>>;
- return car rr . r;
- end;
-
- symbolic procedure decomposesfmulti1(f,vars);
- % Multivariate case: map to strongly monic polynomial.
- begin scalar lvars,ft,rt,x1,a0,kord,u,sigma;
- integer n,m;
- % get the variable with highest degree as main variable.
- u := decomposedegr(f,for each x in vars collect (x. 0));
- n := -1;
- for each x in u do
- if n<cdr x then <<n:=cdr x; x1 := car x>>;
- if n<2 then return list f;
- vars := x1 . delete(x1,vars);
- kord := setkorder vars;
- f := reorder f;
- % Convert f to a strongly monic polynomial.
- n := decomposetdg f;
- x1 := car vars;
- lvars := for each x in cdr vars collect (x . decomposegensym());
- again:
- if m>10 then << rt := list f; goto ret>>;
- % construct transformation sigma
- sigma := for each x in lvars collect x . random 1000;
- ft := numr subf(f,for each x in sigma collect
- (caar x . list('plus,cdar x,list('times,x1,cdr x))));
- if not domainp lc ft then <<m:=m+1; goto again>>;
- a0 := lc ft; ft := quotf(ft,a0);
- rt := decomposesfmnorm(ft,n,sublis(lvars,vars));
- if cdr rt then
- % Transform result back.
- <<rt := reverse rt;
- rt := numr subf(car rt,for each x in sigma collect
- (cdar x . list('difference,caar x,list('times,cdr x,x1))))
- . multf(a0,cadr rt) . cddr rt;
- >> else rt := list f;
- ret:
- setkorder kord;
- rt := for each p in rt collect reorder p;
- % try further decomposition of central polynomial.
- return if cdr rt and decomposetdg car rt>1 then
- append(reverse cdr rt,decomposesfmulti1(car rt,vars))
- else reverse rt;
- end;
- symbolic procedure decomposelmon f;
- % Extract the variables of the leading monomial.
- if domainp f then nil else
- mvar f . decomposelmon lc f;
-
- symbolic procedure decomposenormfac p1;
- if null dmode!* or not flagp(dmode!*,'field) then
- multf(numr mkabsfd decomposecont p1,decomposesign p1)
- else <<while not domainp p1 do p1:=lc p1; p1>>;
- symbolic procedure decomposecont f;
- % Calculate the content of f if the domain is a ring.
- if domainp f then f else
- gcdf(decomposecont lc f, decomposecont red f);
- symbolic procedure decomposesign f;
- % Compute a unit factor c such that the leading coefficient of
- % f/c is a positive integer.
- if domainp f then numr quotsq(f ./ 1,mkabsfd f)
- else decomposesign lc f;
- symbolic procedure decomposesfmnorm(f,n,vars);
- % Multivariate case: map strongly monic polynomial to univariate
- % and lift result.
- begin scalar x,x1,f0,g,u,abort,h,k,tt,q,v;
- integer r,s;
- x1 := car vars;
- % Step 1.
- f0 := numr subf(f,for each y in cdr vars collect (y . 0));
- u := decomposesfuni f0;
- % For multivariate we accept degree=1 polynomials as nontrivial
- % but inhibit recursion.
- if null cdr u then <<u:=append(u,list !*k2f x1)>>;
- x := decomposegensym();
- g := numr subf(car u,list (x1 . x));
- r := ldeg g;
- h := cadr u; u := cddr u;
- while u do
- <<v := car u; u:= cdr u; h := numr subf(h,list(x1 . x));
- h := compose(h,v); >>;
- % Step 2.
- s := divide(n,r);
- if not(cdr s=0) then goto fail else s := car s;
- k := h;
- tt := compose(decomposedf(g,x),h);
- % Step 3: Hensel lifting in degree steps.
- for i:=1:s do
- if not abort then
- % Step 4: loop step.
- <<u := decomposehomog(addf(f,negf compose(g,k)),x1,i);
- q := quotf(u,tt);
- if u and null q then abort:=t else<<h:=q; k:=addf(k,h)>>
- >>;
- if abort then goto fail;
- % Step 5: test result and loop for lower part.
- h := k;
- if f = compose(g,h) then return list(g,h);
- fail: % Exit: no decomposition found.
- return list f;
- end;
-
- symbolic procedure decomposehomog(f,x,d);
- % F is a polynomial (standard form) in x and some other
- % variables. Select that part of f, where the coefficients
- % of x are monomials in total degree d.
- % Result is the sum (standard form) of these monomials.
- begin scalar u,v;
- u := decomposehomog1(f,x,d);
- for each m in u do v := addf(v,m);
- return v;
- end;
-
- symbolic procedure decomposehomog1(f,x,d);
- % Select the monomials.
- if d<0 or null f then nil else
- if domainp f then (if d=0 then list f else nil)
- else begin scalar u1,u2;
- u1:= decomposehomog1(lc f,x,if mvar f = x then d
- else d-ldeg f);
- u2:= decomposehomog1(red f,x,d);
- return
- nconc(
- for each v in u1 collect
- multf(mvar f .** ldeg f .*1 .+ nil , v),
- u2);
- end;
- symbolic procedure decomposegensym();
- compress(append('(!! !D !! !c !! !.),
- explode2(decomposegensym!*:=decomposegensym!*+1)));
- endmodule;
- end;
|