ofsfopt.red 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. % ----------------------------------------------------------------------
  2. % $Id: ofsfopt.red,v 1.6 1999/04/08 12:37:31 dolzmann Exp $
  3. % ----------------------------------------------------------------------
  4. % Copyright (c) 1995-1999 Andreas Dolzmann and Thomas Sturm
  5. % ----------------------------------------------------------------------
  6. % $Log: ofsfopt.red,v $
  7. % Revision 1.6 1999/04/08 12:37:31 dolzmann
  8. % Renamed switch rlsisqf to rlsiatadv.
  9. %
  10. % Revision 1.5 1999/03/23 07:41:38 dolzmann
  11. % Changed copyright information.
  12. %
  13. % Revision 1.4 1996/10/14 16:04:13 sturm
  14. % Bugfix: copied container code to this module.
  15. % Use DFS with !*rlqeheu on.
  16. %
  17. % Revision 1.3 1996/10/07 12:03:28 sturm
  18. % Added fluids for CVS and copyright information.
  19. %
  20. % Revision 1.2 1996/07/15 13:29:07 sturm
  21. % Modified data structure descriptions for automatic processing.
  22. %
  23. % Revision 1.1 1996/03/22 12:14:12 sturm
  24. % Moved and split.
  25. %
  26. % ----------------------------------------------------------------------
  27. lisp <<
  28. fluid '(ofsf_opt_rcsid!* ofsf_opt_copyright!*);
  29. ofsf_opt_rcsid!* := "$Id: ofsfopt.red,v 1.6 1999/04/08 12:37:31 dolzmann Exp $";
  30. ofsf_opt_copyright!* := "Copyright (c) 1995-1999 by A. Dolzmann and T. Sturm"
  31. >>;
  32. module ofsfopt;
  33. % Ordered field standard form optimization. Submodule of [ofsf].
  34. smacro procedure ofsf_cvl(x);
  35. car x;
  36. smacro procedure ofsf_al(x);
  37. cadr x;
  38. smacro procedure ofsf_pl(x);
  39. caddr x;
  40. smacro procedure ofsf_an(x);
  41. cdddr x;
  42. smacro procedure ofsf_mkentry(cvl,al,pl,an);
  43. cvl . al . pl . an;
  44. procedure ofsf_sendtask(hd,p,z);
  45. remote_call!*(hd,'ofsf_opt2,{
  46. ofsf_cvl p,ofsf_al p,ofsf_pl p,ofsf_an p,z,nil,nil},1) ;
  47. procedure ofsf_optmaster(cvl,al,z,nproc);
  48. % Ordered field standard form optimization master. [cvl] is a list
  49. % $(x_1,...,x_n)$ of variables; [al] is a list of active constraints
  50. % already containg an artificial constraint that encodes the target
  51. % function $f(x_1,...,x_n)$; [z] is the identifier that serves as
  52. % artificial variable for optimization, [nproc] is a positive
  53. % integer, the number of slaves to use; it must be less than the
  54. % number of available processors. Returns a list containing a form
  55. % $(v . ((x_1 . p_1) ... (x_n . p_n)))$ where $v$ is the minimal
  56. % value of $f$ subject to the contraints, $(p_1,...,p_n)$ is one
  57. % point such that $f(p_1,...,p_n)=v$.
  58. begin scalar w,pbase,finl,fp,hdl,p,pending,sol,hd;
  59. pbase := ofsf_opt2(cvl,al,nil,nil,z,3*nproc) where !*rlqedfs=nil;
  60. remote_process nil;
  61. hdl := for i:=1:nproc collect pvm_mytid() + i;
  62. pvm_initsend(1);
  63. %% if !*rlverbose then ioto_prin2t {"handlel is ",hdl};
  64. fp := hdl;
  65. pending := nil;
  66. if !*rlverbose then ioto_tprin2t {"initial pbase size is ",length pbase};
  67. while pbase or pending do <<
  68. while pbase and fp do <<
  69. hd := car fp;
  70. fp := cdr fp;
  71. p := car pbase;
  72. pbase := cdr pbase;
  73. if !*rlverbose then ioto_prin2t {"sending task to ",land(hd,4095)};
  74. pending := (ofsf_sendtask(hd,p,z) . hd) . pending
  75. >>;
  76. if pending then <<
  77. if !*rlverbose then
  78. ioto_tprin2 {length pbase," problems left, waiting for ",
  79. for each x in pending collect land(cdr x,4095)," ... "};
  80. finl := remote_wait();
  81. if !*rlverbose then ioto_prin2t "ready";
  82. for each fin in finl do <<
  83. if (w := remote_receive(fin)) and
  84. (null sol or minusf numr subtrsq(car w,car sol))
  85. then
  86. sol := w;
  87. fp := cdr assoc(fin,pending) . fp;
  88. pending := delasc(fin,pending)
  89. >>
  90. >>
  91. >>;
  92. return sol
  93. end;
  94. %%procedure ofsf_optgen(cl,targ,sz,fn);
  95. %% begin scalar w,!*rlqedfs,!*rlsisqf;
  96. %% w := ofsf_opt1(cl,targ,nil);
  97. %% return ofsf_opt2(car w,cadr w,nil,nil,caddr w,sz,fn)
  98. %% end;
  99. procedure ofsf_opt(cl,targ,parml,nproc);
  100. begin scalar svrlqedfs,w;
  101. if !*rlqeheu then <<
  102. svrlqedfs := !*rlqedfs;
  103. !*rlqedfs := T
  104. >>;
  105. w := ofsf_opt0(cl,targ,parml,nproc);
  106. if !*rlqeheu then
  107. !*rlqedfs := svrlqedfs;
  108. return w
  109. end;
  110. procedure ofsf_opt0(cl,targ,parml,nproc);
  111. % Linear optimization. [cl] is a list of parameter-free linear
  112. % atomic formulas with weak ordering relation; [targ] is an SQ with
  113. % constant denominator; [parm] is a dummy argument; [nproc] is the
  114. % number of processors available. Returns [infeasible],
  115. % [-infinity], or a list $(\mu,l_1,...,l_n)$ where the $l_i$ are
  116. % lists of equations. Minimizes [targ] subject to [cl].
  117. begin scalar w,nproc,!*rlsiatadv,!*rlsiso;
  118. w := ofsf_opt1(cl,targ,parml);
  119. if !*rlparallel then
  120. return ofsf_optmkans ofsf_optmaster(car w,cadr w,caddr w,nproc - 1);
  121. return ofsf_optmkans ofsf_opt2(car w,cadr w,nil,nil,caddr w,nil)
  122. end;
  123. procedure ofsf_opt1(cl,targ,parml);
  124. begin scalar z,qvl;
  125. z := intern gensym();
  126. cl := ofsf_0mk2('geq,
  127. addf(multf(denr targ,numr simp z),negf numr targ)) . cl;
  128. qvl := setdiff(ofsf_varl cl,z . parml);
  129. return {qvl,cl,z}
  130. end;
  131. procedure ofsf_varl(l);
  132. begin scalar w;
  133. for each x in l do
  134. w := union(w,ofsf_varlat x);
  135. return w
  136. end;
  137. procedure ofsf_opt2(cvl,al,pl,an,z,sz);
  138. begin scalar w,co,ansl,junct,best,m,theo; integer c,vlv,nodes,dpth;
  139. if !*rlverbose and !*rlparallel then
  140. ioto_tprin2 "entering opt2 ... ";
  141. if !*rlverbose and !*rlqedfs and not !*rlparallel then <<
  142. dpth := length cvl;
  143. vlv := dpth / 4;
  144. ioto_tprin2t {"+++ Depth is ",dpth,", watching level ",dpth - vlv}
  145. >>;
  146. co := ofsf_save(co,{ofsf_mkentry(cvl,al,pl,an)});
  147. while co do <<
  148. w := ofsf_get(co); co := cdr w; w := car w;
  149. cvl := ofsf_cvl w; al := ofsf_al w; pl := ofsf_pl w; an := ofsf_an w;
  150. if !*rlverbose and not !*rlparallel then
  151. nodes := nodes + 1;
  152. if !*rlverbose and !*rlqedfs and eqn(vlv,length cvl) and
  153. not !*rlparallel
  154. then
  155. ioto_tprin2t {"+++ Crossing level ",dpth - vlv};
  156. if !*rlverbose and null !*rlqedfs and not !*rlparallel then <<
  157. if eqn(c,0) then <<
  158. c := ofsf_colength(co) + 1;
  159. ioto_tprin2t {"+++ ",length cvl," variables left for this block"}
  160. >>;
  161. ioto_prin2 {"[",c};
  162. c := c - 1
  163. >>;
  164. if !*rlverbose and !*rlqedfs and not !*rlparallel then
  165. ioto_prin2 {"[",dpth - length cvl};
  166. junct := ofsf_qevar(cvl,al,pl,an,z,theo);
  167. if junct eq 'break then
  168. co := nil
  169. else if junct and ofsf_cvl car junct then
  170. co := ofsf_save(co,junct)
  171. else <<
  172. if !*rlverbose and not !*rlparallel and null junct then
  173. ioto_prin2 "#";
  174. for each x in junct do <<
  175. if m := ofsf_getvalue(ofsf_al x,ofsf_pl x) then <<
  176. if ansl and (minusf (w := numr subtrsq(m,best)) or
  177. null w and !*rlopt1s)
  178. then
  179. ansl := nil;
  180. if null ansl or null w then <<
  181. best := m;
  182. theo := {ofsf_0mk2('leq,addf(
  183. multf(denr best,numr simp z),negf numr best))};
  184. ansl := ofsf_an x . ansl; % insert instead?
  185. if !*rlverbose and not !*rlparallel then
  186. ioto_tprin2t {"min=",numr m or 0,"/",denr m}
  187. >>
  188. >>
  189. >>;
  190. if !*rlverbose and !*rlqedfs and not !*rlparallel then
  191. ioto_prin2 "."
  192. >>;
  193. if !*rlverbose and not !*rlparallel then ioto_prin2 "] ";
  194. if sz and ofsf_colength co >= sz then <<
  195. if ansl then
  196. rederr "ofsf_opt2: found solutions during pbase generation";
  197. junct := 'pbase;
  198. ansl := cdr co;
  199. co := nil
  200. >>
  201. >>;
  202. if junct eq 'pbase then
  203. w := ansl
  204. else if junct eq 'break then
  205. w := junct
  206. else <<
  207. w := nil;
  208. for each x in ansl do
  209. w := lto_insert(ofsf_backsub(x,z,best),w);
  210. w := {best,w}
  211. >>;
  212. if !*rlverbose and not !*rlparallel then
  213. ioto_tprin2t {"+++ ",nodes," nodes computed"};
  214. if !*rlverbose and !*rlparallel then
  215. ioto_prin2t "exiting opt2";
  216. return w
  217. end;
  218. procedure ofsf_qevar(cvl,al,pl,an,z,theo);
  219. begin scalar w,v,an,eset;
  220. if (w := ofsf_optgauss(cvl,al,pl,an,theo)) then return cdr w;
  221. % elimination set method
  222. w := ofsf_opteset(cvl,al,pl,z);
  223. v := car w;
  224. eset := cdr w;
  225. if eset then << % [v] actually occurs in [f].
  226. if v eq z then <<
  227. if !*rlverbose and not !*rlparallel then ioto_prin2 "z";
  228. return ofsf_zesetsubst(cvl,al,pl,an,eset,theo)
  229. >>;
  230. if !*rlverbose and not !*rlparallel then ioto_prin2 "e";
  231. return ofsf_esetsubst(cvl,al,pl,an,v,eset,theo)
  232. >>;
  233. % [v] does not occur in [f]. Reinsert [f] with updated
  234. % variable list.
  235. if !*rlverbose then ioto_prin2 "*";
  236. if v memq ofsf_varl pl then <<
  237. if !*rlverbose and not !*rlparallel then ioto_prin2 "!";
  238. return nil % Maybe wrong!
  239. >>;
  240. return {ofsf_mkentry(delq(v,cvl),al,pl,an)}
  241. end;
  242. procedure ofsf_optgauss(cvl,al,pl,an,theo);
  243. begin scalar v,w,sc;
  244. sc := cvl;
  245. while sc do <<
  246. v := car sc;
  247. sc := cdr sc;
  248. if (w := ofsf_optfindeqsol(al,v)) then sc := nil
  249. >>;
  250. if w then <<
  251. if !*rlverbose and not !*rlparallel then ioto_prin2 "g";
  252. return T . ofsf_esetsubst(cvl,al,pl,an,v,{w},theo)
  253. >>
  254. end;
  255. procedure ofsf_optfindeqsol(al,v);
  256. begin scalar a,w;
  257. a := car al;
  258. if ofsf_op a eq 'equal and v memq ofsf_varlat a then <<
  259. w := ofsf_optmksol(ofsf_arg2l a,v);
  260. return a . quotsq(!*f2q car w,!*f2q cdr w)
  261. >>;
  262. if cdr al then
  263. return ofsf_optfindeqsol(cdr al,v)
  264. end;
  265. %DS
  266. % <eset> ::= (<entry>,...)
  267. % <entry> ::= (<atomic formula> . <standard quotient>)
  268. procedure ofsf_esetsubst(cvl,al,pl,an,v,eset,theo);
  269. begin scalar w,scpl,zonly,nal,npl,junct,x;
  270. cvl := delq(v,cvl);
  271. while eset do <<
  272. x := car eset;
  273. eset := cdr eset;
  274. if cdr x memq '(pinf minf) then <<
  275. nal := ofsf_simpl(for each atf in al collect
  276. ofsf_qesubiat(atf,v,cdr x),theo);
  277. npl := ofsf_simpl(for each atf in pl collect
  278. ofsf_qesubiat(atf,v,cdr x),theo)
  279. >> else <<
  280. nal := ofsf_simpl(for each y in al collect
  281. ofsf_optsubstat(y,cdr x,v),theo);
  282. npl := ofsf_simpl(for each y in pl collect
  283. ofsf_optsubstat(y,cdr x,v),theo);
  284. al := delq(car x,al);
  285. pl := car x . pl
  286. >>;
  287. if null nal and null npl then <<
  288. junct := 'break;
  289. eset := nil
  290. >> else if null nal then <<
  291. zonly := T;
  292. scpl := pl;
  293. while scpl do <<
  294. w := ofsf_varlat car scpl;
  295. scpl := cdr scpl;
  296. if w neq '(z) then scpl := zonly := nil
  297. >>;
  298. if zonly then rederr "BUG IN OFSF_ESETSUBST";
  299. if !*rlverbose and not !*rlparallel then ioto_prin2 "!"
  300. >> else if nal neq 'false and npl neq 'false then
  301. junct := ofsf_mkentry(cvl,nal,npl,(v . cdr x) . an) . junct
  302. >>;
  303. return junct
  304. end;
  305. %DS
  306. % <zeset> ::= (<zentry>,...)
  307. % <zentry> ::= (<atomic formula> . <substitution>)
  308. % <substitution> ::= (<variable> . <standard quotient>)
  309. procedure ofsf_zesetsubst(cvl,al,pl,an,zeset,theo);
  310. begin scalar w,scpl,zonly,nal,npl,junct,x,v;
  311. while zeset do <<
  312. x := car zeset;
  313. zeset := cdr zeset;
  314. v := cadr x;
  315. nal := ofsf_simpl(for each y in al collect
  316. ofsf_optsubstat(y,cddr x,v),theo);
  317. npl := ofsf_simpl(for each y in pl collect
  318. ofsf_optsubstat(y,cddr x,v),theo);
  319. al := delq(car x,al);
  320. pl := car x . pl;
  321. if null nal and null npl then <<
  322. junct := 'break;
  323. zeset := nil
  324. >> else if null nal then <<
  325. zonly := T;
  326. scpl := pl;
  327. while scpl do <<
  328. w := ofsf_varlat car scpl;
  329. scpl := cdr scpl;
  330. if w neq '(z) then scpl := zonly := nil
  331. >>;
  332. if zonly then rederr "BUG IN OFSF_ZESETSUBST";
  333. if !*rlverbose and not !*rlparallel then ioto_prin2 "!"
  334. >> else if nal neq 'false and npl neq 'false then
  335. junct := ofsf_mkentry(delq(v,cvl),nal,npl,cdr x . an) . junct
  336. >>;
  337. return junct
  338. end;
  339. procedure ofsf_optsubstat(atf,sq,v);
  340. % SQ denominator is a positive domain element.
  341. %% ofsf_qesubqat(atf,v,sq);
  342. begin scalar w;
  343. if null (w := ofsf_optsplitterm(ofsf_arg2l atf,v)) then return atf;
  344. return ofsf_0mk2(ofsf_op atf,
  345. addf(multf(car w,numr sq),multf(cdr w,denr sq)))
  346. end;
  347. procedure ofsf_optsplitterm(u,v);
  348. % Ordered fields standard form split term. [u] is a term $a[v]+b$;
  349. % [v] is a variable. Returns the pair $(a . b)$.
  350. begin scalar w;
  351. u := sfto_reorder(u,v);
  352. if (w := degr(u,v)) = 0 then return nil;
  353. if w > 1 then
  354. rederr {"ofsf_optsplitterm:",v,"has degree",w,"in",u};
  355. return reorder lc u . reorder red u
  356. end;
  357. procedure ofsf_simpl(l,theo);
  358. begin scalar w,op,!*rlsiexpla;
  359. w := cl_simpl(rl_smkn('and,l),theo,-1);
  360. if w eq 'false then return 'false;
  361. if w eq 'true then return nil;
  362. op := rl_op w;
  363. if op eq 'and then
  364. return rl_argn(w);
  365. if rl_cxp op then
  366. rederr {"BUG IN OFSF_SIMPL",op};
  367. return {w}
  368. end;
  369. switch boese,useold,usez;
  370. on1('useold);
  371. on1('usez);
  372. procedure ofsf_opteset(cvl,al,pl,z);
  373. begin scalar w,v,sel,lbl,ubl,eset; integer ub,lb,best;
  374. if not (!*usez or !*useold) then rederr "select usez or useold as method";
  375. if !*usez then <<
  376. for each x in al do
  377. if (w := ofsf_zboundchk(x,z)) then <<
  378. best := best + 1;
  379. % [w] is a consed pair.
  380. eset := (x . w) . eset
  381. >>;
  382. if eset then sel := z
  383. >>;
  384. if !*useold or null sel then <<
  385. while cvl do <<
  386. v := car cvl;
  387. cvl := cdr cvl;
  388. lb := ub := 0;
  389. lbl := ubl := nil;
  390. for each x in al do
  391. if (w := ofsf_boundchk(x,v)) then
  392. if car w eq 'lb then <<
  393. lb := lb + 1;
  394. lbl := (x . cdr w) . lbl
  395. >> else if car w eq 'ub then <<
  396. ub := ub + 1;
  397. ubl := (x . cdr w) . ubl
  398. >> else
  399. rederr "BUG 2 IN ofsf_opteset";
  400. if null lbl and ubl then
  401. lbl := '((nil . minf));
  402. if null ubl and lbl then
  403. ubl := '((nil . pinf));
  404. if ub <= lb then <<
  405. lb := ub;
  406. lbl := ubl
  407. >>;
  408. if null sel or lb < best or null !*boese and lb = best then <<
  409. best := lb;
  410. eset := lbl;
  411. sel := v
  412. >>;
  413. if null lbl and null ubl then
  414. cvl := nil
  415. >>
  416. >>;
  417. return sel . eset
  418. end;
  419. procedure ofsf_boundchk(atf,v);
  420. begin scalar u,oldorder,op,sol;
  421. oldorder := setkorder {v};
  422. u := reorder ofsf_arg2l atf;
  423. setkorder oldorder;
  424. if domainp u or mvar u neq v then return nil;
  425. if ldeg u neq 1 then rederr {"ofsf_boundchk:",v,"not linear"};
  426. sol := quotsq(!*f2q negf reorder red u,!*f2q reorder lc u);
  427. op := ofsf_op atf;
  428. if op eq 'equal then return 'equal . sol;
  429. if ofsf_xor(op eq 'geq,minusf lc u) then return 'lb . sol;
  430. return 'ub . sol
  431. end;
  432. procedure ofsf_zboundchk(atf,z);
  433. begin scalar u,v,oldorder,op;
  434. op := ofsf_op atf;
  435. u := ofsf_arg2l atf;
  436. if domainp u then
  437. return nil;
  438. oldorder := setkorder {z};
  439. u := reorder u;
  440. setkorder oldorder;
  441. if ldeg u neq 1 then
  442. rederr {"ofsf_zboundchk:",z,"not linear"};
  443. if mvar u neq z or domainp red u then
  444. return nil;
  445. if not (op eq 'equal or ofsf_xor(op eq 'geq,minusf lc u)) then
  446. return nil;
  447. v := mvar red u;
  448. oldorder := setkorder {v};
  449. u := reorder u;
  450. setkorder oldorder;
  451. return v . quotsq(!*f2q negf reorder red u,!*f2q reorder lc u)
  452. end;
  453. procedure ofsf_xor(a,b);
  454. (a or b) and not(a and b);
  455. procedure ofsf_getvalue(al,pl);
  456. begin scalar atf,w;
  457. atf := ofsf_simpl(append(al,pl),nil);
  458. if atf eq 'false then return nil;
  459. if cdr atf then <<
  460. if cddr atf then rederr {"BUG 1 IN OFSF_GETVALUE",atf};
  461. w := cadr atf;
  462. if ofsf_optlbp w then <<
  463. w := car atf;
  464. if ofsf_optlbp w then
  465. rederr {"BUG 2 IN OFSF_GETVALUE",atf};
  466. atf := cdr atf
  467. >>
  468. >>;
  469. atf := car atf;
  470. if not ofsf_optlbp atf then
  471. rederr {"BUG 3 IN OFSF_GETVALUE",atf};
  472. w := ofsf_arg2l atf;
  473. return quotsq(!*f2q negf red w,!*f2q lc w)
  474. end;
  475. procedure ofsf_optlbp(atf);
  476. ofsf_op atf memq '(equal geq);
  477. procedure ofsf_backsub(an,z,min);
  478. sort(ofsf_backsub1(an,z,min),function(lambda(x,y); ordp(car x,car y)));
  479. procedure ofsf_backsub1(an,z,min);
  480. ofsf_backsub2 for each x in an collect
  481. car x . ofsf_optsubsq(cdr x,{z . min});
  482. procedure ofsf_backsub2(an);
  483. if an then car an . ofsf_backsub2 for each x in cdr an collect
  484. car x . ofsf_optsubsq(cdr x,{caar an . cdar an});
  485. procedure ofsf_optsubsq(sq,al);
  486. if cdar al memq '(minf pinf) or sq memq '(minf pinf) then sq
  487. else subsq(sq,{caar al . prepsq cdar al});
  488. procedure ofsf_optmkans(ans);
  489. begin scalar w;
  490. if ans = '(nil nil) then return 'infeasible;
  491. if ans eq 'break then return {simp '(minus infinity),nil};
  492. return {car ans,for each x in cadr ans collect
  493. for each y in x collect <<
  494. w := atsoc(cdr y,'((minf . (minus infinity)) (pinf . infinity)));
  495. w := if w then cdr w else mk!*sq cdr y;
  496. aeval {'equal,car y,w}
  497. >>}
  498. end;
  499. procedure ofsf_optmksol(u,v);
  500. % Ordered fields standard form make solution. [u] is a term
  501. % $a[v]+b$ with $[a] \neq 0$; [v] is a variable. Returns the pair
  502. % $(-b . a)$.
  503. begin scalar w;
  504. w := setkorder {v};
  505. u := reorder u;
  506. setkorder w;
  507. if degr(u,v) neq 1 then rederr {"ofsf_mksol:",v,"not linear"};
  508. return negf reorder red u . reorder lc u
  509. end;
  510. procedure ofsf_save(co,dol);
  511. % Ordered field standard form save into container. [co] is a
  512. % container; [dol] is a list of container elements. Returns a
  513. % container.
  514. if !*rlqedfs then ofsf_push(co,dol) else ofsf_enqueue(co,dol);
  515. procedure ofsf_push(co,dol);
  516. % Ordered field standard form push into container. [co] is a
  517. % container; [dol] is a list of container elements. Returns a
  518. % container.
  519. <<
  520. for each x in dol do co := ofsf_coinsert(co,x);
  521. co
  522. >>;
  523. procedure ofsf_coinsert(co,ce);
  524. % Ordered field standard form insert into container. [co] is a
  525. % container; [ce] is a container element. Returns a container.
  526. if ofsf_comember(ce,co) then co else ce . co;
  527. procedure ofsf_enqueue(co,dol);
  528. % Ordered field standard form enqueue into container. [co] is a
  529. % container; [dol] is a list of container elements. Returns a
  530. % container.
  531. <<
  532. if null co and dol then <<
  533. co := {nil,car dol};
  534. car co := cdr co;
  535. dol := cdr dol
  536. >>;
  537. for each x in dol do
  538. if not ofsf_comember(x,cdr co) then
  539. car co := (cdar co := {x});
  540. co
  541. >>;
  542. procedure ofsf_get(co);
  543. % Ordered field standard form get from container. [co] is a
  544. % container. Returns a pair $(e . c)$ where $e$ is a container
  545. % element and $c$ is the container [co] without the entry $e$.
  546. if !*rlqedfs then ofsf_pop(co) else ofsf_dequeue(co);
  547. procedure ofsf_pop(co);
  548. % Ordered field standard form pop from container. [co] is a
  549. % container. Returns a pair $(e . c)$ where $e$ is a container
  550. % element and $c$ is the container [co] without the entry $e$.
  551. co;
  552. procedure ofsf_dequeue(co);
  553. % Ordered field standard form dequeue from container. [co] is a
  554. % container. Returns a pair $(e . c)$ where $e$ is a container
  555. % element and $c$ is the container [co] without the entry $e$.
  556. if co then cadr co . if cddr co then (car co . cddr co);
  557. procedure ofsf_colength(co);
  558. % Ordered field standard form container length. [co] is a
  559. % container. Returns the number of elements in [co].
  560. if !*rlqedfs or null co then length co else length co - 1;
  561. procedure ofsf_comember(ce,l);
  562. % Ordered field standard form container memeber. [ce] is a
  563. % container element; [l] is a list of container elements. Returns
  564. % non-[nil], if there is an container element $e$ in [l], such that
  565. % the formula and the variable list of $e$ are equal to the formula
  566. % and variable list of [ce]. This procedure does not use the access
  567. % functions!
  568. begin scalar a;
  569. if null l then
  570. return nil;
  571. a := car l;
  572. if ofsf_al ce = ofsf_al a and ofsf_pl ce = ofsf_pl a and
  573. ofsf_cvl ce = ofsf_cvl a
  574. then
  575. return l;
  576. return ofsf_comember(ce,cdr l)
  577. end;
  578. endmodule; % [ofsfopt]
  579. end; % of file