plotexp2.red 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. module plotexp2; % Compute explicit 2-dim graph y=f(x);
  2. symbolic procedure ploteval2x(x,y);
  3. begin scalar xlo,xhi,ylo,yhi,rx,ry,fp,fcn,fcns,pts;
  4. if y='implicit then
  5. rederr "no implicit plot in one dimension";
  6. rx:=plotrange(x,
  7. reval(plot_xrange or '(!*interval!* -10 10)));
  8. xlo:=car rx;
  9. xhi:=cadr rx;
  10. fcns:= reverse plotfunctions!*;
  11. ry:=plotrange(y, reval(plot_yrange or nil));
  12. if ry then <<ylo:=car ry; yhi:=cadr ry>>;
  13. while fcns do
  14. <<fcn := car fcns; fcns := cdr fcns;
  15. if eqcar(fcn,'points) then fp:=caddr fcn . fp else % WN 25.9.98
  16. pts:=ploteval2x1(cdr fcn,x,xlo,xhi,ylo,yhi).pts;
  17. >>;
  18. plotdriver(plot!-2exp,x,y,pts,fp);
  19. end;
  20. symbolic procedure ploteval2x1(f,x,xlo,xhi,ylo,yhi);
  21. begin scalar plotsynerr!*,l,d,d0,u,v,vv,p,mx,mn,ff;
  22. scalar plotderiv!*;
  23. integer nx;
  24. % compute algebraic derivative.
  25. ff:= errorset({'reval,mkquote {'df,f,x}},nil,nil);
  26. if not errorp ff and not smemq('df,car ff) then
  27. % Hier irrte Goethe. % This comment is for Herbert, please keep it
  28. % plotderiv!*:= rdwrap plotderiv!* . plotderiv!*;
  29. plotderiv!*:= rdwrap car ff . car ff;
  30. ff:=rdwrap f;
  31. p:=float (nx:=plot!-points(x));
  32. d:=(d0:=(xhi-xlo))/p;
  33. v:=xlo;
  34. for i:=0:nx do
  35. <<vv:=if i=0 or i=nx then v
  36. else v+d*(random(100)-50)*0.001;
  37. u:= plotevalform(ff,f,{x.vv});
  38. if plotsynerr!* then typerr(f,"function to plot");
  39. if eqcar(u,'overflow) then u:=nil;
  40. if u then
  41. <<
  42. if yhi and u>yhi then u:=yhi else
  43. if ylo and u<ylo then u:=ylo;;
  44. if null mx or u>mx then mx:=u;
  45. if null mn or u<mn then mn:=u
  46. >>;
  47. l:=(vv.u).l;
  48. v:=v+d;
  49. >>;
  50. if null mx or null mn then rederr "plot, sampling failed";
  51. variation!* :=
  52. if yhi and not(yhi=plotmax!*) then (yhi-ylo) else
  53. (mx-mn); % ploteval2xvariation l;
  54. if plot!-refine!*>0 then
  55. l:=smooth(reversip l,ff,f,x,mx,mn,ylo,yhi,d);
  56. return {for each x in l collect {car x,cdr x}};
  57. end;
  58. symbolic procedure ploteval2xvariation l;
  59. begin scalar u;
  60. % compute geometric mean value.
  61. integer m;
  62. u:=1.0;
  63. for each p in l do
  64. <<m:=m+1; p:=cdr p;
  65. if p and p neq 0.0 then u:=u*abs p;
  66. >>;
  67. return expt(u,1/float m);
  68. end;
  69. symbolic procedure smooth(l,ff,f,x,maxv,minv,ylo,yhi,d);
  70. begin scalar rat,grain,cutmax,cutmin,z,z0;
  71. z:=l;
  72. cutmax := yhi or (- 2*minv + 3*maxv);
  73. cutmin := ylo or (3*minv - 2*maxv);
  74. grain := variation!* *0.05;
  75. rat := d / if numberp maxv and maxv > minv then (maxv - minv)
  76. else 1;
  77. % Delete empty points in front of the point list.
  78. while z and null cdar z and cdr z and null cdadr z do z:=cdr z;
  79. % Find left starting point if there is no one yet.
  80. if z and null cdar z and cdr z then
  81. <<z0:= findsing(ff,f,x,ylo,yhi,cadr z,car z);
  82. if z0 then l:=z:=z0.cdr z;
  83. >>;
  84. while z and cdr z do
  85. <<z0:=z; z:=cdr z;
  86. smooth1(z0,ff,f,x,cutmin,cutmax,grain,rat,0,plot!-refine!*)
  87. >>;
  88. return l;
  89. end;
  90. symbolic procedure smooth1(l,ff,f,x,minv,maxv,g,rat,lev,ml);
  91. smooth2(l,ff,f,x,minv,maxv,g,rat,lev,ml);
  92. symbolic procedure smooth2(l,ff,f,x,minv,maxv,g,rat,lev,ml);
  93. if lev >= ml then
  94. smooth3(l,ff,f,x,minv,maxv,g,rat,lev,ml)
  95. else
  96. if null cdar l then t else
  97. begin scalar p0,p1,p2,p3,x1,x2,x3,y1,y2,y3,d;
  98. scalar dy12,dy32,dx12,dx32,z,a,w;
  99. %%%%% fdeclare(x1,x2,x3,y1,y2,y3,rat,d,dx12,dx32,dy12,dy32);
  100. lev:= add1 lev;
  101. p1:=car l; p3:=cadr l;
  102. x1:=car p1; y1:=cdr p1;
  103. x3:=car p3; y3:=cdr p3;
  104. nopoint:
  105. if null y3 then
  106. <<if null cddr l then return(cdr l:=nil);
  107. x2:=x3; y2:=y3; cdr l:=cddr l;
  108. p3:=cadr l; x3:=car p3; y3:=cdr p3;
  109. if y3 then goto outside else goto nopoint;
  110. >>;
  111. % Generate a new point
  112. x2:=(x1+x3)*0.5;
  113. if null (y2 := plotevalform(ff,f,{x.x2}))
  114. or eqcar(y2,'overflow) then goto outside;
  115. if y2 < minv or y2 > maxv then goto outside;
  116. dy32 := (y3 - y2) * rat; dx32 := x3 - x2;
  117. dy12 := (y1 - y2) * rat; dx12 := x1 - x2;
  118. %% extremely careful here !! see : plot(e^(x/(2-x)),x);
  119. %% WN 29. 9.99
  120. w := errorset({'times2,dy32,dy32},nil,nil);
  121. if ploterrorp w then goto disc else w:=car w;
  122. d := errorset({'times2,dy12,dy12},nil,nil);
  123. if ploterrorp d then goto disc else d:=car d;
  124. w := (w + dx32**2);
  125. d := (d + dx12**2);
  126. d:= errorset({'times2,w,d},nil,nil);
  127. if ploterrorp d then goto disc else d:=car d;
  128. d := sqrt d;
  129. %% original d := sqrt((dy32**2 + dx32**2) * (dy12**2 + dx12**2));
  130. if zerop d then return t;
  131. w := (dy32*dy12 + dx32*dx12);
  132. d:= errorset({'quotient,w,d},nil,nil);
  133. % d is cos of angle between the vectors p2p1 and p2p3.
  134. % d near to 1 means that the angle is almost 0 (needle).
  135. if ploterrorp d then goto disc else d:=car d;
  136. a:=abs(y3-y1)<g;
  137. if d > plotprecision!* and a and lev=ml then goto disc;
  138. % I have a good point, insert it with destructive replacement.
  139. cdr l := (x2 . y2) . cdr l;
  140. % When I have an almost 180 degree angle, I compare the
  141. % derivative at the midpoint with the difference quotient.
  142. % If these are close to each other, I stop the refinement.
  143. if -d > plotprecision!*
  144. and (null plotderiv!*
  145. or
  146. ((w:=plotevalform(car plotderiv!*,cdr plotderiv!*,{x.x2}))
  147. and abs (w - (y3-y1)/(x3-x1))*rat <0.1))
  148. then return t;
  149. smooth2(cdr l,ff,f,x,minv,maxv,g,rat,lev,ml);
  150. smooth2(l,ff,f,x,minv,maxv,g,rat,lev,ml);
  151. return t;
  152. % Function has exceeded the boundaries. I try to locate the screen
  153. % crossing point.
  154. outside:
  155. cdr l := (x2 . nil) . cdr l;
  156. z := cdr l; % insert a break
  157. p2:= (x2 . y2); % artificial midpoint
  158. p0:=findsing(ff,f,x, minv, maxv, p1, p2);
  159. if p0 then
  160. << cdr l := p0 . z;
  161. smooth2(l,ff,f,x,minv,maxv,g,rat,lev,ml) >>;
  162. p0 := findsing(ff,f,x, minv, maxv, p3, p2);
  163. if p0 then
  164. << cdr z := p0 . cdr z;
  165. smooth2(cdr z,ff,f,x,minv,maxv,g,rat,lev,ml) >>;
  166. return;
  167. disc: % look for discontinuities.
  168. return smooth3(l,ff,f,x,minv,maxv,g,rat,lev,ml);
  169. end;
  170. symbolic procedure smooth3(l,ff,f,x,minv,maxv,g,rat,lev,ml);
  171. % detect discontinuities.
  172. begin scalar p1,p2,p3,x1,x2,x3,y1,y2,y3,d;
  173. scalar x2hi,y2hi,x2lo,y2lo,dir,hidir,chi,clo;
  174. scalar lobound,hibound;
  175. integer n;
  176. g := rat := lev := ml := nil;
  177. %%%%% fdeclare(x1,x2,x3,y1,y2,y3,d,hidir);
  178. p1:=car l; p3:=cadr l;
  179. x1:=car p1; y1:=cdr p1;
  180. x3:=car p3; y3:=cdr p3;
  181. if abs(y3-y1)<variation!* then return t;
  182. % Bigstep found.
  183. hibound:=variation!**10.0; lobound:=-hibound;
  184. if y1>y3 then
  185. <<x2hi:=x1; y2hi:=y1; x2lo:= x3; y2lo:=y3; hidir:=-1.0>>
  186. else
  187. <<x2hi:=x3; y2hi:=y3; x2lo:= x1; y2lo:=y1; hidir:=1.0>>;
  188. n:=0; d:= (x3-x1)*0.5; x2:=x1+d;
  189. % intersection loop. Cut remaining interval into two parts.
  190. % If there is again a high increase in one direction we assume
  191. % a pole.
  192. next_point:
  193. if null (y2 := plotevalform(ff,f,{x.x2}))
  194. or eqcar(y2,'overflow) then goto outside;
  195. if y2 < minv then
  196. <<x2lo:=x2;y2lo:=minv;dir:=hidir>>
  197. else if y2 < y2lo then
  198. <<if y2lo<0.0 and y2<y2lo+y2lo and y2<lobound then clo:=t;
  199. x2lo:=x2;y2lo:=y2;dir:=hidir;>>
  200. else if y2 > maxv then
  201. <<x2hi:=x2;y2hi:=maxv;dir:=-hidir>>
  202. else if y2 > y2hi then
  203. <<if y2hi>0.0 and y2>y2hi+y2hi and y2>hibound then chi:=t;
  204. x2hi:=x2;y2hi:=y2;dir:=-hidir;>> else
  205. goto no_disc;
  206. if dir and (n:=n+1)<20 and (not clo or not chi) then
  207. <<d:=d/2; x2:=x2+d*dir; goto next_point>>;
  208. no_disc:
  209. if null dir then return t;
  210. if clo then y2lo:=minv;
  211. if chi then y2hi:=maxv;
  212. outside:
  213. p1:=(x2hi.y2hi); p3:=(x2lo.y2lo);
  214. if hidir=1.0 then <<p2:=p3;p3:=p1;p1:=p2>>;
  215. cdr l := p1 . (car p1.nil) . p3 . cdr l;
  216. return;
  217. brk:
  218. cdr l := (car p1.nil) . cdr l;
  219. return;
  220. end;
  221. symbolic procedure findsing(ff,f,x,minv,maxv,p1,p3);
  222. % P3 is a point with a singularity.
  223. % Try to locate the point where we exceed minv/maxv by subdivision.
  224. begin scalar p1, p2, p3, x1, x2, x3, y1, y2, y3, d, x2n;
  225. x1:=car p1; y1:=cdr p1;
  226. x3:=car p3; y3:=cdr p3;
  227. d := (x3-x1)*0.5; x2n:=x1+d;
  228. for i:=1:5 do
  229. << d:=d*0.5; x2:= x2n;
  230. if null(y2 := plotevalform(ff,f,{x.x2}))
  231. or eqcar(y2,'overflow)
  232. or y2 < minv or y2 > maxv
  233. then x2n := x2n - d
  234. else << p2 := (x2 . y2); x2n := x2n + d>>
  235. >>;
  236. if null p2 then return nil;
  237. % generate uniform maxima/minima
  238. x2 := car p2; y2 := cdr p2;
  239. y2 := if (eqcar(y2,'overflow) and cdr y2<0) or y2<minv
  240. then minv
  241. else if eqcar(y2,'overflow) or y2>maxv then maxv else y2;
  242. return (x2 . y2)
  243. end;
  244. endmodule; % plotexp2
  245. end;