wu.red 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. module wu; % Simple implementation of the Wu algorithm.
  2. % Author: Russell Bradford
  3. % School of Mathematical Sciences
  4. % University of Bath
  5. % Bath
  6. % Avon BA2 7AY
  7. % United Kingdom
  8. % E-mail: rjb@maths.bath.ac.uk
  9. % First distributed version: 8 July 90
  10. % Bug fixes in wupseudodivide, and misc other changes: 28 Aug 90
  11. % This is a simple implementation of the Wu algorithm, intended to help
  12. % myself understand the method. As such, there is little optimization,
  13. % and indeed, only implements the basic version from
  14. %
  15. % "A Zero Structure Theorem for Polynomial-Equations-Solving",
  16. % Wu Wen-tsun, Institute of Systems Science, Academia Sinica, Beijing
  17. % Interface:
  18. % much as the Groebner basis package:
  19. %
  20. % wu({x*y-a, x^y+y^2-b}, {x, y});
  21. %
  22. % uses Wu on the named polynomials with ordering on the variables x > y.
  23. % returns a list of pairs { characteristic set, initial }
  24. %
  25. % { {{a^2 - b*y^2 + y^4}, y} }
  26. %
  27. % The zeros of the input polynomials are the the union of the zeros of
  28. % the characteristic sets, subject to the initials being non-zero.
  29. % Thus the zeros of {x*y-a, x^y+y^2-b} are the zeros of
  30. % {a^2 - b*y^2 + y^4, a - x*y} subject to y neq 0.
  31. %
  32. % The switch
  33. %
  34. % on trwu;
  35. %
  36. % prints some tracing of the algorithm as it works, in particular the
  37. % choice of basic sets, and the computation of characteristic sets.
  38. % This package runs on Reduce 3.3.
  39. % Keywords: polynomial reduction characteristic set sets initial
  40. % ascending
  41. % chrstrem Wu
  42. % All improvements and bug fixes are welcomed!!
  43. % Possible bug fixes, improvements:
  44. % Should use distributed polys, then class is an integer;
  45. % rather than use union, use an insertion sort;
  46. % return a list of {{polys},{initials}};
  47. % fix pseudo divide for when there is a non-trivial content in the
  48. % remainder;
  49. % many opportunities for reusing data from a previous iteration, e.g.,
  50. % when a new polynomial added into a basic set is less than all
  51. % current members of the basic set, and they are reduced wrt it.
  52. % factor out monomials and numeric contents
  53. create!-package('(wu),'(contrib misc));
  54. fluid '(!*trwu !*trchrstrem wuvarlist!* kord!*);
  55. switch trwu, trchrstrem;
  56. procedure wuconstantp f;
  57. % A constant is a poly that does not involve any of the interesting
  58. % variables.
  59. domainp f or not memq(mvar f, wuvarlist!*);
  60. smacro procedure wuclass f;
  61. if wuconstantp f then nil else mvar f;
  62. smacro procedure wudeg f;
  63. if wuconstantp f then 0 else ldeg f;
  64. smacro procedure wuinitial f;
  65. if wuconstantp f then f else lc f;
  66. procedure wureducedpolysp(f, polylist);
  67. % if f reduced wrt the polys in polylist?
  68. null polylist or
  69. (wureducedp(f, car polylist) and wureducedpolysp(f, cdr polylist));
  70. procedure wureducedp(g, f);
  71. % is g reduced wrt f?
  72. wuconstantp f or
  73. wuconstantp g or
  74. deginvar(g, wuclass f) < ldeg f;
  75. procedure deginvar(f, x);
  76. % the degree of x in f
  77. if wuconstantp f then 0
  78. else if mvar f = x then ldeg f
  79. else begin scalar kord!*;
  80. kord!* := list x;
  81. f := reorder f;
  82. return if mvar f = x then ldeg f else 0
  83. end;
  84. % wukord* = '(x y a) means: all other symbols < x < y < a
  85. fluid '(wukord!*);
  86. procedure symbollessp(x, y);
  87. % an ordering on symbols: Cambs lisp and PSL orderp differ on nils
  88. if null y then nil
  89. else if null x then t
  90. else if wukord!* then wuorderp(x, y)
  91. else not orderp(x, y);
  92. procedure wuorderp(x, y);
  93. % an order on the symbols has been specified
  94. % return T if x < y
  95. % circumlocutions abound
  96. begin scalar kord, answ;
  97. if x eq y then return nil;
  98. kord := wukord!*;
  99. while kord and not answ do
  100. if x eq car kord
  101. then answ := if memq(y, cdr kord) then 'yes else 'no
  102. else if y eq car kord
  103. then answ := if memq(x, cdr kord) then 'no else 'yes
  104. else kord := cdr kord;
  105. return if answ then answ eq 'yes else not orderp(x, y)
  106. end;
  107. smacro procedure classlessp(c1, c2);
  108. % an order on classes, which are symbols in this implementation
  109. symbollessp(c1, c2);
  110. procedure wulessp(f, g);
  111. % standard forms f and g
  112. % a partial order
  113. classlessp(wuclass f, wuclass g) or
  114. (wuclass f = wuclass g and wudeg f < wudeg g);
  115. procedure wulessp!*(f, g);
  116. % as above, but use some arbitrary means to complete to a total order
  117. if wulessp(f, g) then t
  118. else if wulessp(g, f) then nil
  119. else totallessp(f, g);
  120. smacro procedure nil2zero f;
  121. f or 0;
  122. procedure totallessp(f, g);
  123. % a total order on polynomials
  124. totalcompare(f, g) = 'less;
  125. procedure totalcompare(f, g);
  126. % order f and g
  127. % horrid bit of code
  128. if f = g then 'equal
  129. else if wulessp(f, g) then 'less
  130. else if wulessp(g, f) then 'greater
  131. else if wuconstantp f then % and so wuconstantp g
  132. totalcompareconstants(f, g)
  133. else begin scalar answ;
  134. answ := totalcompare(lc f, lc g);
  135. if answ neq 'equal then return answ;
  136. return totalcompare(red f, red g)
  137. end;
  138. procedure totalcompareconstants(f, g);
  139. % order the constants f and g
  140. if f = g then 'equal
  141. else if domainp f then
  142. if domainp g then % Assumption of ints
  143. if nil2zero f < nil2zero g then 'less else 'greater
  144. else 'less
  145. else if domainp g then 'greater
  146. else begin scalar wukord!*, wuvarlist!*, answ;
  147. if symbollessp(mvar f, mvar g) then return 'less
  148. else if symbollessp(mvar g, mvar f) then return 'greater
  149. else answ := totalcompareconstants(lc f, lc g);
  150. if answ neq 'equal then return answ;
  151. return totalcompareconstants(red f, red g)
  152. end;
  153. procedure wusort polylist;
  154. % sort a list of polys into Wu order
  155. sort(polylist, 'wulessp!*);
  156. procedure collectvars polylist;
  157. % make a list of the variables appearing in the list of polys
  158. begin scalar varlist;
  159. varlist := for each poly in polylist conc collectpolyvars poly;
  160. return sort(union(varlist, nil), 'symbollessp)
  161. end;
  162. procedure collectpolyvars poly;
  163. collectpolyvarsaux(poly, nil);
  164. procedure collectpolyvarsaux(poly, sofar);
  165. if domainp poly then sofar
  166. else union(
  167. union(sofar, list mvar poly),
  168. union(collectpolyvarsaux(lc poly, nil),
  169. collectpolyvarsaux(red poly, nil)));
  170. procedure pickbasicset polylist;
  171. % find a basic set from the ordered list of polys
  172. begin scalar basicset;
  173. foreach var in wuvarlist!* do <<
  174. while polylist and symbollessp(mvar car polylist, var) do
  175. polylist := cdr polylist;
  176. while polylist and var = mvar car polylist and
  177. not wureducedpolysp(car polylist, basicset) do
  178. polylist := cdr polylist;
  179. if polylist and var = mvar car polylist then <<
  180. basicset := car polylist . basicset;
  181. polylist := cdr polylist
  182. >>
  183. >>;
  184. return reversip basicset
  185. end;
  186. procedure wupseudodivide(f, g, x);
  187. % not a true pseudo divide---multiply f by the smallest power
  188. % of lc g necessary to make a fraction-free division
  189. begin scalar origf, oldkord, lcoeff, degf, degg, answ, fudge;
  190. origf := f;
  191. oldkord := setkorder list x;
  192. f := reorder f;
  193. if wuconstantp f or mvar f neq x then <<
  194. setkorder oldkord;
  195. return nil . origf
  196. >>;
  197. g := reorder g;
  198. if wuconstantp g or mvar g neq x then <<
  199. f := multf(f, quotf(g, gcdf!*(lc f, g)));
  200. setkorder oldkord;
  201. return reorder f . nil
  202. >>;
  203. degf := ldeg f;
  204. degg := ldeg g;
  205. if degf - degg + 1 < 0 then <<
  206. setkorder oldkord;
  207. return nil . origf
  208. >>;
  209. lcoeff := lc g;
  210. lcoeff := exptf(lcoeff, degf - degg + 1);
  211. answ := qremf(multf(lcoeff, f), g);
  212. fudge := gcdf!*(gcdf!*(lcoeff, cdr answ), car answ);
  213. answ := quotf(car answ, fudge) . quotf(cdr answ, fudge);
  214. setkorder oldkord;
  215. return reorder car answ . reorder cdr answ;
  216. end;
  217. procedure simpwupseudodivide u;
  218. begin scalar f, g, x, answ;
  219. f := !*a2f car u;
  220. g := !*a2f cadr u;
  221. x := if cddr u then !*a2k caddr u else mvar f;
  222. answ := wupseudodivide(f, g, x);
  223. return list('list, mk!*sq !*f2q car answ,
  224. mk!*sq !*f2q cdr answ)
  225. end;
  226. put('wudiv, 'psopfn, 'simpwupseudodivide);
  227. procedure findremainder(f, polylist);
  228. % form the Wu-remainder of f wrt those polys in polylist
  229. << foreach poly in polylist do
  230. f := cdr wupseudodivide(f, poly, mvar poly);
  231. f
  232. >>;
  233. procedure prin2t!* u;
  234. % a useful procedure
  235. << prin2!* u;
  236. terpri!* t
  237. >>;
  238. procedure chrstrem polylist;
  239. % polylist a list of polynomials, to be Wu'd
  240. % horrible circumlocutions here
  241. begin scalar revbasicset, pols, rem, remainders;
  242. if !*trwu or !*trchrstrem then <<
  243. terpri!* t;
  244. prin2t!* "--------------------------------------------------------";
  245. >>;
  246. repeat <<
  247. polylist := wusort polylist;
  248. if !*trwu or !*trchrstrem then <<
  249. prin2t!* "The new pol-set in ascending order is";
  250. foreach poly in polylist do printsf poly;
  251. terpri!* t;
  252. >>;
  253. if wuconstantp car polylist then <<
  254. if !*trwu then prin2t!* "which is trivially trivial";
  255. remainders := 'inconsistent;
  256. revbasicset := list 1;
  257. >>
  258. else <<
  259. remainders := nil;
  260. % Keep in reverse order.
  261. revbasicset := reversip pickbasicset polylist;
  262. >>;
  263. if !*trwu and null remainders then <<
  264. prin2t!* "A basic set is";
  265. foreach poly in reverse revbasicset do printsf poly;
  266. terpri!* t;
  267. >>;
  268. pols := setdiff(polylist, revbasicset);
  269. foreach poly in pols do
  270. if remainders neq 'inconsistent then <<
  271. if !*trwu then <<
  272. prin2!* "The remainder of ";
  273. printsf poly;
  274. prin2!* "wrt the basic set is "
  275. >>;
  276. rem := findremainder(poly, revbasicset);
  277. if !*trwu then <<
  278. printsf rem;
  279. >>;
  280. if rem then
  281. if wuconstantp rem then <<
  282. remainders := 'inconsistent;
  283. if !*trwu then <<
  284. prin2t "which is a non-zero constant, and so";
  285. prin2t "the equations are inconsistent."
  286. >>
  287. >>
  288. else remainders := union(list absf rem, remainders);
  289. >>;
  290. if remainders and remainders neq 'inconsistent then
  291. polylist := append(polylist, remainders)
  292. >> until null remainders or remainders = 'inconsistent;
  293. if remainders = 'inconsistent then revbasicset := list 1;
  294. if !*trwu or !*trchrstrem then <<
  295. terpri!* t;terpri!* t;
  296. prin2t!* "The final characteristic set is:";
  297. foreach poly in reverse revbasicset do printsf poly
  298. >>;
  299. return reversip foreach poly in revbasicset collect absf poly
  300. end;
  301. procedure simpchrstrem u;
  302. begin scalar answ, polylist, wuvarlist!*;
  303. polylist := foreach f in u collect !*a2f f;
  304. wuvarlist!* := colectvars polylist;
  305. answ := chrstrem polylist;
  306. return 'list . foreach f in answ collect mk!*sq !*f2q f;
  307. end;
  308. put('chrstrem, 'psopfn, 'simpchrstrem);
  309. procedure wu(polylist, varlist);
  310. % Do the Wu algorithm.
  311. % Vars in varlist arranged in increasing order.
  312. % Return (((poly, poly, ... ) . initial) ... ), a list of characteristic
  313. % sets dotted onto the product of their initials.
  314. % Very parallelizable.
  315. begin scalar stufftodo, answ, polset, chrset, initialset, initial,
  316. wuvarlist!*;
  317. stufftodo := list delete(nil,
  318. union(foreach poly in polylist collect absf poly,
  319. nil));
  320. if null car stufftodo then <<
  321. if !*trwu then prin2t!* "trivial CHS";
  322. return list(list nil . 1);
  323. >>;
  324. if null varlist then <<
  325. if !*trwu then prin2t!* "trivial CHS";
  326. return list(list 1 . 1);
  327. >>;
  328. wuvarlist!* := varlist;
  329. while stufftodo do <<
  330. polset := wusort car stufftodo;
  331. stufftodo := cdr stufftodo;
  332. chrset := chrstrem polset;
  333. if chrset neq '(1) then <<
  334. initialset := foreach pol in chrset collect wuinitial pol;
  335. initial := 1;
  336. foreach pol in initialset do initial := multf(initial, pol);
  337. if !*trwu then <<
  338. prin2!* "with initial ";
  339. printsf initial;
  340. >>;
  341. if member(initial, chrset) then <<
  342. if !*trwu then prin2t!*
  343. "which we discard, as the initial is a member of the CHS";
  344. >>
  345. else answ := union(list(chrset . initial), answ);
  346. foreach initial in initialset do
  347. if not wuconstantp initial then <<
  348. if member(initial, polset) then <<
  349. prin2t!*
  350. "*** Something awry: the initial is a member of the polset";
  351. answ := union(list(polset . 1), answ) % unsure of this one.
  352. >>
  353. else stufftodo := union(list wusort(initial . polset),
  354. stufftodo)
  355. >>
  356. >>
  357. >>;
  358. if null answ then answ := list(list 1 . 1);
  359. if !*trwu then <<
  360. terpri!* t;terpri!* t;
  361. prin2t!* "--------------------------------------------------------";
  362. prin2t!* "Final result:";
  363. foreach zset in answ do <<
  364. prin2t!* "Ascending set";
  365. foreach f in car zset do printsf f;
  366. prin2!* "with initial ";
  367. printsf cdr zset;
  368. terpri!* t
  369. >>
  370. >>;
  371. return answ;
  372. end;
  373. procedure simpwu u;
  374. % rebind kord* to reflect the wu order of kernels
  375. begin scalar pols, vars, oldkord, answ, nargs;
  376. nargs := length u;
  377. if nargs = 0 or nargs > 2 then
  378. rederr "Wu called with wrong number of arguments";
  379. pols := aeval car u;
  380. if nargs = 2 then vars := aeval cadr u;
  381. if (nargs = 1 and not eqcar(pols, 'list)) or
  382. (nargs = 2 and not eqcar(vars, 'list)) then
  383. rederr "Wu: syntax wu({poly, ...}) or wu({poly, ...}, {var, ...})";
  384. oldkord := kord!*;
  385. if nargs = 1 then
  386. begin scalar kord!*, polset, vars;
  387. kord!* := if wukord!* then reverse wukord!* else oldkord;
  388. polset := foreach f in cdr pols collect reorder !*a2f f;
  389. vars := collectvars polset;
  390. if !*trwu then <<
  391. terpri!* t;
  392. prin2!* "Wu variables in decreasing order: ";
  393. foreach id in reverse vars do <<
  394. prin2!* id;
  395. prin2!* " "
  396. >>;
  397. terpri!* t
  398. >>;
  399. answ := wu(polset, vars)
  400. end
  401. else % nargs = 2
  402. begin scalar kord!*, polset, wukord!*;
  403. kord!* := foreach k in cdr vars collect !*a2k k;
  404. wukord!* := reverse kord!*;
  405. polset := foreach f in cdr pols collect reorder !*a2f f;
  406. answ := wu(polset, wukord!*)
  407. end;
  408. return 'list . foreach zset in answ collect
  409. 'list . list('list . foreach f in car zset collect
  410. mk!*sq !*f2q absf reorder f,
  411. mk!*sq !*f2q absf reorder cdr zset)
  412. end;
  413. put('wu, 'psopfn, 'simpwu);
  414. remprop('wu, 'number!-of!-args);
  415. %procedure wukord u;
  416. %% hack to specify order of kernels in Wu
  417. %% wukord a,y,x => other kernels < a < y < x
  418. % wukord!* := if u = '(nil) then nil
  419. % else foreach x in u collect !*a2k x;
  420. %
  421. %rlistat '(wukord);
  422. algebraic;
  423. endmodule;
  424. end;