123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628 |
- % ----------------------------------------------------------------------
- % $Id: ofsfopt.red,v 1.6 1999/04/08 12:37:31 dolzmann Exp $
- % ----------------------------------------------------------------------
- % Copyright (c) 1995-1999 Andreas Dolzmann and Thomas Sturm
- % ----------------------------------------------------------------------
- % $Log: ofsfopt.red,v $
- % Revision 1.6 1999/04/08 12:37:31 dolzmann
- % Renamed switch rlsisqf to rlsiatadv.
- %
- % Revision 1.5 1999/03/23 07:41:38 dolzmann
- % Changed copyright information.
- %
- % Revision 1.4 1996/10/14 16:04:13 sturm
- % Bugfix: copied container code to this module.
- % Use DFS with !*rlqeheu on.
- %
- % Revision 1.3 1996/10/07 12:03:28 sturm
- % Added fluids for CVS and copyright information.
- %
- % Revision 1.2 1996/07/15 13:29:07 sturm
- % Modified data structure descriptions for automatic processing.
- %
- % Revision 1.1 1996/03/22 12:14:12 sturm
- % Moved and split.
- %
- % ----------------------------------------------------------------------
- lisp <<
- fluid '(ofsf_opt_rcsid!* ofsf_opt_copyright!*);
- ofsf_opt_rcsid!* := "$Id: ofsfopt.red,v 1.6 1999/04/08 12:37:31 dolzmann Exp $";
- ofsf_opt_copyright!* := "Copyright (c) 1995-1999 by A. Dolzmann and T. Sturm"
- >>;
- module ofsfopt;
- % Ordered field standard form optimization. Submodule of [ofsf].
- smacro procedure ofsf_cvl(x);
- car x;
- smacro procedure ofsf_al(x);
- cadr x;
- smacro procedure ofsf_pl(x);
- caddr x;
- smacro procedure ofsf_an(x);
- cdddr x;
- smacro procedure ofsf_mkentry(cvl,al,pl,an);
- cvl . al . pl . an;
- procedure ofsf_sendtask(hd,p,z);
- remote_call!*(hd,'ofsf_opt2,{
- ofsf_cvl p,ofsf_al p,ofsf_pl p,ofsf_an p,z,nil,nil},1) ;
- procedure ofsf_optmaster(cvl,al,z,nproc);
- % Ordered field standard form optimization master. [cvl] is a list
- % $(x_1,...,x_n)$ of variables; [al] is a list of active constraints
- % already containg an artificial constraint that encodes the target
- % function $f(x_1,...,x_n)$; [z] is the identifier that serves as
- % artificial variable for optimization, [nproc] is a positive
- % integer, the number of slaves to use; it must be less than the
- % number of available processors. Returns a list containing a form
- % $(v . ((x_1 . p_1) ... (x_n . p_n)))$ where $v$ is the minimal
- % value of $f$ subject to the contraints, $(p_1,...,p_n)$ is one
- % point such that $f(p_1,...,p_n)=v$.
- begin scalar w,pbase,finl,fp,hdl,p,pending,sol,hd;
- pbase := ofsf_opt2(cvl,al,nil,nil,z,3*nproc) where !*rlqedfs=nil;
- remote_process nil;
- hdl := for i:=1:nproc collect pvm_mytid() + i;
- pvm_initsend(1);
- %% if !*rlverbose then ioto_prin2t {"handlel is ",hdl};
- fp := hdl;
- pending := nil;
- if !*rlverbose then ioto_tprin2t {"initial pbase size is ",length pbase};
- while pbase or pending do <<
- while pbase and fp do <<
- hd := car fp;
- fp := cdr fp;
- p := car pbase;
- pbase := cdr pbase;
- if !*rlverbose then ioto_prin2t {"sending task to ",land(hd,4095)};
- pending := (ofsf_sendtask(hd,p,z) . hd) . pending
- >>;
- if pending then <<
- if !*rlverbose then
- ioto_tprin2 {length pbase," problems left, waiting for ",
- for each x in pending collect land(cdr x,4095)," ... "};
- finl := remote_wait();
- if !*rlverbose then ioto_prin2t "ready";
- for each fin in finl do <<
- if (w := remote_receive(fin)) and
- (null sol or minusf numr subtrsq(car w,car sol))
- then
- sol := w;
- fp := cdr assoc(fin,pending) . fp;
- pending := delasc(fin,pending)
- >>
- >>
- >>;
- return sol
- end;
- %%procedure ofsf_optgen(cl,targ,sz,fn);
- %% begin scalar w,!*rlqedfs,!*rlsisqf;
- %% w := ofsf_opt1(cl,targ,nil);
- %% return ofsf_opt2(car w,cadr w,nil,nil,caddr w,sz,fn)
- %% end;
- procedure ofsf_opt(cl,targ,parml,nproc);
- begin scalar svrlqedfs,w;
- if !*rlqeheu then <<
- svrlqedfs := !*rlqedfs;
- !*rlqedfs := T
- >>;
- w := ofsf_opt0(cl,targ,parml,nproc);
- if !*rlqeheu then
- !*rlqedfs := svrlqedfs;
- return w
- end;
- procedure ofsf_opt0(cl,targ,parml,nproc);
- % Linear optimization. [cl] is a list of parameter-free linear
- % atomic formulas with weak ordering relation; [targ] is an SQ with
- % constant denominator; [parm] is a dummy argument; [nproc] is the
- % number of processors available. Returns [infeasible],
- % [-infinity], or a list $(\mu,l_1,...,l_n)$ where the $l_i$ are
- % lists of equations. Minimizes [targ] subject to [cl].
- begin scalar w,nproc,!*rlsiatadv,!*rlsiso;
- w := ofsf_opt1(cl,targ,parml);
- if !*rlparallel then
- return ofsf_optmkans ofsf_optmaster(car w,cadr w,caddr w,nproc - 1);
- return ofsf_optmkans ofsf_opt2(car w,cadr w,nil,nil,caddr w,nil)
- end;
- procedure ofsf_opt1(cl,targ,parml);
- begin scalar z,qvl;
- z := intern gensym();
- cl := ofsf_0mk2('geq,
- addf(multf(denr targ,numr simp z),negf numr targ)) . cl;
- qvl := setdiff(ofsf_varl cl,z . parml);
- return {qvl,cl,z}
- end;
- procedure ofsf_varl(l);
- begin scalar w;
- for each x in l do
- w := union(w,ofsf_varlat x);
- return w
- end;
- procedure ofsf_opt2(cvl,al,pl,an,z,sz);
- begin scalar w,co,ansl,junct,best,m,theo; integer c,vlv,nodes,dpth;
- if !*rlverbose and !*rlparallel then
- ioto_tprin2 "entering opt2 ... ";
- if !*rlverbose and !*rlqedfs and not !*rlparallel then <<
- dpth := length cvl;
- vlv := dpth / 4;
- ioto_tprin2t {"+++ Depth is ",dpth,", watching level ",dpth - vlv}
- >>;
- co := ofsf_save(co,{ofsf_mkentry(cvl,al,pl,an)});
- while co do <<
- w := ofsf_get(co); co := cdr w; w := car w;
- cvl := ofsf_cvl w; al := ofsf_al w; pl := ofsf_pl w; an := ofsf_an w;
- if !*rlverbose and not !*rlparallel then
- nodes := nodes + 1;
- if !*rlverbose and !*rlqedfs and eqn(vlv,length cvl) and
- not !*rlparallel
- then
- ioto_tprin2t {"+++ Crossing level ",dpth - vlv};
- if !*rlverbose and null !*rlqedfs and not !*rlparallel then <<
- if eqn(c,0) then <<
- c := ofsf_colength(co) + 1;
- ioto_tprin2t {"+++ ",length cvl," variables left for this block"}
- >>;
- ioto_prin2 {"[",c};
- c := c - 1
- >>;
- if !*rlverbose and !*rlqedfs and not !*rlparallel then
- ioto_prin2 {"[",dpth - length cvl};
- junct := ofsf_qevar(cvl,al,pl,an,z,theo);
- if junct eq 'break then
- co := nil
- else if junct and ofsf_cvl car junct then
- co := ofsf_save(co,junct)
- else <<
- if !*rlverbose and not !*rlparallel and null junct then
- ioto_prin2 "#";
- for each x in junct do <<
- if m := ofsf_getvalue(ofsf_al x,ofsf_pl x) then <<
- if ansl and (minusf (w := numr subtrsq(m,best)) or
- null w and !*rlopt1s)
- then
- ansl := nil;
- if null ansl or null w then <<
- best := m;
- theo := {ofsf_0mk2('leq,addf(
- multf(denr best,numr simp z),negf numr best))};
- ansl := ofsf_an x . ansl; % insert instead?
- if !*rlverbose and not !*rlparallel then
- ioto_tprin2t {"min=",numr m or 0,"/",denr m}
- >>
- >>
- >>;
- if !*rlverbose and !*rlqedfs and not !*rlparallel then
- ioto_prin2 "."
- >>;
- if !*rlverbose and not !*rlparallel then ioto_prin2 "] ";
- if sz and ofsf_colength co >= sz then <<
- if ansl then
- rederr "ofsf_opt2: found solutions during pbase generation";
- junct := 'pbase;
- ansl := cdr co;
- co := nil
- >>
- >>;
- if junct eq 'pbase then
- w := ansl
- else if junct eq 'break then
- w := junct
- else <<
- w := nil;
- for each x in ansl do
- w := lto_insert(ofsf_backsub(x,z,best),w);
- w := {best,w}
- >>;
- if !*rlverbose and not !*rlparallel then
- ioto_tprin2t {"+++ ",nodes," nodes computed"};
- if !*rlverbose and !*rlparallel then
- ioto_prin2t "exiting opt2";
- return w
- end;
- procedure ofsf_qevar(cvl,al,pl,an,z,theo);
- begin scalar w,v,an,eset;
- if (w := ofsf_optgauss(cvl,al,pl,an,theo)) then return cdr w;
- % elimination set method
- w := ofsf_opteset(cvl,al,pl,z);
- v := car w;
- eset := cdr w;
- if eset then << % [v] actually occurs in [f].
- if v eq z then <<
- if !*rlverbose and not !*rlparallel then ioto_prin2 "z";
- return ofsf_zesetsubst(cvl,al,pl,an,eset,theo)
- >>;
- if !*rlverbose and not !*rlparallel then ioto_prin2 "e";
- return ofsf_esetsubst(cvl,al,pl,an,v,eset,theo)
- >>;
- % [v] does not occur in [f]. Reinsert [f] with updated
- % variable list.
- if !*rlverbose then ioto_prin2 "*";
- if v memq ofsf_varl pl then <<
- if !*rlverbose and not !*rlparallel then ioto_prin2 "!";
- return nil % Maybe wrong!
- >>;
- return {ofsf_mkentry(delq(v,cvl),al,pl,an)}
- end;
- procedure ofsf_optgauss(cvl,al,pl,an,theo);
- begin scalar v,w,sc;
- sc := cvl;
- while sc do <<
- v := car sc;
- sc := cdr sc;
- if (w := ofsf_optfindeqsol(al,v)) then sc := nil
- >>;
- if w then <<
- if !*rlverbose and not !*rlparallel then ioto_prin2 "g";
- return T . ofsf_esetsubst(cvl,al,pl,an,v,{w},theo)
- >>
- end;
- procedure ofsf_optfindeqsol(al,v);
- begin scalar a,w;
- a := car al;
- if ofsf_op a eq 'equal and v memq ofsf_varlat a then <<
- w := ofsf_optmksol(ofsf_arg2l a,v);
- return a . quotsq(!*f2q car w,!*f2q cdr w)
- >>;
- if cdr al then
- return ofsf_optfindeqsol(cdr al,v)
- end;
- %DS
- % <eset> ::= (<entry>,...)
- % <entry> ::= (<atomic formula> . <standard quotient>)
- procedure ofsf_esetsubst(cvl,al,pl,an,v,eset,theo);
- begin scalar w,scpl,zonly,nal,npl,junct,x;
- cvl := delq(v,cvl);
- while eset do <<
- x := car eset;
- eset := cdr eset;
- if cdr x memq '(pinf minf) then <<
- nal := ofsf_simpl(for each atf in al collect
- ofsf_qesubiat(atf,v,cdr x),theo);
- npl := ofsf_simpl(for each atf in pl collect
- ofsf_qesubiat(atf,v,cdr x),theo)
- >> else <<
- nal := ofsf_simpl(for each y in al collect
- ofsf_optsubstat(y,cdr x,v),theo);
- npl := ofsf_simpl(for each y in pl collect
- ofsf_optsubstat(y,cdr x,v),theo);
- al := delq(car x,al);
- pl := car x . pl
- >>;
- if null nal and null npl then <<
- junct := 'break;
- eset := nil
- >> else if null nal then <<
- zonly := T;
- scpl := pl;
- while scpl do <<
- w := ofsf_varlat car scpl;
- scpl := cdr scpl;
- if w neq '(z) then scpl := zonly := nil
- >>;
- if zonly then rederr "BUG IN OFSF_ESETSUBST";
- if !*rlverbose and not !*rlparallel then ioto_prin2 "!"
- >> else if nal neq 'false and npl neq 'false then
- junct := ofsf_mkentry(cvl,nal,npl,(v . cdr x) . an) . junct
- >>;
- return junct
- end;
- %DS
- % <zeset> ::= (<zentry>,...)
- % <zentry> ::= (<atomic formula> . <substitution>)
- % <substitution> ::= (<variable> . <standard quotient>)
- procedure ofsf_zesetsubst(cvl,al,pl,an,zeset,theo);
- begin scalar w,scpl,zonly,nal,npl,junct,x,v;
- while zeset do <<
- x := car zeset;
- zeset := cdr zeset;
- v := cadr x;
- nal := ofsf_simpl(for each y in al collect
- ofsf_optsubstat(y,cddr x,v),theo);
- npl := ofsf_simpl(for each y in pl collect
- ofsf_optsubstat(y,cddr x,v),theo);
- al := delq(car x,al);
- pl := car x . pl;
- if null nal and null npl then <<
- junct := 'break;
- zeset := nil
- >> else if null nal then <<
- zonly := T;
- scpl := pl;
- while scpl do <<
- w := ofsf_varlat car scpl;
- scpl := cdr scpl;
- if w neq '(z) then scpl := zonly := nil
- >>;
- if zonly then rederr "BUG IN OFSF_ZESETSUBST";
- if !*rlverbose and not !*rlparallel then ioto_prin2 "!"
- >> else if nal neq 'false and npl neq 'false then
- junct := ofsf_mkentry(delq(v,cvl),nal,npl,cdr x . an) . junct
- >>;
- return junct
- end;
- procedure ofsf_optsubstat(atf,sq,v);
- % SQ denominator is a positive domain element.
- %% ofsf_qesubqat(atf,v,sq);
- begin scalar w;
- if null (w := ofsf_optsplitterm(ofsf_arg2l atf,v)) then return atf;
- return ofsf_0mk2(ofsf_op atf,
- addf(multf(car w,numr sq),multf(cdr w,denr sq)))
- end;
- procedure ofsf_optsplitterm(u,v);
- % Ordered fields standard form split term. [u] is a term $a[v]+b$;
- % [v] is a variable. Returns the pair $(a . b)$.
- begin scalar w;
- u := sfto_reorder(u,v);
- if (w := degr(u,v)) = 0 then return nil;
- if w > 1 then
- rederr {"ofsf_optsplitterm:",v,"has degree",w,"in",u};
- return reorder lc u . reorder red u
- end;
- procedure ofsf_simpl(l,theo);
- begin scalar w,op,!*rlsiexpla;
- w := cl_simpl(rl_smkn('and,l),theo,-1);
- if w eq 'false then return 'false;
- if w eq 'true then return nil;
- op := rl_op w;
- if op eq 'and then
- return rl_argn(w);
- if rl_cxp op then
- rederr {"BUG IN OFSF_SIMPL",op};
- return {w}
- end;
- switch boese,useold,usez;
- on1('useold);
- on1('usez);
- procedure ofsf_opteset(cvl,al,pl,z);
- begin scalar w,v,sel,lbl,ubl,eset; integer ub,lb,best;
- if not (!*usez or !*useold) then rederr "select usez or useold as method";
- if !*usez then <<
- for each x in al do
- if (w := ofsf_zboundchk(x,z)) then <<
- best := best + 1;
- % [w] is a consed pair.
- eset := (x . w) . eset
- >>;
- if eset then sel := z
- >>;
- if !*useold or null sel then <<
- while cvl do <<
- v := car cvl;
- cvl := cdr cvl;
- lb := ub := 0;
- lbl := ubl := nil;
- for each x in al do
- if (w := ofsf_boundchk(x,v)) then
- if car w eq 'lb then <<
- lb := lb + 1;
- lbl := (x . cdr w) . lbl
- >> else if car w eq 'ub then <<
- ub := ub + 1;
- ubl := (x . cdr w) . ubl
- >> else
- rederr "BUG 2 IN ofsf_opteset";
- if null lbl and ubl then
- lbl := '((nil . minf));
- if null ubl and lbl then
- ubl := '((nil . pinf));
- if ub <= lb then <<
- lb := ub;
- lbl := ubl
- >>;
- if null sel or lb < best or null !*boese and lb = best then <<
- best := lb;
- eset := lbl;
- sel := v
- >>;
- if null lbl and null ubl then
- cvl := nil
- >>
- >>;
- return sel . eset
- end;
- procedure ofsf_boundchk(atf,v);
- begin scalar u,oldorder,op,sol;
- oldorder := setkorder {v};
- u := reorder ofsf_arg2l atf;
- setkorder oldorder;
- if domainp u or mvar u neq v then return nil;
- if ldeg u neq 1 then rederr {"ofsf_boundchk:",v,"not linear"};
- sol := quotsq(!*f2q negf reorder red u,!*f2q reorder lc u);
- op := ofsf_op atf;
- if op eq 'equal then return 'equal . sol;
- if ofsf_xor(op eq 'geq,minusf lc u) then return 'lb . sol;
- return 'ub . sol
- end;
- procedure ofsf_zboundchk(atf,z);
- begin scalar u,v,oldorder,op;
- op := ofsf_op atf;
- u := ofsf_arg2l atf;
- if domainp u then
- return nil;
- oldorder := setkorder {z};
- u := reorder u;
- setkorder oldorder;
- if ldeg u neq 1 then
- rederr {"ofsf_zboundchk:",z,"not linear"};
- if mvar u neq z or domainp red u then
- return nil;
- if not (op eq 'equal or ofsf_xor(op eq 'geq,minusf lc u)) then
- return nil;
- v := mvar red u;
- oldorder := setkorder {v};
- u := reorder u;
- setkorder oldorder;
- return v . quotsq(!*f2q negf reorder red u,!*f2q reorder lc u)
- end;
- procedure ofsf_xor(a,b);
- (a or b) and not(a and b);
- procedure ofsf_getvalue(al,pl);
- begin scalar atf,w;
- atf := ofsf_simpl(append(al,pl),nil);
- if atf eq 'false then return nil;
- if cdr atf then <<
- if cddr atf then rederr {"BUG 1 IN OFSF_GETVALUE",atf};
- w := cadr atf;
- if ofsf_optlbp w then <<
- w := car atf;
- if ofsf_optlbp w then
- rederr {"BUG 2 IN OFSF_GETVALUE",atf};
- atf := cdr atf
- >>
- >>;
- atf := car atf;
- if not ofsf_optlbp atf then
- rederr {"BUG 3 IN OFSF_GETVALUE",atf};
- w := ofsf_arg2l atf;
- return quotsq(!*f2q negf red w,!*f2q lc w)
- end;
- procedure ofsf_optlbp(atf);
- ofsf_op atf memq '(equal geq);
- procedure ofsf_backsub(an,z,min);
- sort(ofsf_backsub1(an,z,min),function(lambda(x,y); ordp(car x,car y)));
- procedure ofsf_backsub1(an,z,min);
- ofsf_backsub2 for each x in an collect
- car x . ofsf_optsubsq(cdr x,{z . min});
- procedure ofsf_backsub2(an);
- if an then car an . ofsf_backsub2 for each x in cdr an collect
- car x . ofsf_optsubsq(cdr x,{caar an . cdar an});
- procedure ofsf_optsubsq(sq,al);
- if cdar al memq '(minf pinf) or sq memq '(minf pinf) then sq
- else subsq(sq,{caar al . prepsq cdar al});
- procedure ofsf_optmkans(ans);
- begin scalar w;
- if ans = '(nil nil) then return 'infeasible;
- if ans eq 'break then return {simp '(minus infinity),nil};
- return {car ans,for each x in cadr ans collect
- for each y in x collect <<
- w := atsoc(cdr y,'((minf . (minus infinity)) (pinf . infinity)));
- w := if w then cdr w else mk!*sq cdr y;
- aeval {'equal,car y,w}
- >>}
- end;
- procedure ofsf_optmksol(u,v);
- % Ordered fields standard form make solution. [u] is a term
- % $a[v]+b$ with $[a] \neq 0$; [v] is a variable. Returns the pair
- % $(-b . a)$.
- begin scalar w;
- w := setkorder {v};
- u := reorder u;
- setkorder w;
- if degr(u,v) neq 1 then rederr {"ofsf_mksol:",v,"not linear"};
- return negf reorder red u . reorder lc u
- end;
- procedure ofsf_save(co,dol);
- % Ordered field standard form save into container. [co] is a
- % container; [dol] is a list of container elements. Returns a
- % container.
- if !*rlqedfs then ofsf_push(co,dol) else ofsf_enqueue(co,dol);
- procedure ofsf_push(co,dol);
- % Ordered field standard form push into container. [co] is a
- % container; [dol] is a list of container elements. Returns a
- % container.
- <<
- for each x in dol do co := ofsf_coinsert(co,x);
- co
- >>;
- procedure ofsf_coinsert(co,ce);
- % Ordered field standard form insert into container. [co] is a
- % container; [ce] is a container element. Returns a container.
- if ofsf_comember(ce,co) then co else ce . co;
- procedure ofsf_enqueue(co,dol);
- % Ordered field standard form enqueue into container. [co] is a
- % container; [dol] is a list of container elements. Returns a
- % container.
- <<
- if null co and dol then <<
- co := {nil,car dol};
- car co := cdr co;
- dol := cdr dol
- >>;
- for each x in dol do
- if not ofsf_comember(x,cdr co) then
- car co := (cdar co := {x});
- co
- >>;
- procedure ofsf_get(co);
- % Ordered field standard form get from container. [co] is a
- % container. Returns a pair $(e . c)$ where $e$ is a container
- % element and $c$ is the container [co] without the entry $e$.
- if !*rlqedfs then ofsf_pop(co) else ofsf_dequeue(co);
- procedure ofsf_pop(co);
- % Ordered field standard form pop from container. [co] is a
- % container. Returns a pair $(e . c)$ where $e$ is a container
- % element and $c$ is the container [co] without the entry $e$.
- co;
- procedure ofsf_dequeue(co);
- % Ordered field standard form dequeue from container. [co] is a
- % container. Returns a pair $(e . c)$ where $e$ is a container
- % element and $c$ is the container [co] without the entry $e$.
- if co then cadr co . if cddr co then (car co . cddr co);
- procedure ofsf_colength(co);
- % Ordered field standard form container length. [co] is a
- % container. Returns the number of elements in [co].
- if !*rlqedfs or null co then length co else length co - 1;
- procedure ofsf_comember(ce,l);
- % Ordered field standard form container memeber. [ce] is a
- % container element; [l] is a list of container elements. Returns
- % non-[nil], if there is an container element $e$ in [l], such that
- % the formula and the variable list of $e$ are equal to the formula
- % and variable list of [ce]. This procedure does not use the access
- % functions!
- begin scalar a;
- if null l then
- return nil;
- a := car l;
- if ofsf_al ce = ofsf_al a and ofsf_pl ce = ofsf_pl a and
- ofsf_cvl ce = ofsf_cvl a
- then
- return l;
- return ofsf_comember(ce,cdr l)
- end;
- endmodule; % [ofsfopt]
- end; % of file
|