groesolv.red 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. module groesolv; % Tools for solving systems of polynomials (and poly-
  2. % % nomial equations) based on Groebner basis techniques.
  3. % Authors: H.Melenk (ZIB Berlin)
  4. % H.M Moeller (Fernunversitaet Hagen)
  5. % W.Neun (ZIB Berlin)
  6. %
  7. % Aug 1992: accepting external solutions for univariate pols.
  8. %
  9. % March 1994: access to roots/multroot.
  10. %
  11. % Feb 1995: assumptions, requirements added.
  12. % operators:
  13. %
  14. % GROESOLVE does the whole job of solving a nonlinear
  15. % set of expressions and / or equations
  16. %
  17. % GROEPOSTPROC expects that its car parameter is a
  18. % lexical groebner base already
  19. fluid '(groesolvelvevel!* !*groebprereduce);
  20. fluid '(groesoldb!* groesoldmode!* !*groebnumval !*groebcomplex
  21. !*groebopt !*groebprot !*groesolrecurs
  22. !*groesolgarbage denominators!* variables!*
  23. groebroots!* % a-list for predefined root expressions
  24. depl!* % the reduce dependency list
  25. !*vdpinteger % coefficient mode
  26. !*compxroots % switch for multroot
  27. gmodule
  28. !*arbvars
  29. );
  30. fluid '(!*convert !*ezgcd !*msg !*precise dmode!* !*varopt);
  31. global '(groebprotfile gvarslast !*trgroesolv glterms assumptions
  32. requirements);
  33. groesolvelvevel!* := 0;
  34. symbolic procedure groesolveeval u;
  35. begin scalar !*ezgcd,GBlist,oldtorder,res,!*groebopt,!*precise,
  36. y,fail,problems,denominators!*,variables!*,gmodule,at;
  37. if null dmode!* then !*ezgcd := t;
  38. !*groebopt := !*varopt; gvarslast :='(list);
  39. oldtorder := apply1('torder,'(lex));
  40. groesoldmode!* := get(dmode!*,'dname);
  41. !*groebcomplex := !*complex;
  42. groesetdmode(groesoldmode!*,NIL);
  43. problems:={u};
  44. while problems and not fail do
  45. <<u:=car problems; problems:=cdr problems;
  46. GBlist := cdr GroebnerFeval u;
  47. at := union(at,cdr glterms);
  48. !*groebopt := nil; % 29.8.88
  49. groesetdmode(groesoldmode!*,T);
  50. if null variables!* then variables!*:=gvarslast;
  51. if not(Gblist = '((list 1))) then
  52. for each gb in GBlist do
  53. <<if !*trgroesolv then
  54. <<writepri("starting from basis",'first);
  55. writepri(mkquote gb,'last)>>;
  56. for each r in res do if gb
  57. % do not compare with the mother problem;
  58. and not subsetp(car r,car u)
  59. then
  60. if groesolvidsubset!?(gb,car r,variables!*) then
  61. res:=delete(r,res) else
  62. if groesolvidsubset!?(car r,gb,variables!*) then
  63. <<gb:=nil;
  64. if !*trgroesolv then writepri("redundant",'only)
  65. >>;
  66. if gb then
  67. <<y:=groesolvearb(groesolve0(gb,variables!*),variables!*);
  68. if y neq 'failed then res:=(gb.y).res else fail:=t;
  69. if !*trgroesolv then
  70. <<writepri("partial result:",'first);
  71. writepri(mkquote('list.cdar res),'last)
  72. >>;
  73. for each d in denominators!* do
  74. problems:={append(gb,{d}),variables!*}.problems;
  75. denominators!*:=nil;
  76. >>;
  77. >>;
  78. >>;
  79. apply1('torder,{oldtorder});
  80. problems:=nil; if fail then res:=nil;
  81. if null res then requirements:=append(requirements,at)
  82. else assumptions := append(assumptions,at);
  83. for each r in res do problems:=union(cdr r,problems);
  84. return 'list . groesolve!-redun2 problems
  85. end;
  86. symbolic procedure groesolve!-redun2 sol;
  87. % Sol is a list of solutions; remove redundancies, now not
  88. % by ideal theory but by simple substitution.
  89. begin scalar b;
  90. for each s in sol do
  91. if s memq sol then
  92. <<b:=nil;
  93. for each r in sol do
  94. if not(r eq s) then
  95. if not b and groesolve!-redun2a(r,s) then b:=r;
  96. if b then sol:=delete(s,sol);
  97. >>;
  98. return sol;
  99. end;
  100. symbolic procedure groesolve!-redun2a(r,s);
  101. % redundancy test: if sub(s,r)=> trivial then t because s
  102. % is a special case of r.
  103. if smemq('root_of,s) then nil else
  104. begin scalar q,!*evallhseqp,!*protfg;
  105. !*evallhseqp:=t; !*protfg:=t;
  106. q:=errorset({'subeval,mkquote {s,r}},nil,nil);
  107. if errorp q then <<erfg!*:=nil;return nil>>;
  108. q:=cdar q;
  109. while q and 0=reval{'difference,cadar q,caddar q} do q:=cdr q;
  110. return null q;
  111. end;
  112. symbolic procedure groesolvidsubset!?(b1,b2,vars);
  113. % test if ideal(b1) is a subset of ideal(b2)
  114. % (b2 is a specialization of b1 wrt zeros).
  115. null b1 or (car b1='list or 0=preduceeval{car b1,b2,vars}) and
  116. groesolvidsubset!?(cdr b1,b2,vars);
  117. symbolic procedure groesolvearb(r,vars);
  118. % Cover unmentioned variables.
  119. if atom r or not !*arbvars then r else
  120. for each s in r collect
  121. <<for each x in cdr vars do
  122. if not smember(x,s) then
  123. s:=append(s,{{'equal,x,prepf makearbcomplex()}});
  124. s>>;
  125. %------------------- driver for the postprocessor ----------------
  126. symbolic procedure groesolve0(A,vars);
  127. begin scalar r,ids,newvars,newA;
  128. if(r:=groepostnumsolve(A,vars))then return r;
  129. if(r:=groepostfastsolve(A,vars))then return r;
  130. r:=groepostsolveeval{A,vars};
  131. if r neq 'failed then return cdr r;
  132. ids:=cdr gindependent_seteval{A,vars};
  133. if null ids then goto nullerr;
  134. ids:=car ids;
  135. newvars:='list.for each x in cdr vars join
  136. if not(x memq ids) then {x};
  137. newA:=groebnereval{A,newvars};
  138. denominators!*:=cdr glterms;
  139. if newA='(list 1) then rerror(groebner,24,
  140. "recomputation for dim=0 failed");
  141. r:=groepostfastsolve(newA,newvars);
  142. if r then return r;
  143. r:=groepostsolveeval{A,vars};
  144. if r neq 'failed then return cdr r;
  145. nullerr:
  146. rerror(groebner,23,
  147. "Moeller ideal decomposition failed with 0 dim ideal");
  148. end;
  149. symbolic procedure groepostnumsolve(gb,vars);
  150. if not errorp errorset('(load!-package 'roots2),nil,nil)
  151. and getd 'multroot0
  152. and get(dmode!*,'dname) member '(ROUNDED COMPLEX!-ROUNDED)
  153. and length gb = length vars and groepostnumsolve1(gb,vars)
  154. then (cdr reval multroot0(precision 0,gb)) where !*compxroots=t;
  155. symbolic procedure groepostnumsolve1(gb,vars);
  156. if null gb then t else
  157. groepostnumsolve1(cdr gb,cdr vars) and
  158. <<for each x in kernels numr simp car gb do q:=q and x member vars;
  159. q>> where q=t;
  160. symbolic procedure groepostfastsolve(gb,vars);
  161. % try to find a fast solution.
  162. begin scalar u,p1,p2,fail,kl,res;
  163. if !*trgroesolv then prin2t "fast solve attempt";
  164. groesoldmode!* := get(dmode!*,'dname);
  165. !*groebnumval := member(groesoldmode!* ,
  166. '(ROUNDED COMPLEX!-ROUNDED));
  167. groesetdmode(groesoldmode!*,'NIL);
  168. u:=kl:=for each p in cdr gb collect
  169. <<p:=numr simp p;
  170. intersection(vars,kernels p).p>>;
  171. if u='((nil)) then goto trivial;
  172. while u and cdr u do
  173. <<p1:=car u; p2:=cadr u; u:= cdr u;
  174. car p1:=setdiff(car p1,car p2);
  175. fail:=fail or null car p1>>;
  176. if fail then goto exit;
  177. res:= for each r in groepostfastsolve1(reverse kl,nil,0)
  178. collect 'list.reverse r;
  179. goto exit;
  180. trivial:
  181. res:= {'list.for each x in cdr vars collect
  182. {'equal,x,mvar makearbcomplex()}};
  183. exit:
  184. groesetdmode(groesoldmode!*,t);
  185. return res;
  186. end;
  187. fluid '(f);
  188. symbolic procedure groepostfastsolve1(fl,sub,n);
  189. if null fl then '(nil) else
  190. begin scalar u,f,v,sub1;
  191. n:=n+1;
  192. f:=car fl; v:=car f; f:=numr subf(cdr f,sub);
  193. if null f then return groepostfastsolve1(cdr fl,sub,n);
  194. % v:=car sort(v,function(lambda(x,y);degr(f,x)>degr(f,y)));
  195. v := car v;
  196. (f:=reorder f) where kord!*={v};
  197. if not domainp lc f then groepostcollectden reorder lc f;
  198. u:=groesolvePolyv(prepf f,v);
  199. return for each s in u join
  200. <<sub1:=if smemq('root_of,s) then sub else
  201. (v . caddar s) . sub;
  202. for each q in groepostfastsolve1(cdr fl,sub1,n) collect
  203. car s.q
  204. >>;
  205. end;
  206. unfluid '(f);
  207. symbolic procedure groepostcollectden d;
  208. % d is a non trivial denominator (standard form);
  209. % collect its factors.
  210. for each p in cdr fctrf d do
  211. if not member(p:=prepf car p,denominators!*) then
  212. denominators!*:=p.denominators!*;
  213. put('groesolve,'psopfn,'groesolveeval);
  214. symbolic procedure groepostsolveeval u;
  215. begin scalar a,b,vars,oldorder;
  216. scalar groesoldb!*;
  217. scalar !*groebprereduce,!*groebopt,!*groesolgarbage;
  218. groesoldmode!* := get(dmode!*,'dname);
  219. groesetdmode(groesoldmode!*,'NIL);
  220. !*groebnumval := member(groesoldmode!* ,
  221. '(ROUNDED COMPLEX!-ROUNDED));
  222. if vdpsortmode!* = 'LEX then t else
  223. rerror(groebner,8,
  224. "Groepostproc, illegal torder; (only LEX allowed)");
  225. a := groerevlist reval car u;
  226. vars := cdr u and groerevlist cadr u or groebnervars(a,nil);
  227. oldorder := setkorder vars;
  228. b := groesolve1(a,a,vars);
  229. a := NIL;
  230. if b eq 'failed then a:=b else
  231. <<for each sol in b do % delete multiplicities
  232. if not member(sol,a) then a := sol . a;
  233. a := 'list . for each sol in a collect 'list . sol;
  234. >>;
  235. setkorder oldorder;
  236. groesetdmode(groesoldmode!*,t);
  237. return a;
  238. end;
  239. put('groepostproc ,'psopfn,'groepostsolveeval);
  240. % DATA structure:
  241. %
  242. % all polynomials are held in prefix form (expressions)
  243. % transformation to standard quotients/ standard forms is done locally
  244. % only; distributive form is not used here.
  245. %
  246. % a zero is a set of equations, if possible with a variable on the
  247. % lhs each
  248. % e.g. {y=17,z=b+8};
  249. % internally: ((equal y 17)(equal z (plus b 8)))
  250. % a zeroset is a list of zeros
  251. % elgl {{y=17,z=b+8},{y=17,z=b-8}}
  252. % internally the sets (lists) are kept untagged as lists; the
  253. % tag 'list is only added to the results and to those lists which
  254. % are parameters to algebraic operators not in this package.
  255. symbolic procedure groesolve1 (A,fullA,vars);
  256. % A lex Groebner basis or tail of lex Groebner basis
  257. % fullA the complete lex Groebner basis to A
  258. % vars the list of variables
  259. if null A or A='(1) then nil else
  260. <<begin scalar f1,A1,res,Q,gi,Ng1,Ng2,NgQ,Qg,mv,test;
  261. res := assoc (A,groesoldb!*); if res then return cdr res;
  262. groesolvelvevel!* := groesolvelvevel!* + 1;
  263. %%tr prin2t "=================================================";
  264. %%tr prin2l list( " groesolvelvevel!*: ",groesolvelvevel!*);
  265. %%tr prin2t " Problem:";
  266. %%tr writepri (mkquote ('list . a),'only);;
  267. if member(A,!*groesolrecurs) then return 'failed;
  268. % <<vars := append(cdr vars,{car vars});
  269. % if member(vars,!*groesolrecurs) then
  270. % <<!*groesolgarbage := T;
  271. % return list for each p in A collect list('EQUAL,p,0) >>;
  272. % !*groesolrecurs := vars . !*groesolrecurs;
  273. % A := cdr Groebnereval{'list.A,'list . vars};
  274. % >>;
  275. !*groesolrecurs := A . !*groesolrecurs;
  276. if length A = 1 then
  277. << %%tr print "single polynomial; solve it";
  278. res := groesolvePoly car A; goto ready>>;
  279. % step 1
  280. f1 := car A;
  281. A1 := cdr A;
  282. test := nil;
  283. mv := intersection(vars,LtermVariables f1); % test Buchcrit 4
  284. for each p in A1 do
  285. if intersection (mv,LtermVariables p) then test := T;
  286. if not test then
  287. << %%tr print "f1 has unique main variable";
  288. NgQ := groesolve1(A1,A1,vars);
  289. if NgQ eq 'failed then <<res:='failed;goto ready>>;
  290. res := ZerosetIntersection(NgQ,f1,vars);
  291. goto ready>>;
  292. % Q := cdr GroebIdq('list . A1,f1,'list . vars); % A1:f1
  293. Q := GroesolvIdq(A1,f1,vars);
  294. %%tr print "A1:f1"; %%tr writepri (mkquote ('list . Q),'only);;
  295. if Q='(1) then % f1 already member of A1; skip it
  296. <<%%tr print "f1 already in A1; ignore";
  297. res:= groesolve1(A1,fullA,vars);
  298. goto ready>>;
  299. NgQ := groesolve1(Q,Q,vars);
  300. if NgQ eq 'failed then <<res:='failed;goto ready>>;
  301. ng1 := ZerosetIntersection (NgQ,f1,vars);
  302. % step 4
  303. if GroesolvIdqTest(A1,f1,vars) then
  304. << while Q do
  305. << gi := car Q; Q := cdr Q;
  306. gi := preduceeval list (gi , 'list . A, 'list . vars);
  307. if gi = 0 then Q:= nil else
  308. A := cdr GroebIdq('list . A ,gi,'list . vars);
  309. >>;
  310. Ng2 := groesolve1(A,A,vars);
  311. if Ng2 eq 'failed then <<res:='failed;goto ready>>;
  312. >> else
  313. <<Ng2 := ();
  314. if length Q = 1 then
  315. << gi := preduceeval list (car Q, 'list . fullA, 'list . vars);
  316. if gi neq 0 then
  317. << Qg := cdr GroebIdq('list . fullA,gi,'list . vars); % A1:gi
  318. Ng2 := groesolve1(Qg,Qg,vars);
  319. if Ng2 eq 'failed then <<res:='failed;goto ready>>;
  320. >> >>
  321. else
  322. <<Ng2 := groesolve2(A1,Q,vars);
  323. if Ng2 eq 'failed then <<res:='failed;goto ready>>
  324. >>
  325. >>;
  326. res:= ZerosetUnion (Ng1,Ng2);
  327. ready:
  328. %%tr print list( "Result, level!*: ",groesolvelvevel!*);
  329. %%tr writeres res;
  330. %%tr print "...................................................";
  331. groesolvelvevel!* := groesolvelvevel!* -1;
  332. groesoldb!* := (a . res) . groesoldb!*;
  333. return res;
  334. end
  335. >> where !*groesolrecurs = !*groesolrecurs; % recursive fluid!
  336. symbolic procedure GroesolvIdqTest(A1,f1,vars);
  337. not(deg(f1,car vars) eq deg(car A1,car vars));
  338. symbolic procedure GroesolvIdq(A1,f1,vars);
  339. begin scalar x,temp;
  340. x := car vars;
  341. if not GroesolvIdqTest(A1,f1,vars)
  342. then return cdr GroebIdq('list . A1,f1,'list . vars);
  343. temp :=
  344. for each p in A1 collect
  345. reval car reverse coeffeval list(p,x);
  346. return cdr groebnereval list ('list . temp,'list . vars);
  347. end;
  348. symbolic procedure groesolve2(A,Q,vars);
  349. % Calculation of the zeroset A1:(g1,g2,,,,gs),
  350. % the gi given as members of Q.
  351. groesolvetree (A,Q,Q,vars);
  352. symbolic procedure groesolvetree(A,T1,phi,vars);
  353. begin scalar Q,NGtemp,NGall,T2,h,g,A2,phi2;
  354. %%tr prin2t ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>";
  355. %%tr prin2t "groesolvetree; A:";
  356. %%tr writepri(mkquote ('list . a),'only);
  357. %%tr writepri( "T1 :",'car);
  358. %%tr writepri(mkquote ('list . T1) ,'last);
  359. %%tr writepri( "phi:",'car);
  360. %%tr writepri(mkquote ('list . phi),'last);
  361. if null phi then return nil else
  362. if null T1 then
  363. <<Q := cdr GroebIdq('list.A, 'TIMES.phi,'list.vars);
  364. %%tr prin2t "<< << << << << << << << << << << << << <<<";
  365. return if car Q = 1 then nil
  366. else groesolve1(Q,Q,vars) >>;
  367. for each g in T1 do
  368. <<h:=Preduceeval list(g,'LIST.A,'LIST.vars);
  369. phi := delete(g,phi);
  370. if not(h=0) then <<T2:=h.T2; phi:=h.phi>>;
  371. >>;
  372. if null phi then return nil; % 29.8.88
  373. T1 := T2;
  374. Q := cdr GroebIdq('list.A, 'TIMES.phi,'list.vars);
  375. %%tr writepri( "PHI :",'car);
  376. %%tr writepri(mkquote ('TIMES.phi) ,'last);
  377. %%tr writepri( "A:PHI :",'car);
  378. %%tr writepri(mkquote ('LIST.Q) ,'last);
  379. if not(car Q = 1) then
  380. << NGall := groesolve1(Q,Q,vars);
  381. if NGall eq 'failed then return 'failed;
  382. >>;
  383. if !*groesolgarbage then
  384. return groesolverestruct(Q,phi,vars,NGall);
  385. while T1 do
  386. <<g:=car T1; T1:=cdr T1;
  387. phi2 := delete(g,phi);
  388. if phi2 then
  389. <<A2 := cdr Groebnereval list('LIST . g . A,'LIST . vars);
  390. if not(car A2 =1) then
  391. <<NGtemp := groesolvetree(A2,T1,phi2,vars);
  392. NGall := ZerosetUnion(NGtemp,NGall)>>;
  393. >>>>;
  394. %%tr prin2t "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<";
  395. return NGall;
  396. end;
  397. symbolic procedure groesolverestruct(A,phi,vars,NGall);
  398. % there was a problem with an embedded solution in phi such that
  399. % A:phi = A
  400. % we try a heuristic by making one variable a formal parameter
  401. begin scalar newA,newvars,mv,oldorder,solu;
  402. mv := LtermVariables ('TIMES.phi);
  403. mv := car mv;
  404. %%tr prin2 "groesolverestruct:taking variable ";prin2t mv;
  405. newvars := delete(mv,vars);
  406. oldorder := setkorder newvars;
  407. newA := cdr GroebnerEval list('LIST . A,'LIST . newvars);
  408. %%tr prin2t "new Groebner basis:";
  409. %%tr writepri(mkquote ('LIST . newA),'ONLY);
  410. !*groesolgarbage := NIL;
  411. solu := groesolve1(newA,newA,newvars);
  412. %%tr if !*groesolgarbage then prin2t "Heuristics failed"
  413. %%tr else prin2t "better result";
  414. setkorder oldorder;
  415. return if !*groesolgarbage then NGall else solu;
  416. end;
  417. %%tr symbolic procedure writeres r;
  418. %%tr writepri (mkquote ('list.for each x in r collect 'list.x),'ONLY);
  419. symbolic procedure LtermVariables u;
  420. % extract variables of leading term in u
  421. begin scalar v;
  422. u := numr simp u;
  423. while not domainp u do
  424. <<v := mvar u . v;
  425. u := lc u>>;
  426. return reversip v;
  427. end;
  428. symbolic procedure ZerosetIntersection (NG,poly,vars);
  429. % NG is a zeroset
  430. % poly is a polynomial
  431. % the routine maps the zeros in NG by the polynomial:
  432. % each zero is substituted into the polynomial;
  433. % that gives a univariate
  434. % solved by SOLVE or numerical techniques.
  435. % the result is the solution NG, including the solutions of the
  436. % polynomial.
  437. begin scalar res,ns,testpoly,ppoly,sol,s,var,dom;
  438. %%tr print "Intersection ";
  439. %%tr writepri (mkquote ('list . NG),'only);
  440. %%tr print " with ";
  441. %%tr writepri(mkquote poly,'only);
  442. res := ();
  443. poly := simp poly;
  444. var:=if not domainp numr poly then groesolmvar(numr poly,vars)
  445. else 'constant;
  446. loop:
  447. if NG=() then goto finish;
  448. ns := car NG; NG := cdr NG;
  449. testpoly := poly;
  450. dom := groesoldmode!* or 'RATIONAL;
  451. groesetdmode(dom,T);
  452. testpoly := simp prepsq testpoly;
  453. for each u in ns do
  454. if idp lhs u and not smemq('root_of,rhs u) then
  455. <<s := rhs u;
  456. testpoly := subsq(testpoly,list (lhs u . s));
  457. >>;
  458. groesetdmode(dom,nil);
  459. ppoly := prepf numr testpoly;
  460. sol := groesolvePolyv(ppoly,var);
  461. res := append(res , for each r in sol collect append(r,ns) ) ;
  462. goto loop;
  463. finish:
  464. %%tr print "Schnittresultat: ";
  465. %%tr writeres res;
  466. return res;
  467. end;
  468. symbolic procedure groesolmvar(poly,vars);
  469. % select main variable wrt vars sequence.
  470. <<while vars and not smember(car vars,poly) do
  471. vars:=cdr vars;
  472. if null vars then rerror('groebner,27,"illegal poly");
  473. car vars>>;
  474. % solving a single polynomial with respect to its main variable
  475. symbolic procedure groeSolvePoly p; groesolvePolyv(p,mainvar p);
  476. symbolic procedure groesolvePolyv(p,var);
  477. % find the zeros for one polynomial p in the
  478. % variable "var".
  479. % current dmode is NIL.
  480. (begin scalar res,u,!*convert,y,z;
  481. if (u:=assoc(var,depl!*)) then depl!*:=delete(u,depl!*);
  482. if !*trgroesolv then
  483. <<writepri(" solving univariate with respect to ",'first);
  484. writepri(mkquote var,'last);
  485. writepri(mkquote p,'only);
  486. >>;
  487. for each s in groebroots!* do
  488. if 0=reval{'difference,p,car s} then res:=cdr s;
  489. if res then return res;
  490. groesetdmode(groesoldmode!*,T);
  491. u := numr simp p;
  492. res := if !*groebnumval and UnivariatePolynomial!? u
  493. then groeroots(p,var)
  494. else (solveeval list (p,var))
  495. where kord!*=nil,
  496. alglist!* = nil . nil;
  497. res := cdr res;
  498. % Collect nontrivial denominator factors.
  499. % Reorder for different local order during solveeval.
  500. for each x in res do
  501. <<y:=prepf (z:=reorder denr simp caddr x);
  502. if dependsl(y,variables!*) then groepostcollectden z;
  503. >>;
  504. res := for each x in res collect list x;
  505. groesetdmode(groesoldmode!*,NIL);
  506. return res;
  507. end) where depl!*=depl!*;
  508. symbolic procedure UnivariatePolynomial!? fm;
  509. domainp fm or UnivariatePolynomial!?1 (fm,mvar fm);
  510. symbolic procedure UnivariatePolynomial!?1 (fm,v);
  511. domainp fm or
  512. domainp lc fm and v = mvar fm and
  513. UnivariatePolynomial!?1(red fm,v);
  514. symbolic procedure predecessor (r,l);
  515. % looks for the predecessor of r in l
  516. if not pairp l or not pairp cdr l or r = car l
  517. then rerror(groebner,9,"No predecessor available") else
  518. if r = cadr l then car l else predecessor (r,cdr l);
  519. symbolic procedure ZerosetUnion(ng1,ng2);
  520. <<%print list( "union von ",ng1,ng2;
  521. ng1 := ZerosetUnion1(ng1,ng2);
  522. % print list( "-->",ng1);
  523. ng1>>;
  524. symbolic procedure ZerosetUnion1(ng1,ng2);
  525. % Vereinigung von Nullstellengebilden
  526. if ng1 = () then ng2
  527. else
  528. if ZerosetMember(car ng1,ng2) then ZerosetUnion1(cdr ng1,ng2)
  529. else
  530. car ng1 . ZerosetUnion1(cdr ng1,ng2);
  531. symbolic procedure ZerosetMember (ns,ng);
  532. if ng = () then nil else
  533. if ZeroEqual(ns,car ng) then ng else
  534. ZerosetMember (ns,cdr ng);
  535. symbolic procedure ZeroEqual(ns1,ns2);
  536. if Zerosubset(ns1,ns2) then Zerosubset(ns2,ns1) else nil;
  537. symbolic procedure Zerosubset(ns1,ns2);
  538. if null ns1 then T else
  539. if member(car ns1,ns2) then Zerosubset(cdr ns1,ns2)
  540. else nil;
  541. symbolic procedure groesetdmode(dmode,dir);
  542. % Interface for switching an arbitrary domain on/off.
  543. % Preserve complex mode. Turn on EZGCD whenever possible.
  544. if null dmode then nil else
  545. begin scalar !*msg,x,y;
  546. if null dir then
  547. << if !*complex then y:=setdmode('complex,nil);
  548. !*complex := nil;
  549. if dmode!* = '!:rd!: then !*rounded :=nil;
  550. if dmode!* then y:=setdmode(get(dmode!*,'dname),nil);
  551. if !*groebcomplex then
  552. <<setdmode('complex,t); !*complex:=t>>;
  553. >>
  554. else
  555. << if memq(dmode,'(complex complex!-rounded complex!-rational))
  556. then <<!*complex := t; y:=setdmode('complex,t);
  557. if (x:=atsoc(dmode,'((complex!-rounded . rounded)
  558. (complex!-rational . rational)) ))
  559. then y:=setdmode(cdr x,t)>>
  560. else y:=setdmode(dmode,t);
  561. if memq(dmode,'(rounded complex!-rounded)) then !*rounded :=t;
  562. >>;
  563. !*ezgcd := null dmode!*;
  564. return y;
  565. end;
  566. symbolic procedure preduceeval pars;
  567. % Polynomial reduction driver. u is an expression and v a list of
  568. % expressions. Preduce calculates the polynomial u reduced wrt the list
  569. % of expressions v.
  570. % parameters:
  571. % 1 expression to be reduced
  572. % 2 polynomials or equations; base for reduction
  573. % 3 optional: list of variables
  574. begin scalar vars,x,u,v,w,oldorder;
  575. scalar !*factor,!*exp,!*gsugar,!*vdpinteger;
  576. integer n,pcount!*; !*exp := t;
  577. if !*groebprot then groebprotfile := list 'LIST;
  578. n := length pars;
  579. x := reval car pars;
  580. u := reval cadr pars;
  581. v := if n>2 then reval caddr pars else nil;
  582. w := for each j in groerevlist u
  583. collect if eqexpr j then !*eqn2a j else j;
  584. if null w then rerror(groebnr2,3,"Empty list in Preduce");
  585. vars := groebnervars(w,v);
  586. if not vars then vdperr 'PREDUCE;
  587. oldorder := vdpinit vars;
  588. w := for each j in w collect a2vdp j;
  589. x := a2vdp x;
  590. if !*groebprot then
  591. <<w := for each j in w collect vdpenumerate j;
  592. groebprotSetq('CANDIDATE,vdp2a x);
  593. for each j in w do groebprotSetq(mkid('poly,vdpnumber j),
  594. vdp2a j)>>;
  595. w := groebNormalForm(x,w, 'sort);
  596. w := vdp2a w;
  597. setkorder oldorder;
  598. return if w then w else 0;
  599. end;
  600. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  601. %
  602. % the following code is the interface to Stan's rootfinder
  603. %
  604. symbolic procedure groeroots(p,x);
  605. begin scalar r;
  606. x := nil; r := reval{'roots,p};
  607. % re-evaluate rhs in order to get prefix form
  608. r := for each e in cdr r collect
  609. list('equal,cadr e,reval caddr e);
  610. return 'list . r;
  611. end;
  612. endmodule;
  613. end;