12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025 |
- %********************************************************************
- module simplifications$
- %********************************************************************
- % Routines for simplifications, contradiction testing
- % and substitution of functions
- % Author: Andreas Brand
- % 1991 1993 1994
- % Updates, changes, additions by Thomas Wolf
- %
- % $Id: crsimp.red,v 1.17 1998/06/25 18:16:41 tw Exp tw $
- %
- symbolic procedure signchange(g)$
- % ensure, that the first term is positive
- if pairp g then
- if (car g='MINUS) then cadr g
- else if (car g='PLUS) and (pairp cadr g) and (caadr g='MINUS)
- then reval list('MINUS,g)
- else g
- else g$
- symbolic procedure simplifyterm(p,ftem)$
- % simplify a single factor p of g=p*q*r*...=0
- if (ftem:=smemberl(ftem,p)) then
- if pairp p and member(car p,'(MINUS SQRT QUOTIENT))
- then simplifyterm(cadr p,ftem)
- else if pairp p and (car p='EXPT) then
- if smemberl(ftem,cadr p) then simplifyterm(cadr p,ftem)
- else 1
- else if member((p:=signchange p),ineq_) then 1
- else p
- else if not p or zerop p then 0
- else 1$
- symbolic procedure contradictioncheck(s,pdes)$
- begin scalar v,p$
- if s then
- while pdes do
- <<p:=car pdes$pdes:=cdr pdes$
- v:=get(p,'val)$
- if pairp v and (car v='TIMES) then
- (if member(s,cdr v) then
- <<v:=delete(s,cdr v)$
- update(p,if length v=1 then car v else cons('TIMES,v),
- get(p,'fcts),get(p,'vars),nil,list(0))>>)
- else if s=v then
- <<raise_contradiction(v,nil)$
- pdes:=nil>>
- >>$
- return contradiction_$
- end$
- symbolic procedure raise_contradiction(g,text)$
- <<contradiction_:=t$
- if print_ then
- <<terpri()$if text then write text
- else write "contradiction : "$
- deprint list g>> >>$
- symbolic procedure simplifypde(g,ftem,tofactor)$
- % simplify g=0
- begin scalar h,l,ruli$
- if rulelist_ then g:=reval evalwhereexp list(rulelist_,g)$
- ruli:=start_let_rules()$
- g:=reval aeval g$
- stop_let_rules(ruli)$
- if g and not zerop g and not (ftem:=smemberl(ftem,g)) then
- <<raise_contradiction(g,nil)$g:=1>>
- else if pairp g then
- if member(car g,'(EXPT QUOTIENT MINUS SQRT)) then
- g:=simplifypde(cadr g,ftem,tofactor)
- else if member(car g,'(LOG LN LOGB LOG10)) then
- g:=simplifypde(reval list('PLUS,cadr g,-1),ftem,tofactor)
- else if tofactor then
- <<if car g='TIMES
- then l:=for each a in cdr g join
- cdr reval list('FACTORIZE,a)
- else l:=cdr reval list('FACTORIZE,g)$
- while l do
- <<if not member(car l,cdr l) then
- h:=union(list simplifyterm(car l,ftem),h)$
- l:=cdr l>>$
- h:=delete(1,h)$
- if null h then
- <<raise_contradiction(g,nil)$
- g:=1>>
- else
- if pairp cdr h then g:=cons('TIMES,reverse h)
- else g:=car h>>$
- return g$
- end$
-
- symbolic procedure fcteval(p,less_vars)$
- % looks for a function which can be eliminated
- % if one is found, it is stored in p as (coeff_of_f.f)
- % if less_vars neq nil then the expr. to be substituted
- % must have only fcts. of less vars
- % 'to_eval neq nil iff not checked yet for substitution
- % of if subst. possible
- % i.e. 'to_eval=nil if checked and not possible
- % 'fcteval_lin includes subst. with coefficients that do not
- % include ftem functions/constants
- % 'fcteval_nca includes subst. with non-vanishing coefficients
- % and therefore no case distinctions (linearity)
- % 'fcteval_nli includes subst. with possibly vanishing coefficients
- % and therefore case distinctions (non-linearity)
- begin scalar ft,a,b,fl,li,nc,nl,f,cpf,fv,fc$
- if flagp(p,'to_eval) then <<
- b:=get(p,'not_to_eval)$ % functions that replace a derivative
- if (not get(p,'fcteval_lin)) and
- (not get(p,'fcteval_nca)) and
- (not get(p,'fcteval_nli)) then <<
- ft:=get(p,'allvarfcts)$
- if null ft then <<
- ft:=get(p,'rational)$
- % drop all functions f from ft for which there is another
- % function which is a function of all variables of f + at
- % least one extra variable
- for each f in ft do <<
- cpf:=get(p,'fcts)$
- fv:=fctargs f$
- while cpf and
- (not_included(fv,fc:=fctargs car cpf) or
- (length fv >= length fc) ) do
- cpf:=cdr cpf;
- if null cpf then fl:=cons(f,cpf)
- >>$
- ft:=fl$
- >>$
- if ft then <<
- if (not less_vars) or
- (not cdr ft) or
- (zerop get(p,'nvars)) then <<
- % either all functions allowed or only one fnc of all vars
- for each f in ft do
- if (f neq b) and linear_fct(p,f) then <<
- % only linear algebr. fcts
- a:=reval coeffn(get(p,'val),f,1)$
- if fl:=smemberl(delete(f,get(p,'fcts)),a) then
- if freeofzero(a,fl,get(p,'vars)) then nc:=cons(cons(a,f),nc)
- else nl:=cons(cons(a,f),nl)
- else
- li:=cons(cons(a,f),li)
- >>$
- if li then put(p,'fcteval_lin,reverse li); % else
- if nc then put(p,'fcteval_nca,reverse nc); % else
- if nl then put(p,'fcteval_nli,reverse nl);
- if not (li or nc or nl) then remflag1(p,'to_eval)
- >>
- >>$
- >>$
- return (get(p,'fcteval_lin) or
- get(p,'fcteval_nca) or
- get(p,'fcteval_nli) )
- >>
- end$
- symbolic procedure freeofzero(p,ft,vl)$
- % gets p (factorized), if p does not vanish identically
- if null ft then p
- else
- begin scalar a,b,fr,pri$
- pri:=print_$
- print_:=nil$
- for each s in cdr reval list('FACTORIZE,p) do
- a:=union(list simplifyterm(s,ft),a)$
- if length a>1 then p:=cons('TIMES,a)$
- while a do
- if null smemberl(ft,car a) or member(car a,ineq_) then a:=cdr a
- else if pairp cdr
- (b:=union(for each s in separ(car a,ft,vl) collect cdr s,nil)) then
- <<fr:=nil$
- while b do if freeofzero(car b,ft,vl) then <<b:=nil$fr:=t>>
- else b:=cdr b$
- if fr then a:=cdr a
- else <<a:=nil$p:=nil>> >>
- else <<a:=nil$p:=nil>>$
- print_:=pri$
- return p
- end$
- symbolic procedure get_subst(l,length_limit,less_vars,no_df)$
- %
- % get the most simple pde from l which leads to a function substitution
- % if less_vars neq nil: the expr. to subst. has only fcts. of less vars
- % if no_df neq nil: the expr. to subst. has no derivatives
- begin scalar p,l1,l2,m,ntms,mdu$
- % mdu=(1:lin, 2:nca, 3:nli)
- % drop all equations longer than length_limit
- if length_limit then <<
- while l do
- if get(car l,'length)>length_limit then l:=nil
- else <<
- l1:=cons(car l,l1)$
- l:=cdr l
- >>$
- l:=reverse l1
- >>$
- % l is now the list of equations <= length_limit
- % next: substitution only if no_df=nil or
- % no derivative of any function occurs
- if no_df then <<
- for each s in l do
- <<l2:=get(s,'derivs)$
- while l2 do
- if pairp(cdaar l2) then
- <<l2:=nil;
- l1:=cons(s,l1)>>
- else l2:=cdr l2>>$
- l:=setdiff(l,l1)>>$
- % next: restrict to substitutions, if any,
- % that have a coefficient without ftem-dependence
- l1:=nil;
- for each s in l do
- if fcteval(s,less_vars) and
- get(s,'fcteval_lin) then l1:=cons(s,l1)$
- if l1 then <<l:=l1;mdu:=1>>
- else <<
- % at least substitutions that do not lead to subcases?
- for each s in l do
- if get(s,'fcteval_nca) then l1:=cons(s,l1)$
- if l1 then <<l:=l1;mdu:=2>>
- else mdu:=3
- >>$
- % next: find an equation with as many as possible variables
- % and few as possible terms for substitution
- m:=-1$
- for each s in l do <<
- l1:=get(s,'nvars);
- if get(s,'starde) then l1:=sub1 l1;
- if l1>m then m:=l1$
- >>$
- while m>=0 do <<
- l1:=l$
- ntms:=10000000$
- while l1 do
- if ((get(car l1,'nvars) -
- if get(car l1,'starde) then 1
- else 0) = m ) and
- fcteval(car l1,less_vars) and
- (get(car l1,'terms) < ntms) then <<
- p:=car l1$
- l1:=cdr l1$
- ntms:=get(p,'terms)$
- >> else l1:=cdr l1$
- m:=if p then -1
- else sub1 m
- >>$
- if p then return if mdu=1 then {mdu,p,car get(p,'fcteval_lin)} else
- if mdu=2 then {mdu,p,car get(p,'fcteval_nca)} else
- {mdu,p,car get(p,'fcteval_nli)}
- end$
- symbolic procedure ineqsplit(q,ftem)$
- % q into factors and
- % drop quotients
- begin scalar l$
- if pairp q and (car q='QUOTIENT) then q:=cadr q$
- q:=cdr reval list('FACTORIZE,q)$
- for each s in q do
- if smemberl(ftem,s) then
- <<s:=signchange s$
- if not member(s,l) then l:=cons(s,l)>>$
- return l$
- end$
- symbolic procedure ineqsubst(new,old,ftem)$
- % tests all q's in ineq_ for subst(new, old,q)=0
- % result: nil, if 0 occurs
- % otherwise list of the subst(car p,...)
- begin scalar l,a$
- while ineq_ do
- if not my_freeof(car ineq_,old) then
- <<a:=simplifyterm(reval reval subst(new, old,car ineq_),ftem)$
- if zerop a then
- <<if print_ then
- <<terpri()$write "contradiction from the substitution:"$
- eqprint list('EQUAL,old,new)$
- write "because of the non-vanishing expression:"$
- eqprint car ineq_>>$
- contradiction_:=t$
- l:=nil$
- ineq_:=nil>>
- else
- <<l:=union(ineqsplit(a,ftem),l)$
- ineq_:=cdr ineq_>> >>
- else
- <<l:=cons(car ineq_,l)$
- ineq_:=cdr ineq_>>$
- ineq_:=reverse l$
- end$
- symbolic procedure do_one_subst(ex,f,a,ftem,vl,level,eqn)$
- % substitute f by ex in a
- begin scalar l,l1,p,oldstarde$
- l:=get(a,'val)$
- oldstarde:=get(a,'starde)$
- if pairp l and (car l='TIMES) then l:=cdr l
- else l:=list l$
- while l do << % for each factor
- if smember(f,car l) then <<
- p:=reval reval subst(ex,f,car l)$
- if not p or zerop p then <<l:=list nil$l1:=list 0>>
- else <<
- if pairp p and (car p='QUOTIENT) then p:=cadr p$
- l1:=if no_of_terms(p)>max_factor then cons(p,l1)
- else
- append(reverse cdr reval list('FACTORIZE,p),l1)
- >>
- >> else l1:=cons(car l,l1)$
- l:=cdr l
- >>$
- l:=nil$
- while l1 do <<
- if not member(car l1,cdr l1) then
- l:=union(list simplifyterm(car l1,ftem),l)$
- l1:=cdr l1
- >>$
- l:=delete(1,l)$
- if null l then <<
- if print_ then <<
- terpri()$ % new
- write"Substitution of "$
- fctprint list f$
- if cdr get(eqn,'fcts) then <<
- write " by an expression in "$terpri()$
- fctprint delete(f,get(eqn,'fcts))
- >>$
- write " found in ",eqn," : "$
- eqprint(list('EQUAL,f,ex))
- >>$
- raise_contradiction(get(a,'val),
- "leads to a contradiction in : ")$
- a:=nil
- >> else <<
- if pairp cdr l then l:=cons('TIMES,l)
- else l:=car l$
- if get(a,'level) neq level then
- a:=mkeq(l,ftem,vl,allflags_,nil,list(0))
- else <<
- for each b in allflags_ do flag(list a,b)$
- if null update(a,l,ftem,vl,nil,list(0)) then <<
- setprop(a,nil)$
- a:=nil
- >>
- >>$
- put(a,'level,level)
- >>$
- if oldstarde and not get(a,'starde) then put(a,'dec_with,nil);
- return a$
- end$
- symbolic procedure do_subst(md,p,l,pde,ftem,forg,vl,plim)$
- % md is the mode of substitution, needed in case of an ISE
- % Substitute a function in all pdes
- begin scalar f,fl,h,ex,res,slim,too_large,was_subst,ps,
- ruli,ise,cf,vl,nof,stde$ %,l$
- % l:=get(p,'fcteval_lin)$
- % if null l then l:=get(p,'fcteval_nca)$
- % if null l then l:=get(p,'fcteval_nli)$
- % if l then << % l:=car l$
- f:=cdr l$
- cf:=car l$
- if get(p,'starde) then ise:=t;
- slim:=get(p,'length)$
- ruli:=start_let_rules()$
- ex:=reval aeval list('QUOTIENT,
- list('PLUS,list('MINUS,get(p,'val)),
- list('TIMES,cf,f)),
- cf)$
- if not ise then ineqsubst(ex,f,ftem)$
- if not contradiction_ then <<
- if not ise then <<
- fl:=delete(f,smemberl(ftem_,ex))$ % functions occuring in ex
- forg:=for each h in forg collect
- if atom h then
- if f=h then <<put(h,'fcts,fl)$was_subst:=t$list('EQUAL,f,ex)>>
- else h
- else
- if (car h='EQUAL) and member(f,get(cadr h,'fcts)) then <<
- put(cadr h,'fcts,union(fl,delete(f,get(cadr h,'fcts))))$
- was_subst:=t$
- reval subst(ex,f,h)
- >> else h$
- >>$
- if expert_mode then <<
- ps:=promptstring!*$
- promptstring!*:="pdes selected for substitution: "$
- l:=xread nil$
- promptstring!*:=ps$
- if idp l then <<if not member(l,pde) then l:=nil>>
- else if pairp l then
- if car l='!*comma!* then l:=intersection(pde,cdr l)
- else l:=nil
- else l:=nil$
- if not_included(pde,l) then too_large:=t$
- if not l then <<
- terpri()$
- write "This is not a pde (e.g. e2) or a list of pdes (e.g. e1,e2,e3)"
- >>
- >> else l:=delete(p,pde)$
- % Do the substitution in all suitable equations
- if ise then <<
- h:=nil;
- vl:=get(p,'vars)$
- fl:=get(p,'fcts)$
- nof:=cdr get(p,'starde)$
- while l do <<
- if (stde:=get(car l,'starde)) and
- (nof<=cdr stde) and
- (not not_included(vl,get(car l,'vars))) and
- (not not_included(fl,get(car l,'fcts))) then h:=cons(car l,h);
- l:=cdr l
- >>$
- l:=h;
- >>$
- while l and not contradiction_ do <<
- if member(f,get(car l,'fcts)) then
- if not expert_mode and plim and (slim*get(car l,'length)>plim)
- then too_large:=t
- else <<
- pde:=eqinsert(do_one_subst(ex,f,car l,ftem,vl,get(p,'level),p),
- delete(car l,pde))$
- for each h in pde do drop_rl_with(car l,h);
- put(car l,'rl_with,nil);
- for each h in pde do drop_dec_with(car l,h,'dec_with_rl);
- put(car l,'dec_with_rl,nil);
- flag(list car l,'to_int);
- was_subst:=t
- >>$
- l:=cdr l
- >>$
- if print_ and (not contradiction_) and was_subst then <<
- terpri()$write "Substitution of "$
- fctprint list f$
- if cdr get(p,'fcts) then <<
- write " by an "$
- if ise then write"(separable) "$
- write "expression in "$terpri()$
- fctprint delete(f,get(p,'fcts))
- >>$
- write " found in ",p," : "$
- eqprint(list('EQUAL,f,ex))
- >>$
- % To avoid using p repeatedly for substitutions of different
- % functions in the same equations:
- if ise then <<
- put(p,'fcteval_lin,nil);
- put(p,'fcteval_nca,nil);
- put(p,'fcteval_nli,nil);
- remflag1(p,'to_eval)$ % otherwise 'fcteval_??? would be computed again
- md:=md; % only in order to do something with md if the next
- % statement is commented out
- % if too_large then
- % if md=1 then put(p,'fcteval_lin,list((cf . f))) else
- % if md=2 then put(p,'fcteval_nca,list((cf . f))) else
- % put(p,'fcteval_nli,list((cf . f)))$
- % could probably unnecessarily be repeated
- >>;
- % delete f and p if not anymore needed
- if (not ise) and
- (not too_large) and
- (not contradiction_) then <<
- if not assoc(f,depl_copy_) then
- depl!*:=delete(assoc(f,depl!*),depl!*)$
- was_subst:=t$ % in the sense that pdes have been updated
- ftem_:=delete(f,ftem_)$
- pde:=delete(p,pde)$
- setprop(p,nil)
- >>$
- % if was_subst then
- res:=list(pde,forg)
- % also if not used to delete the pde if the function to be
- % substituted does not appear anymore
- >>$
- stop_let_rules(ruli)$
- % >>$
- if not contradiction_ then return cons(was_subst,res)$
- end$
- symbolic procedure make_subst(pdes,forg,vl,l1,length_limit,pdelimit,
- less_vars,no_df,no_cases,lin_subst,
- mingrowth,cost_limit)$
- % make a subst.
- % l1 is the list of possible "candidates"
- begin scalar p,q,r,l,h,cop,cases_,w,md$ % ,ineq
- if expert_mode then l1:=selectpdes(pdes,1)$
- again:
- if (mingrowth and (w:=search_subs(l1,cost_limit,no_cases))) or
- ((null mingrowth) and
- (w:=get_subst(l1,length_limit,less_vars,no_df))) then
- if ( car w = 1) or
- ((lin_subst=nil) and
- ( (car w = 2) or
- ((car w = 3) and
- member(caaddr w,ineq_) ) ) ) then <<
- l:=do_subst(car w,cadr w,caddr w,pdes,ftem_,forg,vl,pdelimit)$
- if l and null car l then << % not contradiction but not used
- l1:=delete(cadr w,l1);
- if l1 then <<
- pdes:=cadr l;
- forg:=caddr l;
- l:=nil;
- goto again
- >>
- >>;
- if l then l:=cdr l
- >> else
- if (null lin_subst) and (null no_cases) then <<
- md:=car w; % md = type of substitution, needed in case of ISE
- p:=cadr w; % p = the equation
- w:=caddr w; % w = (coeff . function)
- % make an equation from the coefficient
- q:=mkeq(car w,get(p,'fcts),get(p,'vars),allflags_,t,list(0))$
- % and an equation from the remainder
- r:=mkeq(list('PLUS,get(p,'val),
- list('TIMES,car w,
- list('MINUS,cdr w))),
- get(p,'fcts),get(p,'vars),allflags_,t,list(0))$
- if contradiction_ then <<
- contradiction_:=nil$
- h:=get(q,'val)$
- if pairp h and (car h='TIMES) then ineq_:=union(cdr h,ineq_)
- else ineq_:=union(list h,ineq_)$
- setprop(q,nil)$
- setprop(r,nil)$
- l:=do_subst(md,p,w,pdes,ftem_,forg,vl,pdelimit)$
- if print_ then write"therefore no special investigation"$
- if l and null car l then << % not contradiction but not used
- l1:=delete(p,l1);
- if l1 then <<
- pdes:=cadr l;
- forg:=caddr l;
- l:=nil;
- goto again
- >>
- >>;
- if l then l:=cdr l
- >> else <<
- cop:=backup_pdes(pdes,forg)$
- remflag1(p,'to_eval)$
- if print_ then <<
- terpri()$
- write "for the substitution of ",cdr w," by ",p$
- write " we have to consider the case : "$
- eqprint list('EQUAL,0,car w)
- >>$
- pdes:=eqinsert(q,delete(p,pdes))$
- pdes:=eqinsert(r,pdes)$
- level_:=cons(1,level_)$
- print_level()$
- h:=get(q,'val)$ % to add it to ineq_ afterwards
- l:=crackmain(pdes,ineq_,forg,vl)$
- level_:=cons(2,level_)$
- if print_ then <<
- print_level()$
- terpri()$
- write "now back to the substitution of ",cdr w," by ",p$
- >>$
- pdes:=restore_pdes(cop)$
- if pairp h and (car h='TIMES) then ineq_:=union(cdr h,ineq_)
- else ineq_:=union(list h,ineq_)$
- setprop(q,nil);
- setprop(r,nil);
- if contradiction_ then <<
- contradiction_:=nil$
- l:=do_subst(md,p,w,pdes,ftem_,forg,vl,pdelimit)$
- if l and null car l then << % not contradiction but not used
- l1:=delete(p,l1);
- if l1 then <<
- pdes:=cadr l;
- forg:=caddr l;
- l:=nil;
- goto again
- >>
- >>;
- if l then l:=cdr l
- >> else <<
- cases_:=t$
- cop:=nil; % to save memory
- h:=crackmain(pdes,ineq_,forg,vl)$
- if contradiction_ then contradiction_:=nil
- else l:=union(h,l)
- >>
- >>$
- >>$
- return if contradiction_ then nil % list(nil,nil)
- else if cases_ then list l
- else l$
- end$
- symbolic procedure get_fact_pde(pdes)$
- % look for pde in pdes which can be factorized
- begin scalar m,p,pv,fdegl,pdeg,h,f,fcc,fcl,tf,pmdeg,fmdeg,tfm,fm,pm$
- m:=0; % counts how often the factor occurs that occurs most
- while pdes do <<
- p:=car pdes$ pdes:=cdr pdes$
- pv:=get(p,'val)$
- if pairp pv and (car pv='TIMES) then <<
- pv:=cdr pv$ % the list of factors in p
- fdegl:=for each f in pv collect
- pde_degree(f,smemberl(get(p,'rational),f))$
- pdeg:=for each h in fdegl sum h$
- for each f in pv do <<
- % counting how often f has occured as factor
- fcc:=fcl$
- while fcc and (caar fcc neq f) do fcc:=cdr fcc$
- if fcc then <<
- h:=add1 cadar fcc;
- rplaca(cdar fcc,h);
- >> else <<
- fcl:=cons({f,1,p},fcl);
- h:=1
- >>;
- tf:=nil;
- % Is f the best factor so far and p the best equation?
- if ( h>m ) or
- ((h=m ) and
- (( pdeg < pmdeg ) or
- (( pdeg = pmdeg ) and
- ((car fdegl < fmdeg ) or
- ((car fdegl = fmdeg ) and
- ((tf:=no_of_terms(f)) < tfm) ) ) ) ) ) then <<
- m:=h;
- fm:=f;
- pm:=p;
- pmdeg:=pdeg;
- fmdeg:=car fdegl;
- tfm:=if tf then tf
- else no_of_terms(f)$
- >>$
- fdegl:=cdr fdegl
- >>
- >>$
- >>$
- return if m=0 then nil
- else <<
- put(pm,'val,cons('TIMES,cons(fm,delete(fm,cdr get(pm,'val)))))$
- pm
- >>
- end$
- algebraic procedure start_let_rules$
- begin scalar ruli;
- ruli:={};
- let explog_$
- if sin(!%x)**2+cos(!%x)**2 neq 1 then <<ruli:=cons(1,ruli);let trig1_>> else ruli:=cons(0,ruli)$
- if cosh(!%x)**2 neq (sinh(!%x)**2 + 1) then <<ruli:=cons(1,ruli);let trig2_>> else ruli:=cons(0,ruli)$
- if sin(!%x)*tan(!%x/2)+cos(!%x) neq 1 then <<ruli:=cons(1,ruli);let trig3_>> else ruli:=cons(0,ruli)$
- if sin(!%x)*cot(!%x/2)-cos(!%x) neq 1 then <<ruli:=cons(1,ruli);let trig4_>> else ruli:=cons(0,ruli)$
- if cos(2*!%x) + 2*sin(!%x)**2 neq 1 then <<ruli:=cons(1,ruli);let trig5_>> else ruli:=cons(0,ruli)$
- if sin(2*!%x) neq 2*cos(!%x)*sin(!%x) then <<ruli:=cons(1,ruli);let trig6_>> else ruli:=cons(0,ruli)$
- if sinh(2*!%x) neq 2*sinh(!%x)*cosh(!%x) then <<ruli:=cons(1,ruli);let trig7_>> else ruli:=cons(0,ruli)$
- if cosh(2*!%x) neq 2*cosh(!%x)**2-1 then <<ruli:=cons(1,ruli);let trig8_>> else ruli:=cons(0,ruli)$
- return ruli;
- end$
- algebraic procedure stop_let_rules(ruli)$
- begin
- clearrules explog_$
- if first ruli = 1 then clearrules trig8_$ ruli:=rest ruli$
- if first ruli = 1 then clearrules trig7_$ ruli:=rest ruli$
- if first ruli = 1 then clearrules trig6_$ ruli:=rest ruli$
- if first ruli = 1 then clearrules trig5_$ ruli:=rest ruli$
- if first ruli = 1 then clearrules trig4_$ ruli:=rest ruli$
- if first ruli = 1 then clearrules trig3_$ ruli:=rest ruli$
- if first ruli = 1 then clearrules trig2_$ ruli:=rest ruli$
- if first ruli = 1 then clearrules trig1_$
- end$
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % procedures for finding an optimal substitution %
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- symbolic procedure fbts(a,b)$
- % fbts ... first better than second
- (cadr a <= cadr b) and
- (caddr a <= caddr b) and
- (cadddr a <= cadddr b);
- symbolic procedure list_subs(p,fevl,fli,mdu)$
- % p is an equation, fevl a substitution list of p,
- % fli is a list of lists (f,p1,p2,..) where
- % f is a function,
- % pi are lists (eqn,nco,nte,mdu) where
- % eqn is an equation that can be used for substituting f
- % nco is the number of terms of the coefficient of f in the eqn
- % nte is the number of terms without f in the eqn
- % mdu is the kind of substitution (1:lin, 2:nca, 3:nli)
- begin
- scalar a,f,nco,nte,cpy,cc,ntry;
- for each a in fevl do <<
- f:=cdr a;
- nco:=no_of_terms(car a);
- nte:=get(p,'terms);
- nte:=if nte=1 then 0
- else nte-nco$
- % Is there already any substitution list for f?
- cpy:=fli;
- while cpy and (f neq caar cpy) do cpy:=cdr cpy$
- ntry:={p,nco,nte,mdu}$
- if null cpy then fli:=cons({f,ntry},fli) % no, there was not
- else << % yes, there was one
- cc:=cdar cpy$
- while cc and (null fbts(car cc,ntry)) do cc:=cdr cc$
- if null cc then << % ntry is at least in one criterium better
- % than a known one
- rplaca(cpy,cons(f,cons(ntry,cdar cpy)));
- cc:=cdar cpy$ % just the list of derivatives with ntry as the first
- while cdr cc do
- if fbts(ntry,cadr cc) then rplacd(cc,cddr cc)
- else cc:=cdr cc$
- >>
- >>
- >>;
- return fli
- end$
- algebraic procedure cwrno(n,r)$
- % number of terms of (a1+a2+..+an)**r if ai are pairwise prime
- % number of combinations of r factors out of n possible factors
- % with repititions and without order = (n+r-1 over r)
- <<n:=n+r-1;
- % The rest of the procedure computes binomial(n,r).
- if 2*r>n then k:=n-r;
- for i:=1:r product (n+1-i)/i
- >>$
- symbolic procedure besu(ic1,mdu1,ic2,mdu2)$
- % Is the first substitution better than the second?
- ((mdu1<mdu2) and (ic1<=ic2)) or
- ((mdu1=mdu2) and (ic1< ic2)) or
- % ########## difficult + room for improvement as the decision is
- % actually dependent on how precious memory is
- % (more memory --> less cases and less time):
- ((mdu1=2) and (ic1<(ic2+ 4))) or
- ((mdu1=3) and (ic1<(ic2+25)))$
- symbolic procedure search_subs(pdes,cost_limit,no_cases)$
- begin
- scalar fli,p,el,f,fpl,dv,drf,d,ffl,hp,ff,nco,be,s,nte,ic,fp,
- rm,mc,subli,mdu,tr_search$
- % at first find the list of all functions that could be substituted
- % together with a list of pdes, the number of terms in the coeff and
- % the type of substitution
- % tr_search:=t$
- for each p in pdes do fcteval(p,nil)$
- fp:=pdes;
- while fp and
- ((get(car fp,'terms)>2) or
- (null get(car fp,'fcteval_lin)) ) do fp:=cdr fp;
- if fp then return {1,car fp,car get(car fp,'fcteval_lin)}$
- for each p in pdes do <<
- fli:=list_subs(p,get(p,'fcteval_lin),fli,1)$
- fli:=list_subs(p,get(p,'fcteval_nca),fli,2)$
- if null no_cases then fli:=list_subs(p,get(p,'fcteval_nli),fli,3)$
- >>$
- if tr_search then <<
- write"equations substitution: (eqn, no of coeff. t., no of other t., mdu)"$
- terpri()$
- for each el in fli do <<write el;terpri()>>$
- >>$
- if fli then
- if (null cdr fli) and % one function
- (null cddar fli) then % one equation, i.e. no choice
- return <<
- fli:=cadar fli; % fli is now (eqn,nco,nte,mdu)
- mdu:=cadddr fli;
- {mdu,car fli,car get(car fli,if mdu = 1 then 'fcteval_lin else
- if mdu = 2 then 'fcteval_nca else
- 'fcteval_nli) }
- >> else
- % (more than 1 fct.) or (only 1 function and more than 1 eqn.)
- for each el in fli do << % for any function to be substituted
- % (for the format of fli see proc list_subs)
- f:=car el$ el:=cdr el$
- % el is now a list of possible eqn.s to use for subst. of f
- fpl:=nil$ % fpl will be a list of lists (p,hp,a1,a2,..) where
- % p is an equation that involves f,
- % hp the highest power of f in p
- % ai are lists {ff,cdr d,nco} where ff is a derivative of f,
- % cdr d its power and nco the number of coefficients
- for each p in pdes do << % for each equation in which f could be subst.
- dv:=get(p,'derivs)$ % ((fct var1 n1 ...).pow)
- drf:=nil$
- for each d in dv do
- if caar d = f then drf:=cons(d,drf)$
- % drf is now the list of powers of derivatives of f in p
- ffl:=nil$ % ffl will be a list of derivatives of f in p
- % together with the power of f and number of
- % terms in the coeff.
- if drf then << % f occurs in this equation and we estimate the increase
- hp:=0$
- for each d in drf do <<
- if cdar d then ff:=cons('DF,car d)
- else ff:=caar d;
- nco:=no_of_terms(coeffn(get(p,'val),ff,cdr d));
- if cdr d > hp then hp:=cdr d$
- ffl:=cons({ff,cdr d,nco},ffl);
- >>
- >>;
- if drf then fpl:=cons(cons(p,cons(hp,ffl)),fpl);
- >>$
- % now all information about all occurences of f is collected and for
- % all possible substitutions of f the cost will be estimated and the
- % cheapest substitution for f will be determined
- be:=nil; % be will be the best equation with an associated min. cost mc
- for each s in el do <<
- % for each possible equation that can be used to subst. for f
- % number of terms of (a1+a2+..+an)**r = n+r-1 over r
- % f = (a1+a2+..+a_nte) / (b1+b2+..+b_nco)
- nco:=cadr s;
- nte:=caddr s;
- ic:= - get(car s,'terms); % ic will be the cost associated with
- % substituting f by car s and car s
- % will be dropped after the substitution
- for each fp in fpl do
- if (car s) neq (car fp) then <<
- rm:=get(car fp,'terms); % to become the number of terms without f
- hp:=cadr fp;
- ic:=ic - rm; % as the old eqn. car fp will be replaced
-
- for each ff in cddr fp do << % for each power of each deriv. of f
- ic:=ic + (caddr ff)* % number of terms of coefficient of ff
- cwrno(nte,cadr ff)* % (numerator of f)**(power of ff)
- cwrno(nco,hp - cadr ff); % (denom. of f)**(hp - power of ff)
- rm:=rm - caddr ff; % caddr ff is the number of terms with ff
- >>;
- % Now all terms containing f in car fp have been considered. The
- % remaining terms are multiplied with (denom. of f)**hp
- ic:=ic + rm*cwrno(nco,hp)
- >>;
- % Is this substitution better than the best previous one?
- if (null be) or besu(ic,cadddr s,mc,mdu) then
- <<be:=car s; mc:=ic; mdu:=cadddr s>>;
- >>;
- % It has been estimated that the substitution of f using the
- % best eqn be has an additional cost of ic terms
- if tr_search and (length el > 1) then <<
- terpri()$
- write"Best substitution for ",f," : ",{ic,f,be,mdu}$
- >>$
- if (null cost_limit) or (ic<cost_limit) then
- subli:=cons({ic,mdu,f,be},subli)$
- >>$
-
- % Now pick the best substitution
- if subli then <<
- s:=car subli;
- subli:=cdr subli;
- for each el in subli do
- if besu(car el,cadr el,car s,cadr s) then s:=el$
- if tr_search then <<
- terpri()$
- write"Optimal substitution:"$terpri()$
- write" replace ",caddr s," with the help of ",cadddr s,","$terpri()$
- if car s < 0 then write" saving ", - car s," terms, "
- else write" with a cost of ",car s," additional terms, "$
- terpri()$
- write if cadr s = 1 then " linear substitution" else
- if cadr s = 2 then " nonlinearity inceasing substitution" else
- " with case distinction" $
- >>$
- el:=get(cadddr s,if (cadr s) = 1 then 'fcteval_lin else
- if (cadr s) = 2 then 'fcteval_nca else
- 'fcteval_nli);
- while (caddr s) neq (cdar el) do el:=cdr el;
- return {cadr s,cadddr s,car el}
- % = {mdu ,p ,car get(p,'fcteval_???)}
- >>$
- end$
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- % procedures for substitution of a derivative by a new function %
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- symbolic procedure check_subst_df(pdes,forg)$
- % yields a list of derivatives which occur in all
- % pdes and in forg
- begin scalar l,l1,l2,n,cp,not_to_substdf$
- if pdes then <<
- for each s in pdes do l:=union(for each a in get(s,'derivs)
- collect car a,l)$ % all derivs
- for each s in forg do
- if pairp s then l:=union(for each a in all_deriv_search(s,ftem_)
- collect car a,l)$
- l1:=df_min_list(l)$
- l:=nil$
- for each s in l1 do
- if pairp s and not member(car s,not_to_substdf) then <<
- l:=cons(cons('DF,s),l)$
- not_to_substdf:=cons(car s,not_to_substdf)
- >> $
- % Derivatives of functions should only be substituted if the
- % function occurs in at least 2 equations
- while l do <<
- n:=0; % counter
- cp:=pdes;
- while cp and (n<2) do <<
- if member(car l,get(car cp,'fcts)) then n:=add1 n;
- cp:=cdr cp
- >>;
- if n=2 then l2:=cons(car l,l2);
- l:=cdr l
- >>
- >>$
- return l2$
- end$
- symbolic procedure df_min_list(dflist)$
- % yields the lowest derivative for each function in the list of
- % deriv. dflist.
- % e.g. dflist='((f x z) (g x) (g) (f y) (h x y) (h x z))
- % ==> result='(f g (h x))
- if dflist then
- begin scalar l,d,m,lmax$
- while dflist do
- <<m:=car dflist$
- dflist:=cdr dflist$
- l:=nil$
- while dflist do
- <<if (d:=df_min(car dflist,m)) then m:=d
- else l:=cons(car dflist,l)$
- dflist:=cdr dflist$
- >>$
- if pairp m and null cdr m then lmax:=cons(car m,lmax)
- else lmax:=cons(m,lmax)$
- dflist:=l$
- >>$
- return lmax$
- end$
- symbolic procedure df_min(df1,df2)$
- % yields the minimal derivative of d1,d2
- % e.g. df_min('(f x y),'(f x z))='(f x), df_min('(f x z),'(g x))=nil
- <<if not pairp df1 then df1:=list df1$
- if not pairp df2 then df2:=list df2$
- if car df1=car df2 then
- if (df1:=df_min1(cdr df1,cdr df2)) then cons(car df2,df1)
- else car df2>>$
- symbolic procedure df_min1(df1,df2)$
- begin scalar l,a$
- while df1 do
- <<a:=car df1$
- if not zerop (a:=min(dfdeg(df1,car df1),dfdeg(df2,car df1))) then
- l:=cons(car df1,l)$
- if a>1 then l:=cons(a,l)$
- df1:=cdr df1$
- if df1 and numberp car df1 then df1:=cdr df1>>$
- return reverse l$
- end$
- symbolic procedure dfsubst_forg(p,g,d,forg)$
- % substitute the function d in forg by an integral g
- % of the function p
- for each h in forg collect
- if pairp h and member(d,get(cadr h,'fcts)) then
- <<put(cadr h,'fcts,
- cons(p,delete(d,get(cadr h,'fcts))))$
- reval subst(g,d,h)>>
- else h$
- symbolic procedure expand_INT(p,varlist)$
- if null varlist then p
- else begin scalar v,n$
- v:=car varlist$
- varlist:=cdr varlist$
- if pairp(varlist) and numberp(car varlist) then
- <<n:=car varlist$
- varlist:=cdr varlist>>
- else n:=1$
- for i:=1:n do p:=list('INT,p,v)$
- return expand_INT(p,varlist)
- end$
- endmodule$
- end$
|