decompos.red 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. module decompos; % Decomposition of polynomials f(x) = g(h(x)).
  2. % Author: Herbert Melenk <melenk@sc.zib-berlin.de>.
  3. % Algorithms: 1. univariate case:
  4. % V.S. Alagar, M.Tanh: Fast Polynomial Decomposition
  5. % Algorithms, EUROCAL 1985, pp 150-153 (Springer).
  6. %
  7. % 2. multivariate lifting:
  8. % J. von zur Gathen: Functional Decomposition of Polynomials:
  9. % the Tame Case, J. Symbolic Computation (1990) 9, 281-299.
  10. % Copyright (c) 1990 ZIB.
  11. %
  12. % 1-July-93 Replaced gensym calls by local name generator.
  13. % Otherwise decompose may produce different results
  14. % for identical input.
  15. % 29-Apr.-93: completed normalization of multivariate results:
  16. % shifting sign and content (field: leading coefficient)
  17. % and absolute term to the 1st form.
  18. global '(decomposegensym!*);
  19. put('decompose,'psopfn,'decomposesf);
  20. symbolic procedure decomposesf f;
  21. 'list . reverse decomposef2(simp reval car f,t)
  22. where !*factor=nil,!*exp=t;
  23. symbolic procedure decomposef1(f,msg);
  24. decomposef2(f ./ 1 ,msg);
  25. symbolic procedure decomposef2(f,msg);
  26. begin scalar hvars,r,rr,x,y,u,vars,newvars,d;
  27. decomposegensym!*:=1000;
  28. vars := decomposesfvars(numr f,nil);
  29. newvars := for each x in vars collect decomposegensym();
  30. d := denr f;
  31. if not domainp d
  32. then rerror(poly,18,typerr(prepsq f,"polynomial"));
  33. f := numr subf(numr f,pair(vars,newvars));
  34. if length vars = 1 then r := decomposesfuni0 f
  35. else r := decomposesfmulti(f,newvars);
  36. hvars := '(u v w a b c d e);
  37. for each x in vars do hvars := delete (x,hvars);
  38. while r do
  39. <<if cdr r
  40. then <<y := x; x := nil;
  41. while null x do
  42. if hvars then <<x := car hvars; hvars := cdr hvars;
  43. if not(x=reval x) then x := nil>>
  44. else x:=decomposegensym();
  45. u := prepsq subsq(car r,list(mvar numr car r . x));
  46. if d neq 1 then<<u:=list('QUOTIENT,u,prepf d);d:=1>>;
  47. rr := (if y then list('EQUAL,y,u) else u) . rr>>
  48. else <<u := prepsq car r;
  49. y := x;
  50. rr := (if y then list('EQUAL,y,u) else u) . rr>>;
  51. r := cdr r>>;
  52. rr := subla(pair(newvars,vars),car rr) . cdr rr;
  53. return rr
  54. end;
  55. symbolic procedure decomposesfvars(f,v);
  56. % Select the kernels from a standard form.
  57. if domainp f then v else
  58. decomposesfvars(red f,
  59. decomposesfvars(lc f,
  60. if not member(mvar f,v)
  61. then append(v,list mvar f) else v));
  62. symbolic procedure decomposesfuni0 f;
  63. for each p in decomposesfuni f collect (p ./ 1);
  64. symbolic procedure decomposesfuni f;
  65. % Univariate variant.
  66. begin scalar x,y,res,ddfl,h,testf;
  67. integer n;
  68. n := ldeg f;
  69. if primep n then return list f;
  70. x := mvar f; y := decomposegensym();
  71. ddfl := decomposefctrf decomposedf(f,x);
  72. if length ddfl > 1 then
  73. for each d in ddfl do
  74. if null res and 0=remainder(n , (ldeg d + 1)) then
  75. <<h := numr decomposeint(d,x);
  76. if null testf then
  77. testf := addf(f,negf numr subf(f,list(x . y)));
  78. if quotf (testf,
  79. addf(h,negf numr subf(h,list(x . y)))) then
  80. res := list(decomposebacksubstuni(f,h,x),h);
  81. if res and ldeg car res<2 then res:=nil;
  82. >>;
  83. if null res then return list f else
  84. return for each u in res join decomposesfuni u
  85. end;
  86. symbolic procedure decomposefctrf f;
  87. % Generate all factors of f by combining the prime factors.
  88. begin scalar u,w,q;
  89. q := fctrf f; u:= cdr q;
  90. if length u = 1 and cdar u=1 then return list f;
  91. % eliminate the two trivial factors.
  92. w := delete(quotf(f,car q),decomposefctrf1 u);
  93. w := delete(1,w);
  94. return w;
  95. end;
  96. symbolic procedure decomposefctrf1 v;
  97. % Collect all possible crossproducts from v.
  98. if null v then '(1) else
  99. begin scalar r,c,q;
  100. c:=car v;
  101. r:=decomposefctrf1 cdr v;
  102. q:=for i:=1:cdr c collect exptf(car c,i);
  103. return
  104. append(r,
  105. for each u in q join
  106. for each p in r collect
  107. multf(u,p) );
  108. end;
  109. symbolic procedure decomposebacksubstuni(f,h,x);
  110. begin scalar c,g,n,p,pars,ansatz,eqs;
  111. p := 1; n := ldeg f/ldeg h;
  112. for i:=0:n do
  113. <<c := mkid('coeff,i);
  114. pars := c . pars;
  115. ansatz := addf(multf(numr simp c,p) , ansatz);
  116. p := multf(p,h);
  117. >>;
  118. pars := reverse pars;
  119. ansatz := addf(f , negf ansatz);
  120. eqs := decomposecoeff(ansatz,list x);
  121. eqs := solveeval list('list . for each u in eqs collect prepf u,
  122. 'list . pars);
  123. eqs := cdr cadr eqs; % select the only solution.
  124. for i:= 0:n do
  125. g := addf(g,numr simp list('times,list('expt,x,i),
  126. caddr nth(eqs,i+1)));
  127. return g
  128. end;
  129. symbolic procedure decomposedf(f,x);
  130. % Differentiate a polynomial wrt top-level variable x.
  131. % Returns a standard form.
  132. if domainp f or not(mvar f = x) then nil else
  133. if ldeg f = 1 then lc f else
  134. mvar f .** (ldeg f - 1) .* multf(lc f,ldeg f)
  135. .+ decomposedf(red f,x);
  136. symbolic procedure decomposeint(f,x);
  137. % Integrate a polynomial (standard form) wrt the (main-)variable x.
  138. % Returns a standard quotient.
  139. if null f then nil ./ 1 else
  140. if domainp f then (x .** 1 .* f .+ nil) ./ 1 else
  141. addsq(multsq((x .** (ldeg f + 1) .* 1 .+ nil)./ 1 ,
  142. multsq(lc f./1,1 ./ldeg f+1))
  143. , decomposeint(red f,x));
  144. symbolic procedure decomposecoeff(f,vars);
  145. % Select the coefficients of f wrt vars.
  146. begin scalar o;
  147. o := setkorder vars;
  148. f := reorder f;
  149. setkorder o;
  150. return decomposecoeff1(f,vars)
  151. end;
  152. symbolic procedure decomposecoeff1(f,vars);
  153. if domainp f then nil else
  154. if not member(mvar f,vars) then list f else
  155. nconc(decomposecoeff1(lc f,vars),decomposecoeff1(red f,vars));
  156. symbolic procedure decomposetdg f;
  157. % calculate total degree
  158. if domainp f then 0 else
  159. max(ldeg f + decomposetdg lc f, decomposetdg red f);
  160. symbolic procedure decomposedegr(f,vl);
  161. if domainp f then vl else
  162. <<if ldeg f > cdr v then cdr v := ldeg f;
  163. decomposedegr(lc f,vl);
  164. decomposedegr(red f,vl);
  165. vl>> where v = assoc(mvar f,vl);
  166. symbolic procedure compose (u,v);
  167. % Calculate f(x)=u(v(x)) for standard forms u,v.
  168. if domainp u then u else
  169. numr subf(u,list(mvar u . prepf v));
  170. % Multivariate polynomial decomposition.
  171. %
  172. % Technique:
  173. % select a field as domain (rational),
  174. % map f to a strongly monic polynomial by variable transform,
  175. % map f to a univariate image,
  176. % decompose the univariate polynomial,
  177. % lift decomposition to multivariate,
  178. % convert back to original variables,
  179. % transform back to original domain (if possible).
  180. symbolic procedure decomposesfmulti(f,vars);
  181. % Multivariant case: map to field (rationals).
  182. begin scalar dm,ft,r,rr,a,q,c,p1,p2;
  183. if null dmode!* or not flagp(dmode!*,'field) then
  184. <<setdmode('rational,t) where !*msg=nil; dm := t;
  185. ft := !*q2f resimp !*f2q f>> else ft := f;
  186. r := decomposesfmulti1(ft,vars);
  187. if dm then setdmode('rational,nil) where !*msg=nil;
  188. if null cdr r then return list(f./1);
  189. % if null dm then return
  190. % for each p in r collect (p ./ 1);
  191. % Convert back to integer polynomials.
  192. rr := for each p in reverse r collect simp prepf p;
  193. r := nil;
  194. while rr and cdr rr do
  195. <<p1 := car rr; p2 := cadr rr;
  196. % Propagate absolute term and content from p1 to p2.
  197. q := denr p1; a := numr p1;
  198. while not domainp a do a := red a;
  199. p1 := addf(numr p1,negf a);
  200. c := decomposenormfac p1;
  201. p1 := multsq(p1 ./ 1, 1 ./ c);
  202. p2 := subsq(p2,list(mvar numr p2 .
  203. list('quotient,
  204. list('plus,list('times,decomposegensym(),prepf c),
  205. prepf a),
  206. prepf q)));
  207. r := p1 . r; rr := p2 . cddr rr>>;
  208. return car rr . r;
  209. end;
  210. symbolic procedure decomposesfmulti1(f,vars);
  211. % Multivariate case: map to strongly monic polynomial.
  212. begin scalar lvars,ft,rt,x1,a0,kord,u,sigma;
  213. integer n,m;
  214. % get the variable with highest degree as main variable.
  215. u := decomposedegr(f,for each x in vars collect (x. 0));
  216. n := -1;
  217. for each x in u do
  218. if n<cdr x then <<n:=cdr x; x1 := car x>>;
  219. if n<2 then return list f;
  220. vars := x1 . delete(x1,vars);
  221. kord := setkorder vars;
  222. f := reorder f;
  223. % Convert f to a strongly monic polynomial.
  224. n := decomposetdg f;
  225. x1 := car vars;
  226. lvars := for each x in cdr vars collect (x . decomposegensym());
  227. again:
  228. if m>10 then << rt := list f; goto ret>>;
  229. % construct transformation sigma
  230. sigma := for each x in lvars collect x . random 1000;
  231. ft := numr subf(f,for each x in sigma collect
  232. (caar x . list('plus,cdar x,list('times,x1,cdr x))));
  233. if not domainp lc ft then <<m:=m+1; goto again>>;
  234. a0 := lc ft; ft := quotf(ft,a0);
  235. rt := decomposesfmnorm(ft,n,sublis(lvars,vars));
  236. if cdr rt then
  237. % Transform result back.
  238. <<rt := reverse rt;
  239. rt := numr subf(car rt,for each x in sigma collect
  240. (cdar x . list('difference,caar x,list('times,cdr x,x1))))
  241. . multf(a0,cadr rt) . cddr rt;
  242. >> else rt := list f;
  243. ret:
  244. setkorder kord;
  245. rt := for each p in rt collect reorder p;
  246. % try further decomposition of central polynomial.
  247. return if cdr rt and decomposetdg car rt>1 then
  248. append(reverse cdr rt,decomposesfmulti1(car rt,vars))
  249. else reverse rt;
  250. end;
  251. symbolic procedure decomposelmon f;
  252. % Extract the variables of the leading monomial.
  253. if domainp f then nil else
  254. mvar f . decomposelmon lc f;
  255. symbolic procedure decomposenormfac p1;
  256. if null dmode!* or not flagp(dmode!*,'field) then
  257. multf(numr mkabsfd decomposecont p1,decomposesign p1)
  258. else <<while not domainp p1 do p1:=lc p1; p1>>;
  259. symbolic procedure decomposecont f;
  260. % Calculate the content of f if the domain is a ring.
  261. if domainp f then f else
  262. gcdf(decomposecont lc f, decomposecont red f);
  263. symbolic procedure decomposesign f;
  264. % Compute a unit factor c such that the leading coefficient of
  265. % f/c is a positive integer.
  266. if domainp f then numr quotsq(f ./ 1,mkabsfd f)
  267. else decomposesign lc f;
  268. symbolic procedure decomposesfmnorm(f,n,vars);
  269. % Multivariate case: map strongly monic polynomial to univariate
  270. % and lift result.
  271. begin scalar x,x1,f0,g,u,abort,h,k,tt,q,v;
  272. integer r,s;
  273. x1 := car vars;
  274. % Step 1.
  275. f0 := numr subf(f,for each y in cdr vars collect (y . 0));
  276. u := decomposesfuni f0;
  277. % For multivariate we accept degree=1 polynomials as nontrivial
  278. % but inhibit recursion.
  279. if null cdr u then <<u:=append(u,list !*k2f x1)>>;
  280. x := decomposegensym();
  281. g := numr subf(car u,list (x1 . x));
  282. r := ldeg g;
  283. h := cadr u; u := cddr u;
  284. while u do
  285. <<v := car u; u:= cdr u; h := numr subf(h,list(x1 . x));
  286. h := compose(h,v); >>;
  287. % Step 2.
  288. s := divide(n,r);
  289. if not(cdr s=0) then goto fail else s := car s;
  290. k := h;
  291. tt := compose(decomposedf(g,x),h);
  292. % Step 3: Hensel lifting in degree steps.
  293. for i:=1:s do
  294. if not abort then
  295. % Step 4: loop step.
  296. <<u := decomposehomog(addf(f,negf compose(g,k)),x1,i);
  297. q := quotf(u,tt);
  298. if u and null q then abort:=t else<<h:=q; k:=addf(k,h)>>
  299. >>;
  300. if abort then goto fail;
  301. % Step 5: test result and loop for lower part.
  302. h := k;
  303. if f = compose(g,h) then return list(g,h);
  304. fail: % Exit: no decomposition found.
  305. return list f;
  306. end;
  307. symbolic procedure decomposehomog(f,x,d);
  308. % F is a polynomial (standard form) in x and some other
  309. % variables. Select that part of f, where the coefficients
  310. % of x are monomials in total degree d.
  311. % Result is the sum (standard form) of these monomials.
  312. begin scalar u,v;
  313. u := decomposehomog1(f,x,d);
  314. for each m in u do v := addf(v,m);
  315. return v;
  316. end;
  317. symbolic procedure decomposehomog1(f,x,d);
  318. % Select the monomials.
  319. if d<0 or null f then nil else
  320. if domainp f then (if d=0 then list f else nil)
  321. else begin scalar u1,u2;
  322. u1:= decomposehomog1(lc f,x,if mvar f = x then d
  323. else d-ldeg f);
  324. u2:= decomposehomog1(red f,x,d);
  325. return
  326. nconc(
  327. for each v in u1 collect
  328. multf(mvar f .** ldeg f .*1 .+ nil , v),
  329. u2);
  330. end;
  331. symbolic procedure decomposegensym();
  332. compress(append('(!! !D !! !c !! !.),
  333. explode2(decomposegensym!*:=decomposegensym!*+1)));
  334. endmodule;
  335. end;