kuechl.red 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. module kuechl; % Walking faster, B. Amrhrein, O. Gloor,
  2. % W. Kuechlin
  3. % in: Calmet, Limongelli (Eds.) Design and
  4. % Implementation of Symbolic Computation Systems,
  5. % Sept.1996
  6. % Version 3 with a rational local solution (after letters from
  7. % H. M. Moeller).
  8. % Version 4 with keeping the polynomials as DIPs converting only
  9. % their order mode.
  10. fluid '(vdpsortmode!* vdpsortextension!* dipvars!* !*trgroeb
  11. groetime!* !*vdpinteger pcount!* !*gsugar !*groebopt
  12. !*groebrm !*groebdivide);
  13. switch trgroeb;
  14. fluid '(secondvalue!*);
  15. put('groebner_walk,'psopfn,'groeb!-w1);
  16. symbolic procedure groeb!-w1 u;
  17. begin
  18. if !*groebopt then
  19. rerror(groebner,31,
  20. "don't call 'groebner_walk' with 'on groebopt'");
  21. if null dipvars!* then
  22. rerror(groebner,30,"'torder' must be called before");
  23. groetime!* := time(); % initialization
  24. !*gsugar := t; % initialization
  25. !*groebrm := nil; % initialization
  26. u := car groeparams(u,1,1);
  27. groebnervars(u,nil);
  28. u := groeb!-list(u,'simp);
  29. groedomainmode();
  30. u := groeb!-w2 u;
  31. return 'list . groeb!-collect(u, 'mk!*sq);
  32. end;
  33. symbolic procedure groeb!-list (u, fcn);
  34. % Execute the function 'fcn' for the elements of the algebriac
  35. % list 'u'.
  36. <<if atom u or not(eqcar(u,'list)) then
  37. rerror('groebner,29,
  38. "groebner: list as argument required");
  39. groeb!-collect(cdr u, fcn)
  40. >>;
  41. symbolic procedure groeb!-collect(l, f);
  42. % Collect the elements of function 'f' applied to the elements of
  43. % the symbolic list 'l'. If 'f' is a number, map 'l' only.
  44. for each x in l collect
  45. if numberp f then f else apply1(f,x);
  46. symbolic procedure groeb!-w2 g;
  47. % This is (essentially) the routine Groebner_Walk.
  48. % G is a list of standard quotients,
  49. % a Groebner basis gradlex or based on a vector like [1 1 1 ...]
  50. % The result is the Groebner basis (standard quotients) with the
  51. % final term order (lex) as its main order.
  52. begin scalar iwv, owv, omega, gomega, gomegaplus, tt, tto, pc;
  53. scalar first, mx, imx, mmx, immx, nn, ll, prim;
  54. scalar !*vdpinteger, !*groebdivide;
  55. !*vdpinteger := nil; % switch on division mode
  56. !*groebdivide := t;
  57. first := t; % Initialization
  58. pcount!* := 0; % Initialization
  59. mmx := !*i2rn 1; % Initialization
  60. immx := mmx; % Initialization
  61. iwv := groeb!-collect(dipvars!*, 1);
  62. omega := iwv; % input order vector
  63. owv := 1 . groeb!-collect(cdr dipvars!*, 0);
  64. tto := owv; % output order vector
  65. groeb!-w9('weighted,omega); % Install omega as weighted order
  66. g := groeb!-collect(g, 'sq2vdp);
  67. pc := pcount!*;
  68. gbtest g; % Test the Groebner property
  69. nn := length dipvars!*;
  70. ll := rninv!: !*i2rn nn; % inverse of the length
  71. prim := t; % preset
  72. loop:
  73. groeb!-w9('weighted, omega);
  74. mx := groeb!-w6!-4 groeb!-collect(omega, 1);
  75. % Compute the maximum of \omega.
  76. if !*trgroeb then groebmess34 cadr mx;
  77. imx := rninv!: mx;
  78. g := if first then groeb!-collect(g, 'vdpsimpcont)
  79. else groeb!-w10 g;
  80. if !*trgroeb then groebmess29(omega);
  81. gomega := if first or not prim then g
  82. else groeb!-w3(g,omega); % G_\omega = initials(G_\omega);
  83. pcount!* := pc;
  84. if !*trgroeb and not first then groebmess32 gomega;
  85. gomegaplus := if first then list gomega
  86. else gtraverso(gomega,nil,nil,nil);
  87. if cdr gomegaplus then rerror(groebner,31,
  88. "groebner_walk, cdr of 'groebner' must be nil")
  89. else gomegaplus := car gomegaplus;
  90. if !*trgroeb and not first then groebmess30 gomegaplus;
  91. if not first and prim
  92. then g := groeb!-w4(gomegaplus, gomega, g)
  93. else if not prim then g := gomega;
  94. % G = lift(G_{%omega}{plus},<{plus},G_{%omega), G, <)
  95. if not first
  96. then g := for each x in g collect gsetsugar (x, nil);
  97. if !*trgroeb and not first then groebmess31 g;
  98. if groeb!-w5(omega,imx,tto,immx) then goto ret;
  99. % stop if tt has been 1 once.
  100. if not first and rnonep!: tt then goto ret; % Secodary abort crit.
  101. tt := groeb!-w6!-6(g,tto,immx,omega,imx,ll); % determine_border
  102. if !*trgroeb then groebmess36 tt;
  103. if null tt then go to ret;
  104. % criterion: take primary only if tt neq 1
  105. prim := not rnonep!: tt;
  106. if !*trgroeb then groebmess37 prim;
  107. %\omega = (1 - t)*\omega + t*tau
  108. omega := groeb!-w7(tt, omega, imx, tto, immx);
  109. if !*trgroeb then groebmess35 omega;
  110. first := nil;
  111. go to loop;
  112. ret:
  113. if !*trgroeb then groebmess33 g;
  114. g := groeb!-collect(g, 'vdpsimpcont);
  115. g := groeb!-collect(g, 'vdp2sq);
  116. return g
  117. end;
  118. symbolic procedure groeb!-w3(g, omega);
  119. % Extract head terms of g corresponding to omega
  120. begin scalar x, y, gg, ff;
  121. gg := for each f in g collect
  122. <<ff := vdpfmon(vdplbc f,vdpevlmon f);
  123. gsetsugar(ff, nil);
  124. x := evweightedcomp2(0, vdpevlmon ff, omega);
  125. y := x;
  126. f := vdpred f;
  127. while not vdpzero!? f and y=x do
  128. <<y := evweightedcomp2(0, vdpevlmon f,omega);
  129. if y=x then
  130. ff := vdpsum(ff,vdpfmon(vdplbc f,vdpevlmon f));
  131. f := vdpred f>>;
  132. ff>>;
  133. return gg;
  134. end;
  135. symbolic procedure groeb!-w4(gb, gomega, g);
  136. %gb Groebner basis of gomega,
  137. %gomega head term system g_\omega of g,
  138. %g full (original) system of polynomials.
  139. begin scalar x;
  140. for each y in gb do gsetsugar(y,nil);
  141. x := for each y in gomega collect groeb!-w8(y, gb);
  142. x := for each z in x collect groeb!-w4!-1(z, g);
  143. return x
  144. end;
  145. symbolic procedure groeb!-w4!-1(pl, fs);
  146. % pl is a list of polynomials corresponding to the full system fs.
  147. % Compute the sum of pl * fs.
  148. % Result is the sum.
  149. begin scalar z;
  150. z := vdpzero();
  151. gsetsugar(z,0);
  152. for each p in pair(pl,fs) do
  153. if car p then
  154. z := vdpsum(z,vdpprod(car p , cdr p));
  155. z := vdpsimpcont z;
  156. return z
  157. end;
  158. symbolic procedure groeb!-w5(ev1, x1, ev2, x2);
  159. % ev1 = ev2 equality test.
  160. groeb!-w5!-1(x1, ev1, x2, ev2);
  161. symbolic procedure groeb!-w5!-1(x1, ev1, x2, ev2);
  162. (null ev1 and null ev2) or
  163. (rntimes!:(!*i2rn car ev1 , x1) = rntimes!:(!*i2rn car ev2 , x2)
  164. and groeb!-w5!-1(x1 ,cdr ev1 ,x2 , cdr ev2));
  165. symbolic procedure groeb!-w6!-4 omega;
  166. % Compute the weighted length of \omega.
  167. groeb!-w6!-5 (omega, vdpsortextension!*, 0);
  168. symbolic procedure groeb!-w6!-5(omega, v, m);
  169. if null omega then !*i2rn m
  170. else if 0 = car omega
  171. then groeb!-w6!-5(cdr omega, cdr v, m)
  172. else if 1 = car omega
  173. then groeb!-w6!-5(cdr omega, cdr v, m #+ car v)
  174. else groeb!-w6!-5(cdr omega, cdr v, m #+ car omega #* car v);
  175. symbolic procedure groeb!-w6!-6(gb, tt, ifactt, tp, ifactp, ll);
  176. % Compute the weight border (minimum over all polynomials of gb).
  177. begin
  178. scalar mn, x, zero, one;
  179. zero := !*i2rn 0;
  180. one := !*i2rn 1;
  181. while not null gb do
  182. << x := groeb!-w6!-7(car gb, tt, ifactt, tp, ifactp,
  183. zero, one, ll);
  184. if null mn or (x and rnminusp!: rndifference!:(x, mn))
  185. then mn := x;
  186. gb := cdr gb;>>;
  187. return mn
  188. end;
  189. symbolic procedure groeb!-w6!-7(pol, tt, ifactt, tp, ifactp,
  190. zero, one, ll);
  191. % Compute the minimal weight for one polynomial; the iea is,
  192. % that the polynomial has a degree greater than 0.
  193. begin
  194. scalar a,b,ev1,ev2,x,y,z,mn;
  195. ev1 := vdpevlmon pol;
  196. a := evweightedcomp2(0, ev1, vdpsortextension!*);
  197. y := groeb!-w6!-8(ev1,tt, ifactt, tp, ifactp,
  198. zero, zero, one, ll);
  199. y := (rnminus!: car y) . (rnminus!: cdr y);
  200. pol := vdpred pol;
  201. while not (vdpzero!? pol) do
  202. <<ev2 := vdpevlmon pol;
  203. pol := vdpred pol;
  204. b := evweightedcomp2(0, ev2, vdpsortextension!*);
  205. if not (a = b) then
  206. <<x := groeb!-w6!-9(ev2, tt, ifactt, tp, ifactp,
  207. car y, cdr y, one, ll, nil);
  208. if x then
  209. <<z := rndifference!:(x, one);
  210. if rnminusp!: rndifference!:(zero, x) and
  211. (rnminusp!: z or rnzerop!: z)
  212. and
  213. (null mn or rnminusp!: rndifference!:(x, mn))
  214. then mn := x>>
  215. >>
  216. >>;
  217. return mn
  218. end;
  219. symbolic procedure groeb!-w6!-8(ev, tt, ifactt, tp, ifactp,
  220. sum1, sum2, m, dm);
  221. begin
  222. scalar x, y, z;
  223. if ev then <<x := rntimes!:(!*i2rn car ev, m);
  224. y := rntimes!:(!*i2rn car tp, ifactp);
  225. z := rntimes!:(!*i2rn car tt, ifactt)>>;
  226. return
  227. if null ev then sum1 . sum2 else
  228. groeb!-w6!-8(cdr ev, cdr tt, ifactt, cdr tp, ifactp,
  229. rnplus!:(sum1,rntimes!:(y, x)),
  230. rnplus!:(sum2, rntimes!:( rndifference!:(z, y),x )),
  231. rndifference!:(m, dm),
  232. dm)
  233. end;
  234. symbolic procedure groeb!-w6!-9(ev, tt, ifactt, tp, ifactp,
  235. y1 , y2, m, dm, done);
  236. % Compute the rational solution s:
  237. % (tp + s * (tt - tp)) * ev1 = (tp + s * (tt - tp)) * evn.
  238. % The sum with ev1 is collected already in y1 and y2
  239. % (with negative sign).
  240. % This routine collects the sum with evn and computes the solution.
  241. begin
  242. scalar x, y, z;
  243. if ev then <<x := rntimes!:(!*i2rn car ev, m);
  244. y := rntimes!:(!*i2rn car tp, ifactp),
  245. z := rntimes!:(!*i2rn car tt, ifactt)>>;
  246. return
  247. if null ev then
  248. if null done then nil
  249. else
  250. rnquotient!:(rnminus!: y1, y2)
  251. else
  252. groeb!-w6!-9( cdr ev, cdr tt, ifactt, cdr tp, ifactp,
  253. rnplus!:(y1, rntimes!:(y, x)),
  254. rnplus!:(y2, rntimes!:(rndifference!:(z, y),x )),
  255. rndifference!:(m, dm),
  256. dm,
  257. done or not(car ev = 0))
  258. end;
  259. symbolic procedure groeb!-w7 (tt, omega, x, tto, y);
  260. % Compute omega*x * (1-tt) + tto*y *tt.
  261. % tt is a rational number.
  262. % x and y are rational numbers (inverses of the legths of omega/tt).
  263. begin scalar n,z;
  264. n := !*i2rn 1;
  265. omega := for each g in omega collect
  266. << z := rnplus!:(
  267. rntimes!:(
  268. rntimes!:(!*i2rn g, x),
  269. rndifference!:(!*i2rn 1, tt)),
  270. rntimes!:(
  271. rntimes!:(!*i2rn car tto, y),
  272. tt));
  273. tto := cdr tto;
  274. n := groeb!-w7!-1(n, rninv!: z);
  275. z>>;
  276. omega := for each a in omega collect
  277. rnequiv rntimes!:(a , !*i2rn n);
  278. return omega;
  279. end;
  280. symbolic procedure groeb!-w7!-1(n, m);
  281. % Compute lcm of n and m. N and m are rational numbers.
  282. % Return the lcm.
  283. % Ignore the denominators of n and m.
  284. begin
  285. scalar x, y, z;
  286. if atom n then x := n else
  287. <<x := rnprep!: n;
  288. if not atom x then x := cadr x>>;
  289. if atom m then y := m else
  290. <<y := rnprep!: m;
  291. if not atom y then y := cadr y>>;
  292. z := lcm( x, y);
  293. return z
  294. end;
  295. symbolic procedure groeb!-w8(p, gb);
  296. % Computes the cofactor of p wrt gb.
  297. % Result is a list of cofactors corresponding to g.
  298. % The cofactor 0 is represented as nil.
  299. begin
  300. scalar x,y;
  301. x := groeb!-w8!-1(p,gb);
  302. p := secondvalue!*;
  303. while not vdpzero!? p do
  304. <<y := groeb!-w8!-1(p,gb);
  305. p := secondvalue!*;
  306. x := for each pp in pair(x,y) do
  307. if null car pp then cdr pp
  308. else if null cdr pp then car pp
  309. else vdpsum(car pp, cdr pp) >>;
  310. return x
  311. end;
  312. symbolic procedure groeb!-w8!-1(p, gb);
  313. % Search in groebner basis gb the polynomial which divides the
  314. % head monomial of the polynomial p. The walk version of
  315. % groebSearchInList
  316. % Result: the sequence corresponding to g with the monomial
  317. % factor inserted.
  318. begin
  319. scalar e, cc, r, done, pp;
  320. pp := vdpevlmon p;
  321. cc := vdplbc p;
  322. r := for each poly in gb collect
  323. if done then nil else
  324. if vevdivides!?(vdpevlmon poly,pp) then
  325. <<done := t;
  326. e := poly;
  327. cc := vbcquot(cc,vdplbc poly);
  328. pp := vevdif(pp, vdpevlmon poly);
  329. secondvalue!* :=
  330. vdpsum(
  331. vdpprod(gsetsugar(vdpfmon(vbcneg cc, pp),nil),poly),
  332. p);
  333. vdpfmon(cc, pp)>>
  334. else nil;
  335. if null e then
  336. <<print p;
  337. print "-----------------";
  338. print gb;
  339. rerror(groebner,28,"groeb-w8-1 illegal structure")>>;
  340. return r
  341. end;
  342. symbolic procedure groeb!-w9(mode, ext);
  343. % Switch on vdp order mode "mode" with extension "ext".
  344. % Result is the previous extension.
  345. begin scalar x;
  346. x := vdpsortextension!*;
  347. vdpsortextension!* := ext;
  348. torder2 mode;
  349. return x
  350. end;
  351. symbolic procedure groeb!-w10 s;
  352. % Convert the dips in s corresponding to the actual order.
  353. groeb!-collect(s, 'groeb!-w10!-1);
  354. symbolic procedure groeb!-w10!-1 p;
  355. % Convert the dip p corresponding to the actal order.
  356. begin scalar x;
  357. x := vdpfmon(vdplbc p, vdpevlmon p);
  358. x := gsetsugar(vdpenumerate x, nil);
  359. p := vdpred p;
  360. while not vdpzero!? p do
  361. <<x := vdpsum(vdpfmon(vdplbc p, vdpevlmon p), x);
  362. p := vdpred p>>;
  363. return x
  364. end;
  365. symbolic procedure rninv!: x;
  366. % Return inverse of a (rational) number x: 1/x.
  367. <<if atom x then x := !*i2rn x;
  368. x := cdr x;
  369. if car x < 0 then mkrn(- cdr x, - car x)
  370. else mkrn(cdr x, car x) >>;
  371. symbolic procedure sq2vdp s;
  372. % Standard quotient to VDP.
  373. begin
  374. scalar x,y;
  375. x := f2vdp numr s;
  376. gsetsugar(x, nil);
  377. y := f2vdp denr s;
  378. gsetsugar(y, 0);
  379. s := vdpdivmon(x,vdplbc y,vdpevlmon y);
  380. return s;
  381. end;
  382. symbolic procedure vdp2sq v;
  383. % Conversion VDP to standard quotient
  384. begin
  385. scalar x, y, z, one;
  386. one := 1 ./ 1;
  387. x := nil ./ 1;
  388. while not vdpzero!? v do
  389. <<y := vdp2f vdpfmon(one, vdpevlmon v) ./ 1;
  390. z := vdplbc v;
  391. x := addsq(x, multsq(z,y));
  392. v := vdpred v>>;
  393. return x;
  394. end;
  395. endmodule;
  396. end;