dpoly.red 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. module dpoly;
  2. COMMENT
  3. ##################
  4. ## ##
  5. ## POLYNOMIALS ##
  6. ## ##
  7. ##################
  8. Polynomial vectors and polynomials are handled in a unique way using
  9. the module component of monomials to store the vector component. If
  10. the component is 0, we have a polynomial, otherwise a vector. They
  11. are represented in a distributive form (dpoly for short).
  12. Informal syntax of (vector) polynomials :
  13. <dpoly> ::= list of <term>s
  14. <term> ::= ( <monomial> . <base coefficient> )
  15. END COMMENT;
  16. % ----------- constructors and selectors -------------------
  17. symbolic procedure dp_lc p;
  18. % Leading base coefficient of the dpoly p.
  19. cdar p;
  20. symbolic procedure dp_lmon p;
  21. % Leading monomial of the dpoly p.
  22. caar p;
  23. symbolic procedure dp_term (a,e);
  24. % Constitutes a term from a:base coeff. and e:monomial.
  25. (e . a);
  26. symbolic procedure dp_from_ei n;
  27. % Returns e_i as dpoly.
  28. list dp_term(bc_fi 1,mo_from_ei n);
  29. symbolic procedure dp_fi n;
  30. % dpoly from integer
  31. if n=0 then nil else
  32. list dp_term(bc_fi n,mo_zero());
  33. symbolic procedure dp_fbc c;
  34. % Converts the base coefficient c into a dpoly.
  35. if bc_zero!? c then nil else
  36. list dp_term(c,mo_zero());
  37. % ------------ dpoly arithmetics ---------------------------
  38. symbolic procedure dp!=comp(i,v);
  39. if null v then nil
  40. else if eqn(mo_comp dp_lmon v,i) then car v . dp!=comp(i,cdr v)
  41. else dp!=comp(i,cdr v);
  42. symbolic procedure dp_comp(i,v);
  43. % Returns the (polynomial) component i of the vector v.
  44. for each x in dp!=comp(i,v) collect (mo_deletecomp car x) . cdr x;
  45. symbolic procedure dp!=mocompare (t1,t2);
  46. % true <=> term t1 is smaller than term t2 in the current term order.
  47. eqn(mo_compare (car t1, car t2),1);
  48. symbolic procedure dp_neworder p;
  49. % Returns reordered dpoly p after change of the term order.
  50. sort(for each x in p collect (mo_neworder car x) . cdr x,
  51. function dp!=mocompare);
  52. symbolic procedure dp_neg p;
  53. % Returns - p for the dpoly p.
  54. for each x in p collect (car x . bc_neg cdr x);
  55. symbolic procedure dp_times_mo (mo,p);
  56. % Returns p * x^mo for the dpoly p and the monomial mo.
  57. for each x in p collect (mo_sum(mo,car x) . cdr x);
  58. symbolic procedure dp_times_bc (bc,p);
  59. % Returns p * bc for the dpoly p and the base coeff. bc.
  60. for each x in p collect (car x . bc_prod(bc,cdr x));
  61. symbolic procedure dp_times_bcmo (bc,mo,p);
  62. % Returns p * bc * x^mo for the dpoly p, the monomial mo and the base
  63. % coeff. bc.
  64. for each x in p collect (mo_sum(mo,car x) . bc_prod(bc,cdr x));
  65. symbolic procedure dp_times_ei(i,p);
  66. % Returns p * e_i for the dpoly p.
  67. dp_neworder for each x in p collect (mo_times_ei(i,car x) . cdr x);
  68. symbolic procedure dp_project(p,k);
  69. % Delete all terms x^a*e_i with i>k.
  70. for each x in p join if mo_comp car x <= k then {x};
  71. symbolic procedure dp_content p;
  72. % Returns the leading coefficient, if invertible, or the content of
  73. % p.
  74. if null p then bc_fi 0
  75. else begin scalar w;
  76. w:=dp_lc p; p:=cdr p;
  77. while p and not bc_inv w do
  78. << w:=bc_gcd(w,dp_lc p); p:=cdr p >>;
  79. return w
  80. end;
  81. symbolic procedure dp_mondelete(p,s);
  82. % Returns (p.m) with common monomial factor m with support in the
  83. % var. list s deleted.
  84. if null p or null s then (p . mo_zero()) else
  85. begin scalar cmf;
  86. cmf:=dp!=cmf(p,s);
  87. if mo_zero!? cmf then return (p . cmf)
  88. else return
  89. cons(for each x in p collect mo_diff(car x,cmf) . cdr x,cmf)
  90. end;
  91. symbolic procedure dp!=cmf(p,s);
  92. begin scalar a;
  93. a:=mo_seed(dp_lmon p,s); p:=cdr p;
  94. while p and (not mo_zero!? a) do
  95. << a:=mo_gcd(a,mo_seed(dp_lmon p,s)); p:=cdr p >>;
  96. return a
  97. end;
  98. symbolic procedure dp_unit!? p;
  99. % Tests whether lt p of the dpoly p is a unit.
  100. % This means : p is a unit, if the t.o. is noetherian
  101. % or : p is a local unit, if the t.o. is a tangentcone order.
  102. p and (mo_zero!? dp_lmon p);
  103. symbolic procedure dp_simp pol;
  104. % Returns (pol_new . z) with
  105. % pol_new having leading coefficient 1 or
  106. % dp_content pol canceled out
  107. % and pol_old = z * dpoly_new .
  108. if null pol then pol . bc_fi 1
  109. else begin scalar z,z1;
  110. if (z:=bc_inv (z1:=dp_lc pol)) then
  111. return dp_times_bc(z,pol) . z1;
  112. % -- now we assume that base coefficients are a gcd domain ----
  113. z:=dp_content pol;
  114. if bc_minus!? z1 then z:=bc_neg z;
  115. pol:=for each x in pol collect
  116. car x . car bc_divmod(cdr x,z);
  117. return pol . z;
  118. end;
  119. symbolic procedure dp_prod(p1,p2);
  120. % Returns p1 * p2 for the dpolys p1 and p2.
  121. if length p1 <= length p2 then dp!=prod(p1,p2)
  122. else dp!=prod(p2,p1);
  123. symbolic procedure dp!=prod(p1,p2);
  124. if null p1 or null p2 then nil
  125. else
  126. begin scalar v;
  127. for each x in p1 do
  128. v:=dp_sum( dp_times_bcmo(cdr x,car x, p2 ),v);
  129. return v;
  130. end;
  131. symbolic procedure dp_sum(p1,p2);
  132. % Returns p1 + p2 for the dpolys p1 and p2.
  133. if null p1 then p2
  134. else if null p2 then p1
  135. else begin scalar sl,al;
  136. sl := mo_compare(dp_lmon p1, dp_lmon p2);
  137. if sl = 1 then return car p1 . dp_sum(cdr p1, p2);
  138. if sl = -1 then return car p2 . dp_sum(p1, cdr p2);
  139. al := bc_sum(dp_lc p1, dp_lc p2);
  140. if bc_zero!? al then return dp_sum(cdr p1, cdr p2)
  141. else return dp_term(al,dp_lmon p1) . dp_sum(cdr p1, cdr p2)
  142. end;
  143. symbolic procedure dp_diff(p1,p2);
  144. % Returns p1 - p2 for the dpolys p1 and p2.
  145. dp_sum(p1, dp_neg p2);
  146. symbolic procedure dp_power(p,n);
  147. % Returns p^n for the dpoly p.
  148. if (not fixp n) or (n < 0) then typerr(n," exponent")
  149. else if n=0 then dp_fi 1
  150. else if n=1 then p
  151. else if null cdr p then dp!=power1(p,n)
  152. else dp!=power(p,n);
  153. symbolic procedure dp!=power1(p,n); % For monomials.
  154. list dp_term(bc_power(dp_lc p,n),mo_power(dp_lmon p,n));
  155. symbolic procedure dp!=power(p,n);
  156. if n=1 then p
  157. else if evenp n then dp!=power(dp_prod(p,p),n/2)
  158. else dp_prod(p,dp!=power(dp_prod(p,p),n/2));
  159. symbolic procedure dp_tcpart p;
  160. % Return the homogeneous degree part of p of highest degree.
  161. if null p then nil
  162. else begin scalar d,u; d:=car mo_deg caar p;
  163. while p and (d=car mo_deg caar p) do
  164. << u:=car p . u; p:=cdr p >>;
  165. return reversip u;
  166. end;
  167. symbolic procedure dp_deletecomp p;
  168. % delete the component part from all terms.
  169. dp_neworder for each x in p collect mo_deletecomp car x . cdr x;
  170. symbolic procedure dp_factor p;
  171. for each y in cdr ((fctrf numr simp dp_2a p) where !*factor=t)
  172. collect dp_from_a prepf car y;
  173. % ------ Converting prefix forms into dpolys ------------------
  174. symbolic procedure dp_from_a u;
  175. % Converts the algebraic (prefix) form u into a dpoly.
  176. if eqcar(u,'list) or eqcar(u,'mat) then typerr(u,"dpoly")
  177. else if atom u then dp!=a2dpatom u
  178. else if not atom car u or not idp car u
  179. then typerr(car u,"dpoly operator")
  180. else (if x='dp!=fnpow then dp!=fnpow(dp_from_a cadr u,caddr u)
  181. else if x then
  182. apply(x,list for each y in cdr u collect dp_from_a y)
  183. else dp!=a2dpatom u)
  184. where x = get(car u,'dp!=fn);
  185. symbolic procedure dp!=a2dpatom u;
  186. % Converts the atom (or kernel) u into a dpoly.
  187. if u=0 then nil
  188. else if numberp u or not member(u, ring_all_names cali!=basering)
  189. then list dp_term(bc_from_a u,mo_zero())
  190. else list dp_term(bc_fi 1,mo_from_a u);
  191. symbolic procedure dp!=fnsum u;
  192. % U is a list of dpoly expressions. The result is the dpoly
  193. % representation for the sum. Analogously for the other symbolic
  194. % procedures below.
  195. (<<for each y in cdr u do x := dp_sum(x,y); x>>) where x = car u;
  196. put('plus,'dp!=fn,'dp!=fnsum);
  197. put('plus2,'dp!=fn,'dp!=fnsum);
  198. symbolic procedure dp!=fnprod u;
  199. (<<for each y in cdr u do x := dp_prod(x,y); x>>) where x = car u;
  200. put('times,'dp!=fn,'dp!=fnprod);
  201. put('times2,'dp!=fn,'dp!=fnprod);
  202. symbolic procedure dp!=fndif u; dp_diff(car u, cadr u);
  203. put('difference,'dp!=fn,'dp!=fndif);
  204. symbolic procedure dp!=fnpow(u,n); dp_power(u,n);
  205. put('expt,'dp!=fn,'dp!=fnpow);
  206. symbolic procedure dp!=fnneg u;
  207. ( if null v then v else dp_term(bc_neg dp_lc v,dp_lmon v) . cdr v)
  208. where v = car u;
  209. put('minus,'dp!=fn,'dp!=fnneg);
  210. symbolic procedure dp!=fnquot u;
  211. if null cadr u or not null cdadr u
  212. or not mo_zero!? dp_lmon cadr u
  213. then typerr(dp_2a cadr u,"distributive polynomial denominator")
  214. else dp!=fnquot1(car u,dp_lc cadr u);
  215. symbolic procedure dp!=fnquot1(u,v);
  216. if null u then u
  217. else dp_term(bc_quot(dp_lc u,v), dp_lmon u) .
  218. dp!=fnquot1(cdr u,v);
  219. put('quotient,'dp!=fn,'dp!=fnquot);
  220. % -------- Converting dpolys into prefix forms -------------
  221. % ------ Authors: R. Gebauer, A. C. Hearn, H. Kredel -------
  222. symbolic procedure dp_2a u;
  223. % Returns the prefix equivalent of the dpoly u.
  224. if null u then 0 else dp!=replus dp!=2a u;
  225. symbolic procedure dp!=2a u;
  226. if null u then nil
  227. else ((if bc_minus!? x then
  228. list('minus,dp!=retimes(bc_2a bc_neg x . y))
  229. else dp!=retimes(bc_2a x . y))
  230. where x = dp_lc u, y = mo_2a dp_lmon u)
  231. . dp!=2a cdr u;
  232. symbolic procedure dp!=replus u;
  233. if atom u then u else if null cdr u then car u else 'plus . u;
  234. symbolic procedure dp!=retimes u;
  235. % U is a list of prefix expressions the first of which is a number.
  236. % The result is the prefix representation for their product.
  237. if car u = 1 then if cdr u then dp!=retimes cdr u else 1
  238. else if null cdr u then car u
  239. else 'times . u;
  240. % ----------- Printing routines for dpolys --------------
  241. % ---- Authors: R. Gebauer, A. C. Hearn, H. Kredel ------
  242. symbolic procedure dp_print u;
  243. % Prints a distributive polynomial in infix form.
  244. << terpri(); dp_print1(u,nil); terpri(); terpri() >>;
  245. symbolic procedure dp_print1(u,v);
  246. % Prints a dpoly in infix form.
  247. % U is a distributive form. V is a flag which is true if a term
  248. % has preceded current form.
  249. if null u then if null v then print_lf 0 else nil
  250. else begin scalar bool,w;
  251. w := dp_lc u;
  252. if bc_minus!? w then <<bool := t; w := bc_neg w>>;
  253. if bool then print_lf " - " else if v then print_lf " + ";
  254. ( if not bc_one!? w or mo_zero!? x then
  255. << bc_prin w; mo_prin(x,t)>>
  256. else mo_prin(x,nil))
  257. where x = dp_lmon u;
  258. dp_print1(cdr u,t)
  259. end;
  260. symbolic procedure dp_print2 u;
  261. % Prints a dpoly with restricted number of terms.
  262. (if c and (length u>c) then
  263. begin scalar i,v,x;
  264. v:=for i:=1:c collect <<x:=car u; u:=cdr u; x>>;
  265. dp_print1(v,nil); write" + # ",length u," terms #"; terpri();
  266. end
  267. else << dp_print1(u,nil); terpri() >>)
  268. where c:=get('cali,'printterms);
  269. % -------------- Auxiliary dpoly operations -------------------
  270. symbolic procedure dp_ecart p;
  271. % Returns the ecart of the dpoly p.
  272. if null p then 0 else (dp!=ecart p) - (mo_ecart dp_lmon p);
  273. symbolic procedure dp!=ecart p;
  274. if null p then 0
  275. else max2(mo_ecart dp_lmon p,dp!=ecart cdr p);
  276. symbolic procedure dp_homogenize(p,x);
  277. % Homogenize (according to mo_ecart) the dpoly p using the variable x.
  278. if null p then p
  279. else begin integer maxdeg;
  280. maxdeg:=0;
  281. for each y in p do maxdeg:=max2(maxdeg,mo_ecart car y);
  282. return dp!=compact dp_neworder for each y in p collect
  283. mo_inc(car y,x,maxdeg-mo_ecart car y) . cdr y;
  284. end;
  285. symbolic procedure dp_seed(p,s);
  286. % Returns the dpoly p with all vars outside the list s set equal to 1.
  287. if null p then p
  288. else dp!=compact dp_neworder
  289. for each x in p collect mo_seed(car x,s).cdr x;
  290. symbolic procedure dp!=compact p;
  291. % Collect equal terms in the sorted dpoly p.
  292. if null p then p else dp_sum(list car p,dp!=compact cdr p);
  293. symbolic procedure dp_xlt(p,x);
  294. % x is the main variable. Returns the leading term of p wrt. x or p,
  295. % if p is free of x.
  296. if null p then p
  297. else begin scalar d,m;
  298. d:=mo_varexp(x,dp_lmon p);
  299. if d=0 then return p;
  300. return for each m in p join
  301. if mo_varexp(x,car m)=d then {mo_inc(car m,x,-d) . cdr m};
  302. end;
  303. % -- dpoly operations based on computation with ideal bases.
  304. symbolic procedure dp_pseudodivmod(g,f);
  305. % Returns a dpoly list {q,r,z} such that z * g = q * f + r and
  306. % z is a dpoly unit. Computes redpol({[f.e_1]},[g.0]).
  307. % g, f and r must belong to the same free module.
  308. begin scalar u;
  309. f:=list bas_make1(1,f,dp_from_ei 1);
  310. g:=bas_make(0,g);
  311. u:=red_redpol(f,g);
  312. return {dp_neg dp_deletecomp bas_rep car u,bas_dpoly car u,cdr u};
  313. end;
  314. symbolic operator dpgcd;
  315. symbolic procedure dpgcd(u,v);
  316. if !*mode='algebraic then dp_2a dpgcd!*(dp_from_a u,dp_from_a v)
  317. else dpgcd!*(u,v);
  318. symbolic procedure dpgcd!*(u,v);
  319. % Compute the gcd of two polynomials by the syzygy method :
  320. % 0 = u*u1 + v*v1 => gcd = u/v1 = -v/u1 .
  321. if dp_unit!? u or dp_unit!? v then dp_fi 1
  322. else begin scalar w;
  323. w:=bas_dpoly first dpmat_list
  324. syzygies!* dpmat_make(2,0,{bas_make(1,u),bas_make(2,v)},nil,nil);
  325. return car dp_pseudodivmod(u,dp_comp(2,w));
  326. end;
  327. endmodule; % dpoly
  328. end;