crintfix.red 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. %********************************************************************
  2. module intfix$ % Further fixes to the integration package.
  3. %********************************************************************
  4. % Routines to extend the REDUCE integrator or to fix problems
  5. % Author: Francis Wright
  6. %
  7. % $Id$
  8. %
  9. if lisp !*comp then apply1('load!-package, 'int)$
  10. fluid '(!*depend !*nolnr !*failhard)$
  11. % die folgende Aenderung verhindert das Erzeugen von int* ...
  12. remd('simpint!*)$
  13. symbolic procedure simpint!* u$
  14. begin scalar x$
  15. return if (x := opmtch('int . u)) then simp x
  16. else simpiden('int . u)
  17. % statt else simpiden('int!* . u)
  18. end$
  19. % ein Patch fuer das REDUCE 3.5 EZGCD
  20. %symbolic procedure simpexpt u$
  21. % % We suppress reordering during exponent evaluation, otherwise
  22. % % internal parts (as in e^(a*b)) can have wrong order.
  23. % begin scalar expon;
  24. % expon := simpexpon carx(cdr u,'expt) where kord!*=nil;
  25. % expon := resimp expon; % We still need right order. <--- change.
  26. % return simpexpt1(car u,expon,nil)
  27. % end$
  28. % Zum Integrieren
  29. % put('int, 'simpfn, 'SimpIntPatch)$
  30. %algebraic <<
  31. % % fuer reelle Rechnungen:
  32. % let {abs(~r)**(~n) => r**n when (fixp(n) and evenp(n))}$
  33. % let {
  34. % int(1/~x^(~n),~x) => -x/(x^n*(n-1)) when numberp n,
  35. % ~x^(~m/~n)*~x => x**((m+n)/n) when (numberp n and numberp m),
  36. % int(~z/~y,~x) => log(y) when z = df(y,x)}$
  37. %
  38. % if sin(!%x)**2+cos(!%x)**2 neq 1 then
  39. % let {sin(~x)**2 => 1-cos(x)**2}$
  40. %
  41. % if cosh(!%x)**2 neq (sinh(!%x)**2 + 1) then
  42. % let {cosh(~x)**2 => (sinh(x)**2 + 1)}$
  43. %
  44. % if sin(!%x)*tan(!%x/2)+cos(!%x) neq 1 then
  45. % let {tan(~x/2) => (1-cos(x))/sin(x)}$
  46. %
  47. % if sin(!%x)*cot(!%x/2)-cos(!%x) neq 1 then
  48. % let {cot(~x/2) => (1+cos(x))/sin(x)}$
  49. %
  50. % if sqrt(!%x**2-!%y**2)-sqrt(!%x-!%y)*sqrt(!%x+!%y) neq 0 then
  51. % let {sqrt(~x)*sqrt(~y) => sqrt(x*y)}
  52. %>>$
  53. endmodule$
  54. module dfint$
  55. % Patch to improve differentiation, mainly of integrals.
  56. % This version specifically for use by the crack package.
  57. % Francis J. Wright <F.J.Wright@QMW.ac.uk>, 27 December 1997
  58. fluid '(!*fjwflag)$ !*fjwflag := t$
  59. switch allowdfint, dfint$ % dfint OFF by default
  60. deflist('((dfint ((t (rmsubs))))
  61. (allowdfint ((t (progn (put 'int 'dfform 'dfform_int) (rmsubs)))
  62. (nil (remprop 'int 'dfform))))), 'simpfg)$
  63. % There is no code to reverse the df-int commutation,
  64. % so no reason to call rmsubs when the switch is turned off.
  65. !*allowdfint := t$ % allowdfint ON by default
  66. put('int, 'dfform, 'dfform_int)$
  67. % The switch allowdfint ALLOWS differentiation under the integral sign
  68. % provided the result simplies, and should normally be on.
  69. % The switch dfint FORCES differentiation under the integral sign,
  70. % PROVIDED ALLOWDFINT IS ALSO ON, and should normally be turned on
  71. % only when required.
  72. symbolic procedure diffp(u,v);
  73. % U is a standard power, V a kernel.
  74. % Value is the standard quotient derivative of U wrt V.
  75. begin scalar n,w,x,y,z; integer m;
  76. n := cdr u; % integer power.
  77. u := car u; % main variable.
  78. if u eq v and (w := 1 ./ 1) then go to e
  79. else if atom u then go to f
  80. %else if (x := assoc(u,dsubl!*)) and (x := atsoc(v,cdr x))
  81. % and (w := cdr x) then go to e % deriv known.
  82. % DSUBL!* not used for now.
  83. else if (not atom car u and (w:= difff(u,v)))
  84. or (car u eq '!*sq and (w:= diffsq(cadr u,v)))
  85. then go to c % extended kernel found.
  86. else if x := get(car u,'dfform) then return apply3(x,u,v,n)
  87. else if x:= get(car u,dfn_prop u) then nil
  88. else if car u eq 'plus and (w := diffsq(simp u,v))
  89. then go to c
  90. else go to h; % unknown derivative.
  91. y := x;
  92. z := cdr u;
  93. a: w := diffsq(simp car z,v) . w;
  94. if caar w and null car y then go to h; % unknown deriv.
  95. y := cdr y;
  96. z := cdr z;
  97. if z and y then go to a
  98. else if z or y then go to h; % arguments do not match.
  99. y := reverse w;
  100. z := cdr u;
  101. w := nil ./ 1;
  102. b: % computation of kernel derivative.
  103. if caar y
  104. then w := addsq(multsq(car y,simp subla(pair(caar x,z),
  105. cdar x)),
  106. w);
  107. x := cdr x;
  108. y := cdr y;
  109. if y then go to b;
  110. c: % save calculated deriv in case it is used again.
  111. % if x := atsoc(u,dsubl!*) then go to d
  112. % else x := u . nil;
  113. % dsubl!* := x . dsubl!*;
  114. % d: rplacd(x,xadd(v . w,cdr x,t));
  115. e: % allowance for power.
  116. % first check to see if kernel has weight.
  117. if (x := atsoc(u,wtl!*))
  118. then w := multpq('k!* .** (-cdr x),w);
  119. m := n-1;
  120. % Evaluation is far more efficient if results are rationalized.
  121. return rationalizesq if n=1 then w
  122. else if flagp(dmode!*,'convert)
  123. and null(n := int!-equiv!-chk
  124. apply1(get(dmode!*,'i2d),n))
  125. then nil ./ 1
  126. else multsq(!*t2q((u .** m) .* n),w);
  127. f: % Check for possible unused substitution rule.
  128. if not depends(u,v)
  129. and (not (x:= atsoc(u,powlis!*))
  130. or not depends(cadddr x,v))
  131. and null !*depend
  132. then return nil ./ 1;
  133. w := list('df,u,v);
  134. w := if x := opmtch w then simp x else mksq(w,1);
  135. go to e;
  136. h: % Final check for possible kernel deriv.
  137. if car u eq 'df % multiple derivative
  138. then if depends(cadr u,v)
  139. % FJW - my version of above test was simply as follows. Surely, inner
  140. % derivative will already have simplied to 0 unless v depends on A!
  141. and not(cadr u eq v)
  142. % (df (df v A) v) ==> 0
  143. %% and not(cadr u eq v and not depends(v,caddr u))
  144. %% % (df (df v A) v) ==> 0 unless v depends on A.
  145. then
  146. <<if !*fjwflag and eqcar(cadr u, 'int) then
  147. % (df (df (int F x) A) v) ==> (df (df (int F x) v) A) ?
  148. % Commute the derivatives to differentiate the integral?
  149. if caddr cadr u eq v then
  150. % Evaluating (df u v) where u = (df (int F v) A)
  151. % Just return (df F A) - derivative absorbed
  152. << w := 'df . cadr cadr u . cddr u; go to j >>
  153. else if !*allowdfint and
  154. % Evaluating (df u v) where u = (df (int F x) A)
  155. % (If dfint is also on then this will not arise!)
  156. % Commute only if the result simplifies:
  157. not_df_p(w := diffsq(simp!* cadr cadr u, v))
  158. then <<
  159. % Generally must re-evaluate the integral (carefully!)
  160. % FJW. Bug fix!
  161. % w := aeval{'int, mk!*sq w, caddr cadr u} . cddr u;
  162. w := 'df . reval{'int, mk!*sq w, caddr cadr u} . cddr u;
  163. go to j >>; % derivative absorbed
  164. if (x := find_sub_df(w:= cadr u . derad(v,cddr u),
  165. get('df,'kvalue)))
  166. then <<w := simp car x;
  167. for each el in cdr x do
  168. for i := 1:cdr el do
  169. w := diffsq(w,car el);
  170. go to e>>
  171. else w := 'df . w
  172. >>
  173. else if null !*depend then return nil ./ 1
  174. else w := {'df,u,v}
  175. else w := {'df,u,v};
  176. j: if (x := opmtch w) then w := simp x
  177. else if not depends(u,v) and null !*depend then return nil ./ 1
  178. else w := mksq(w,1);
  179. go to e
  180. end$
  181. % Author: Francis J. Wright <F.J.Wright@QMW.ac.uk>
  182. % Last revised: 27 December 1997
  183. symbolic procedure dfform_int(u, v, n);
  184. % Simplify a SINGLE derivative of an integral.
  185. % u = '(int y x) [as main variable of SQ form]
  186. % v = kernel
  187. % n = integer power
  188. % Return SQ form of df(u**n, v) = n*u**(n-1)*df(u, v)
  189. % This routine is called by diffp via the hook
  190. % "if x := get(car u,'dfform) then return apply3(x,u,v,n)".
  191. % It does not necessarily need to use this hook, but it needs to be
  192. % called as an alternative to diffp so that the linearity of
  193. % differentiation has already been applied.
  194. begin scalar result, x, y;
  195. y := simp!* cadr u; % SQ form integrand
  196. x := caddr u; % kernel
  197. result :=
  198. if v eq x then y
  199. % df(int(y,x), x) -> y replacing the let rule in INT.RED
  200. else if not !*intflag!* and % not in the integrator
  201. % If used in the integrator it can cause infinite loops,
  202. % e.g. in df(int(int(f,x),y),x) and df(int(int(f,x),y),y)
  203. !*allowdfint and % must be on for dfint to work
  204. << y := diffsq(y, v); !*dfint or not_df_p y >>
  205. % it has simplified
  206. then simp{'int, mk!*sq y, x} % MUST re-simplify it!!!
  207. % i.e. differentiate under the integral sign
  208. % df(int(y, x), v) -> int(df(y, v), x).
  209. % (Perhaps I should use prepsq - kernels are normally true prefix?)
  210. else !*kk2q{'df, u, v}; % remain unchanged
  211. if not(n eq 1) then
  212. result := multsq( (((u .** (n-1)) .* n) .+ nil) ./ 1, result);
  213. return result
  214. end$
  215. symbolic procedure not_df_p y;
  216. % True if the SQ form y is not a df kernel.
  217. not(denr y eq 1 and
  218. not domainp (y := numr y) and eqcar(mvar y, 'df))$
  219. endmodule$
  220. module intdf$
  221. % Patch to simpint1 in src/int/trans/driver.red to provide better
  222. % simplification of integrals of derivatives. (I think -- hope --
  223. % this is the right place to hook this patch into the integrator!)
  224. % This patch was motivated by the needs of crack.
  225. % F.J.Wright@Maths.QMW.ac.uk, 31 December 1997
  226. %% load_package int$
  227. %apply1('load!-package, 'int)$ % not at compile time!
  228. switch PartialIntDf$ % off by default
  229. deflist('((PartialIntDf ((t (rmsubs))))), 'simpfg)$
  230. % If the switch PartialIntDf is turned on then integration by parts is
  231. % performed if the result simplifies in the sense that it integrates a
  232. % symbolic derivative and does not introduce new symbolic derivatives.
  233. % However, because the initial integral contains an unevaluated
  234. % derivative then the result must still contain an unevaluated
  235. % integral.
  236. symbolic procedure simpint1 u;
  237. % Varstack* rebound, since FORMLNR use can create recursive
  238. % evaluations. (E.g., with int(cos(x)/x**2,x)).
  239. begin scalar !*keepsqrts,v,varstack!*;
  240. u := 'int . prepsq car u . cdr u;
  241. if (v := formlnr u) neq u
  242. then if !*nolnr
  243. then <<v := simp subst('int!*,'int,v);
  244. return remakesf numr v ./ remakesf denr v>>
  245. else <<!*nolnr := nil . !*nolnr;
  246. v:=errorset!*(list('simp,mkquote v),!*backtrace);
  247. if pairp v then v := car v else v := simp u;
  248. !*nolnr := cdr !*nolnr;
  249. return v>>;
  250. % FJW: At this point linearity has been applied.
  251. return if (v := opmtch u) then simp v
  252. % FJW: Check for a directly integrable derivative:
  253. else if (v := NestedIntDf(cadr u, caddr u)) then mksq(v,1)
  254. else if !*failhard then rerror(int,4,"FAILHARD switch set")
  255. % FJW: Integrate by parts if the result simplifies:
  256. else if !*PartialIntDf and
  257. (v := PartialIntDf(cadr u, caddr u)) then mksq(v,1)
  258. else mksq(u,1)
  259. end$
  260. symbolic procedure NestedIntDf(y, x);
  261. %% int( ... df(f,A,x,B) ..., x) -> ... df(f,A,B) ...
  262. %% Find a df(f,A,x,B) among possibly nested int's and df's within
  263. %% the integrand y in int(y,x), and return the whole structure y
  264. %% but with the derivative integrated; otherwise return nil.
  265. %% [A,B are arbitrary sequences of kernels.]
  266. not atom y and
  267. begin scalar car_y, nested;
  268. return
  269. if (car_y := car y) eq 'df and memq(x, cddr y) then
  270. %% int( df(f, A, x, B), x ) -> df(f, A, B)
  271. 'df . cadr y . delete(x, cddr y)
  272. %% use delete for portability!
  273. %% deleq is defined in CSL, delq in PSL -- oops!
  274. else if memq(car_y, '(df int)) and
  275. (nested := NestedIntDf(cadr y, x)) then
  276. %% int( df(int(df(f, A, x, B), c), C), x ) ->
  277. %% df(int(df(f, A, B), c), C)
  278. %% int( int(df(f, A, x, B), c), x ) ->
  279. %% int(df(f, A, B), c)
  280. car_y . nested . cddr y
  281. end$
  282. symbolic procedure PartialIntDf(y, x);
  283. %% int(u(x)*df(v(x),x), x) -> u(x)*v(x) - int(df(u(x),x)*v(x), x)
  284. %% Integrate by parts if the resulting integral simplifies [to
  285. %% avoid infinite loops], which means that df(u(x),x) may not
  286. %% contain any unevaluated derivatives; otherwise return nil.
  287. not atom y and
  288. begin scalar denlist, facs, df, u, v;
  289. if car y eq 'quotient then <<
  290. denlist := cddr y;
  291. % y := numerator:
  292. if atom(y := cadr y) then return % no derivative
  293. >>;
  294. % y := list of factors:
  295. if car y eq 'times then y := cdr y
  296. else if denlist then y := y . nil
  297. else return;
  298. % Find an integrable derivative among the factors:
  299. facs := y;
  300. while facs and not
  301. (eqcar(df := car facs, 'df) and memq(x, cddr df)) do
  302. facs := cdr facs;
  303. if null facs then return; % no integrable derivative
  304. % Construct u(x) and v(x) [v(x) may still be a derivative]:
  305. u := delete(df, y); % list of factors
  306. u := if null u then 1 else if cdr u then 'times . u else car u;
  307. if denlist then u := 'quotient . u . denlist;
  308. v := cadr df; % kernel being differentiated
  309. if (df := delete(x, cddr df)) then v := 'df . v . df;
  310. % Check that df(u(x),x) simplifies:
  311. if smemq('df, df := reval {'df,u,x}) then return;
  312. return reval {'difference,
  313. {'times,u,v}, {'int, {'times, df, v}, x}}
  314. end$
  315. endmodule$
  316. end$