mrvlimit.red 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. %----------------------------------------------------------------------------
  2. % |
  3. % Source code for a new Exp-Log limits package in REDUCE |
  4. % |
  5. % Author: Neil Langmead |
  6. % Place: ZIB, Berlin |
  7. % Date: April 1997 |
  8. % e/mail: langmead@zib.de |
  9. % |
  10. % all bugs and comments or suggestions please report to Winfried Neun, |
  11. % ZIB, Takustrasse 7, D-14195, Berlin Dahlem, Germany: e/mail neun@zib.de |
  12. %----------------------------------------------------------------------------
  13. module mrvlimit;
  14. create!-package ('(mrvlimit expon),nil);
  15. global '(tracelimit!*); % for the tracing facility)
  16. switch tracelimit;
  17. off tracelimit; % off by default
  18. flag('(sqchk),'opfn);
  19. %symbolic procedure max_power(f,x);
  20. % if domainp f then 0 else
  21. % if mvar f eq x then ldeg f else
  22. % max(max_power(lc f,x),max_power(red f,x))
  23. %put('max2,'psopfn,'max_power)
  24. load_package limits;
  25. load_package sets;
  26. algebraic;
  27. off mcd;
  28. %in "/silo/neil/test.red";
  29. symbolic procedure maxi(f,g);
  30. begin scalar c;
  31. if(freeof(f,'x)) then return g;
  32. if(freeof(g,'x)) then return f;
  33. if(f=g) then return f else
  34. <<
  35. if(null f) then return g else
  36. <<
  37. if(null g) then return f
  38. else <<
  39. if (intersection(f,g) neq '(list)) then return union(f,g)
  40. else <<
  41. if(evalb('x member f)='true) then return g
  42. else <<
  43. if(evalb('x member g)='true) then return f
  44. else <<
  45. if(car f='list and cadr f='list) then % double list
  46. << % only want caddr f to be given to compare
  47. c:=compare(caddr f,cadr g);
  48. %write "c is ", c; write length(c)
  49. return c;
  50. >>
  51. else <<
  52. if(car g='list and cadr g='list) then
  53. <<
  54. c:=compare(cadr f,caddr g);
  55. %write "c is ", c;
  56. return c;
  57. >>
  58. else <<
  59. c:=compare(cadr f, cadr g);
  60. %write "c is ", c;
  61. return c;
  62. >>;
  63. >>;
  64. %if(c=cadr f) then return cadr f else <<
  65. % if(c=cadr g) then return (cadr g)
  66. % else return union(cdr f,cdr g);
  67. % >>;
  68. >>;
  69. >>;
  70. >>;
  71. >>;
  72. >>;
  73. >>;
  74. end; % of max
  75. %max
  76. %-------------------------------------------------------------------------
  77. algebraic;
  78. procedure maxi1(f,g); lisp cadr (lisp (list('list,maxi(f,g))));
  79. algebraic;
  80. expr procedure compare(f,g);
  81. begin scalar logg, logf;
  82. logf:=log(f);
  83. logg:=log(g);
  84. if(mrv_limit(logf/logg,x,infinity)=0) then return {g} else <<
  85. if(mrv_limit(logg/logf,x,infinity)=0) then return {f} else
  86. return {f,g}; >>;
  87. end;
  88. procedure comp(f,g); lisp('list.compare(f,g));
  89. %----------------------------------------------------------------------------
  90. load_package assist;
  91. symbolic procedure mrv(li);
  92. begin
  93. off mcd; on factor;
  94. % The next line doesn't do anything in symbolic mode. Presumably li
  95. % should be simplified in some way. However, li is not always an
  96. % algebraic expression. Sometimes it is a list of one, or a list of a
  97. % number.
  98. li:=li;
  99. if(numberp li) then return nil else <<
  100. if(li='(list)) then return nil else <<
  101. if(atom li) then return lisp ('list.{li}) else <<
  102. if(car li='times) then <<
  103. if(atom cadr li and atom caddr li) then
  104. << if(length(cddr li)=1) then
  105. return lisp ('list.maxi1({cadr li}, {caddr li}))
  106. else return maxi1({cadr li},mrv(cddr li))
  107. >>
  108. else return maxi1(mrv(cadr li), mrv(cddr li))
  109. >>
  110. else <<
  111. if(car li='minus) then <<
  112. if(atom cadr li) then return 'list.{cadr li} else return
  113. mrv(cadr li)
  114. >>
  115. %return mrv(append({'plus},cdr li))
  116. else <<
  117. if(car li='plus) then <<
  118. %if(null caddr li) then return mrv(cadr li)
  119. if(length cdr li=1) then %only one argument to plus
  120. return mrv(cadr li) else <<
  121. if(atom cadr li and atom caddr li) then
  122. << if(length(cddr li)=1) then return
  123. lisp ('list.maxi1({cadr li},{caddr li}))
  124. else return
  125. lisp ('list.maxi1({cadr li},mrv(append({'plus},cddr li))))
  126. >>
  127. else <<
  128. if(atom cadr li and pairp caddr li) then
  129. return
  130. maxi1('list.{cadr li}, mrv(cddr li)) % here as well
  131. else <<
  132. if(pairp cadr li and null caddr li) then return mrv(cadr li) else
  133. <<
  134. if(pairp cadr li and atom caddr li) then
  135. <<
  136. if(length(cdr li)>2) then % we have plus with > two args
  137. return lisp cdr ('list.maxi1(mrv(cadr li),mrv(append({'plus},cddr li)))) %her
  138. else
  139. return lisp cdr ('list.maxi1(mrv(cadr li), mrv(cddr li))) >>
  140. else
  141. << if(null caddr li) then return mrv(cadr li)
  142. else return maxi1(mrv(cadr li), mrv(append({'plus},cddr li))) >>
  143. >>
  144. >>
  145. >>
  146. >>
  147. >>
  148. else <<
  149. if(car li='expt) then <<
  150. if(cadr li neq 'e) then
  151. return mrv(cadr li)
  152. else << %we have e to the power of something
  153. if sqchk mrv_limit(caddr li,'x,'infinity)
  154. eq 'infinity
  155. then
  156. return
  157. maxi1('list.{li},mrv(caddr li)) else
  158. <<
  159. if sqchk mrv_limit(caddr li,'x,'infinity)
  160. = '(minus infinity)
  161. then
  162. return maxi1('list.{li},'list.mrv(cddr li)) else return
  163. mrv(caddr li)
  164. >>
  165. >>
  166. >>
  167. else << if(car li='log) then
  168. << if(atom cadr li) then return mrv(cadr li) else
  169. return mrv(cdr li)
  170. >> else <<
  171. if(car li='sqrt) then return mrv(cdr li) else
  172. return mrv(car li)
  173. >>
  174. >>
  175. >>
  176. >>
  177. >> % for minus
  178. >> %for null
  179. >> % for numberp
  180. >>;
  181. off mcd;
  182. end; % of mrv
  183. algebraic;
  184. procedure mrv1(li); lisp (mrv(li));
  185. %----------------------------------------------------------------------------
  186. % procedure to return a list of subexpressions of exp
  187. % this will then be used for the mrv function
  188. symbolic procedure flatten(li);
  189. % This procedure turns a list with possibly nested sub_lists into a single
  190. % List with no nested sub-lists. Easier to search this list.
  191. makeflat(li,nil);
  192. symbolic procedure makeflat(li,answer);
  193. if li=nil then nil
  194. else
  195. if atom li then li.answer
  196. else if (cdr li)=nil then makeflat(car li,answer)
  197. else append(makeflat(car li,answer),makeflat(cdr li,answer));
  198. algebraic;
  199. procedure flat(li); lisp(flatten li);
  200. procedure mkflat(li); lisp(makeflat(li,nil));
  201. %in "max";
  202. %trst maxi;
  203. symbolic procedure lim(exp,var,val);
  204. begin scalar mrv_list, rule;
  205. mrv_list:=mrv1(exp);
  206. if(mrv_list='(list)) then rederr "unable to compute mrv set"
  207. else
  208. <<
  209. rule:=list(list ('replaceby, cdr mrv_list,'w));
  210. let rule;
  211. >>;
  212. end;
  213. % nedd to consider if x belongs to mrv(exp), then follow rest of alg.
  214. algebraic;
  215. expr procedure move_up(exp,x);
  216. sub({log(x)=x,x=e^x},exp);
  217. expr procedure move_down(exp,x);
  218. sub({e^x=x,x=log(x)},exp);
  219. %off mcd;
  220. algebraic;
  221. expr procedure rewrite(m);
  222. begin scalar ans_list,summ,k,g,c,A;
  223. ans_list:={};
  224. g:=part(m,1); write length g;
  225. for k:=1:arglength(m) do
  226. <<
  227. summ:=length(den(part(m,k)))+length(num(part(m,k))); write summ;
  228. if(summ<(length(den(g))+length(num(g)))) then g:=part(m,k);
  229. >>;
  230. write "g is ", g;
  231. %for each f in m do <<
  232. % if(length(f)<length(g)) then g:=f;
  233. % >>;
  234. % % gets smallest element in the list
  235. %write "g is ", g;
  236. %if(limit(g,x,infinity)=infinity) then g:=1/g; write "g is ", g;
  237. for each f in m do
  238. <<
  239. c:=limit(log(f)/log(g),x,infinity);
  240. A:=e^(log(f)-c*log(g));
  241. f:=A*w^c;
  242. ans_list:=append({f}, ans_list);
  243. >>;
  244. return ans_list;
  245. end;
  246. %trst rewrite
  247. %rewrite({e^(-x),e^x})
  248. %h:=e^(-x/(1+e^-x))
  249. %rewrite({e^(x-h),e^-(x/(1+h)),h,e^x,e^(-x)})
  250. expr procedure smallest(li);
  251. begin scalar current,k;
  252. current:=part(li,1);
  253. for k:=1:arglength(li) do <<
  254. if(length(current)>length(part(li,k))) then
  255. current:=part(li,k);
  256. >>;
  257. return current;
  258. end;
  259. expr procedure smallest(li);
  260. begin scalar l1,l2;
  261. if(length li=1) then return part(li,1) else
  262. <<
  263. l1:=lngth2(part(li,1));
  264. l2:=lngth2(part(li,2));
  265. if(l1>l2) then return part(li,2) else
  266. << if(l1<l2) then return part(li,1) else return part(li,1); >>;
  267. >>;
  268. end;
  269. symbolic procedure lngth u;
  270. begin
  271. if(u='list) then return nil else
  272. <<
  273. if(atom u) then return 1 else
  274. <<
  275. if(atom car u) then return (1+lngth cdr u)
  276. else return lngth car u + lngth cdr u;
  277. >>;
  278. >>;
  279. end;
  280. %put('lngth2,'psopfn,'lngth);
  281. algebraic;
  282. procedure lngth2 u; lisp lngth u;
  283. %-------------------------------------------------------------------------
  284. % main routine to compute limits of exp-log functions as the variable tends
  285. % to infinity.
  286. operator x;
  287. operator series;
  288. algebraic;
  289. expr procedure mrv_limit(f,var,val);
  290. begin scalar mrv_f,mrv1_f,w, mrv_f2,tt, lead_term, series_exp,f1, small, rule1,
  291. const, e0,sig,rule2,k, nu,de,h,recurse;
  292. off mcd; off factor; off rational; off exp; off precise;
  293. %if(val neq infinity) then return sub(var=val,f);
  294. % trigonometric expressions aren't dealt with by the algorithm
  295. if(not(freeof(f,sin))) then rederr "input not an exp log function";
  296. if(not(freeof(f,cos))) then rederr "input not an exp log function";
  297. if(not(freeof(f,tan))) then rederr "input not an exp log function";
  298. if(freeof(f,var)) then % possible cases: f can be a number, an expression
  299. % independent of var, or possibly not an exp log
  300. % function. In all cases, return f as the answer
  301. return f;
  302. if(val neq infinity) then return sub(var=val,f);
  303. %on rational;
  304. %on rounded;
  305. %this checks for numbers. red doesn't recognise some objects as numbers unless
  306. % the rounded switch is on
  307. f1:=f; if(numberp(f1)) then return f; off rational;
  308. off rounded;
  309. %off mcd;
  310. %on rational;
  311. %on rounded; % maybe a risk, but we'll try it
  312. if(var neq x) then f:=sub(var=x,f) else nil;
  313. if(numberp(f)) then return f;
  314. %%%% special case where f=e, or pi. Don't want to use the on rounded switch
  315. %%%% in these cases
  316. if(f=e) then return e;
  317. if(f=pi) then return pi;
  318. %if(f=x) then return plus_infinity;
  319. on factor; off mcd; mrv_f:=mrv1(f);
  320. %write "*********************************************************************";
  321. if(lisp !*tracelimit) then
  322. write "mrv_f is ", mrv_f;
  323. %write "*********************************************************************";
  324. off factor;
  325. %on mcd;
  326. if(member(x,mrv_f)) then
  327. <<
  328. off exp; off mcd;
  329. while(member(x,mrv_f)) do
  330. <<
  331. f:=move_up(f,x); %write "f is ", f;
  332. %mrv_f:=mrv1(f);
  333. mrv_f:=for k:=1:arglength(mrv_f) collect move_up(part(mrv_f,k),x);
  334. %write "mrv is ", mrv_f;
  335. >>;
  336. % we know that x was a member of mrv(f), so now, the mrv set will contain
  337. % e^x at least. Hence, write directly in terms of w=e^(-x)
  338. %mrv_f2:=rewrite(mrv_f); % write mrv_f2;
  339. small:=e^(-x);
  340. % now have the smallest element, but don't know its limiting behaviour
  341. % if lim is infinity, need to set w to 1/small
  342. rule1:={small => ww };
  343. let rule1;
  344. f:=f;
  345. on mcd; nu:=num(f); de:=den(f); f:=nu/de; off mcd;
  346. f:=f; % write f;
  347. clearrules rule1;
  348. % f now rewritten
  349. >>
  350. else <<
  351. %mrv_f2:=rewrite(mrv_f); % write "f2 is ", mrv_f2;
  352. % now need to rewrite f itself
  353. small:=smallest(mrv_f);
  354. h:=log(small); %write "h is ", h;
  355. if(mrv_limit(h,x,infinity)=infinity) then
  356. <<
  357. small:=small^-1;
  358. % write "small has been changed", small;
  359. >>;
  360. rule1:=
  361. {
  362. small => ww,
  363. 1/small => ww^-1
  364. };
  365. let rule1; off mcd;
  366. %write "smallest f is ", small;
  367. f:=f;
  368. on mcd;
  369. % de:=den(f); nu:=num(f);
  370. % f:=nu/de;
  371. off mcd; %f:=f;
  372. clearrules rule1;
  373. %write "f is ", f;
  374. % now rewritten in terms of w, and mrv(f)=w hopefully
  375. >>;
  376. % at this point, f has been rewritten. Now check lcof of series expansion
  377. % lisp !*mcd:=nil; lisp !*factor:=nil; lisp !*exp:=t; lisp !*rational:=nil;
  378. off mcd; on factor; off exp; off rational;
  379. series_exp:=taylor(f,ww,0,1);
  380. if(lisp !*tracelimit) then
  381. write "performing taylor on: ", f;
  382. %off mcd; on exp; on factor; off rational;
  383. if(not taylorseriesp series_exp and part(series_exp,0)=taylor)
  384. then rederr "could not compute the Taylor series expansion";
  385. tt:=log(small); %write "tt is ", tt;
  386. series_exp:=sub(log(ww)=tt,series_exp); %off mcd; off factor; off exp;
  387. series_exp:=taylortostandard series_exp;
  388. if(lisp !*tracelimit) then write "series expansion is ", series_exp;
  389. % should now have the lead term of the series expansion in terms of w
  390. if(numberp(series_exp)) then return series_exp
  391. else <<
  392. if(lisp !*tracelimit) then
  393. write "series is ", series_exp;
  394. off rational; off mcd; off exp; off factor;
  395. series_exp:=series_exp; off factor;
  396. const:=coeffn(series_exp,ww,0); %write "const is ", const;
  397. if(const neq 0) then
  398. <<
  399. if(numberp(const)) then return const else
  400. <<
  401. if(lisp !*tracelimit) then
  402. write "performing recursion on ", const;
  403. off mcd; on factor; off exp; on rational; const:=const;
  404. return mrv_limit(const,x,infinity); >>;
  405. >>
  406. else
  407. <<
  408. % need to look at exponent of ww. If e0>0 then return 0, if
  409. % e0<0 return infinity, if e0=0 return mrv_limit(c)
  410. %write "series_exp is ", series_exp;
  411. series exp:=series_exp; off mcd; % try it here!
  412. %if(lisp !*tracelimit) then
  413. %write "series exp is ", series_exp;
  414. % series_exp:=lisp reval series_exp;
  415. %off mcd;
  416. e0:=find_least_expt(series_exp);
  417. if(lisp !*tracelimit) then write "leading exponent e0 is ", e0;
  418. off mcd; on factor; off exp; off rational;
  419. %if(part(e0,1)=expt) then
  420. %<< e0:=part(e0,2);
  421. %e0:=part(e0,1); if(e0=e) then return e;
  422. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  423. %
  424. % possible cases: e0:={expt_list,num_list,x_list}
  425. % if both num_list and x_list are empty, then e0 takes the value of the
  426. % smallest exponent in expt_list.
  427. % if numbers in expt_list are all positive, then e0 is the value in either
  428. % num_list, or expt_list: if num_list, then this number is returned, if
  429. % expt_list, then we apply algorithm recusively to the value of x_exp
  430. %
  431. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  432. if(part(e0,1)=expt) then <<
  433. e0:=part(e0,2);
  434. %if(not numberp e0) then return part(e0,2);
  435. if(e0<0 and ((lisp car series_exp) neq minus))
  436. then return infinity else
  437. << %*sign(lcof(series_exp,ww))
  438. if(e0<0) then return -infinity
  439. else
  440. <<
  441. if(e0>0) then return 0 else <<
  442. off mcd; off factor; off rational; on exp;
  443. recurse:=lcof(series_exp,ww); return
  444. mrv_limit(recurse,x,infinity); >>;
  445. >>;
  446. >>;
  447. >>
  448. else <<
  449. if(part(e0,1)=number) then return part(e0,2) else
  450. <<if sqchk part(e0,1) = 'minus then return -infinity else nil>>
  451. >>;
  452. e0:=lpower(series_exp,ww); off mcd;
  453. % expr free of neg powers ? sort of
  454. if(numberp e0) then <<
  455. on mcd; on exp; e0:=lpower(num series_exp,ww)/lpower(den series_exp,ww);
  456. off mcd; e0:=e0; >>;
  457. % if(numberp e0) then << % we have to go back to series_exp
  458. % on mcd; on rational; series_exp:=series_exp;
  459. % temp:=lpower(num(series_exp),ww)/lpower(den(series_exp),ww);
  460. % off mcd; temp:=temp; e0:=temp; lisp (e0:=lisp prepsq cadr e0);
  461. % >>
  462. % if(numberp(e0)) then <<
  463. % if(e0>0) then return infinity else <<
  464. %if(e0<0) then return -infinity else return 0 >>;
  465. % >>;
  466. % >>;
  467. lisp (e0:=lisp prepsq cadr e0);
  468. % off rational; off mcd; series_exp:=series_exp;
  469. %write "series_exp is ", series_exp;
  470. if(e0=ww) then return 0 else
  471. <<
  472. if(part(e0,0)=expt) then
  473. <<
  474. if(part(e0,2)<0) then % have plus /minus infinity
  475. <<
  476. %write "sign is ", sign(lcof(series_exp,ww));
  477. %write "expt is ", part(e0,2);
  478. if(sign(lcof(series_exp,ww))=-1) then
  479. return -infinity else << if
  480. (sign(lcof(series_exp,ww))=1) then return infinity
  481. else <<
  482. rule2:= {
  483. sign(log(~x)) => 1
  484. };
  485. let rule2;
  486. sig:=sign(lcof(series_exp,ww));
  487. clearrules rule2;
  488. return infinity;
  489. >>;
  490. >>;
  491. >>
  492. else
  493. <<
  494. if(part(e0,2)>0) then return 0 else
  495. % the limiting behaviour of f depends on that of c
  496. << on rational;
  497. off mcd; return mrv_limit(lcof(series_exp,ww),x,infinity); >>;
  498. >>;
  499. >>;
  500. >>;
  501. >>;
  502. >>;
  503. off mcd;
  504. end;
  505. %---------------------------------------------------------------------------
  506. %a:=log(w^-1+x)-x
  507. %a:=a*w^-1
  508. %a:=a/(log(w^-1+log(x)))
  509. %taylor(a,w,0,3)
  510. %off mcd
  511. %my_limit(e^-x,x,infinity)
  512. %clear ww
  513. %off mcd
  514. %my_limit(e^x,x,infinity)
  515. %trst my_limit
  516. %ex:=log(log(x)+log(log(x)))-log(log(x))
  517. %ex:=ex/(log(log(x)+log(log(log(x)))))
  518. %ex:=ex*log(x)
  519. % now need to see about the recursion part. Create test file, and sort out
  520. % mrv function, and sort out extensions.
  521. %trst mrv
  522. %trst my_limit
  523. %-----------------------------------------------------------------------------
  524. % for examples, please see the test flie included with the documentation. The
  525. % examples labelled from ex1 to ex12 are all taken from Dominik Gruntz' Thesis
  526. % paper. Most are complicated examples, as he himself admits. This package
  527. % does not use the standard limits operator in REDUCE: it has been written to
  528. % be independent, and can be presented as a separted facility in REDUCE.
  529. %-----------------------------------------------------------------------------
  530. endmodule;
  531. end;
  532. expr procedure test(exp);
  533. if(freeof(exp,ww^-1) and freeof(exp,ww^-2)) then t else nil;
  534. % we need a procedure to determine if an expression is free of negative
  535. % powers of w
  536. %$symbolic procedure free_of_neg_power(exp,var);
  537. %if(freeof(exp,ww^a)) then t else nil where numberp(a) and a<0;
  538. %procedure free(exp,var); lisp free_of_neg_power(exp,var);
  539. end;
  540. symbolic procedure least_exp(exp);
  541. begin scalar expon,base,temp,expon2;
  542. expon:=0;
  543. while(exp) do <<
  544. if(car exp='expt) then
  545. <<
  546. base:=cadr exp;
  547. temp:=caddr exp;
  548. if(temp<=expon) then expon:=temp;
  549. >> else << while exp do << exp:=cdr exp; return least_exp(exp); >>;
  550. >>;
  551. return expon;
  552. end;
  553. procedure least(exp); lisp least_exp(exp);