driver.red 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. module driver; % Driving routines for integration program.
  2. % Author: Mary Ann Moore and Arthur C. Norman.
  3. % Modifications by: John P. Fitch, David Hartley, Francis J. Wright.
  4. fluid '(!*algint
  5. !*backtrace
  6. !*exp
  7. % !*failhard
  8. !*gcd
  9. !*intflag!*
  10. !*keepsqrts
  11. !*limitedfactors
  12. !*mcd
  13. !*noncomp
  14. !*nolnr
  15. !*partialintdf
  16. !*precise
  17. !*purerisch
  18. !*rationalize
  19. !*structure
  20. !*trdint
  21. !*trint
  22. !*uncached
  23. basic!-listofnewsqrts
  24. basic!-listofallsqrts
  25. gaussiani
  26. intvar
  27. kord!*
  28. listofnewsqrts
  29. listofallsqrts
  30. loglist
  31. powlis!*
  32. sqrt!-intvar
  33. sqrt!-places!-alist
  34. subfg!*
  35. varlist
  36. varstack!*
  37. xlogs
  38. zlist);
  39. exports integratesq,simpint,simpint1;
  40. imports algebraiccase,algfnpl,findzvars,getvariables,interr,printsq,
  41. transcendentalcase,varsinlist,kernp,simpcar,prepsq,mksq,simp,
  42. opmtch,formlnr;
  43. switch algint,nolnr,trdint,trint;
  44. switch hyperbolic;
  45. % Form is int(expr,var,x1,x2,...);
  46. % meaning is integrate expr wrt var, given that the result may
  47. % contain logs of x1,x2,...
  48. % x1, etc are intended for use when the system has to be helped
  49. % in the case that expr is algebraic.
  50. % Extended arguments x1, x2, etc., are not currently supported.
  51. symbolic procedure simpint u;
  52. % Simplifies an integral. First two components of U are the integrand
  53. % and integration variable respectively. Optional succeeding
  54. % components are log forms for the final integral.
  55. if atom u or null cdr u or cddr u and (null cdddr u or cddddr u)
  56. then rerror(int,1,"Improper number of arguments to INT")
  57. else if cddr u then simpdint u
  58. % then if getd 'simpdint then simpdint u
  59. % else rerror(int,2,"Improper number of arguments to INT")
  60. else begin scalar ans,dmod,expression,variable,loglist,oldvarstack,
  61. !*intflag!*,!*purerisch,cflag,intvar,listofnewsqrts,
  62. listofallsqrts,sqrtfn,sqrt!-intvar,sqrt!-places!-alist,
  63. basic!-listofallsqrts,basic!-listofnewsqrts,coefft,
  64. varchange,w;
  65. !*intflag!* := t; % Shows we are in integrator.
  66. variable := !*a2k cadr u;
  67. if not(idp variable or pairp variable and numlistp cdr variable)
  68. % then typerr(variable,"integration variable");
  69. then <<varchange := variable . intern gensym();
  70. if !*trint
  71. then printc {"Integration kernel", variable,
  72. "replaced by simple variable", cdr varchange};
  73. variable := cdr varchange>>;
  74. intvar := variable; % Used in SIMPSQRT and algebraic integrator.
  75. w := cddr u;
  76. if w then rerror(int,3,"Too many arguments to INT");
  77. listofnewsqrts:= list mvar gaussiani; % Initialize for SIMPSQRT.
  78. listofallsqrts:= list (argof mvar gaussiani . gaussiani);
  79. sqrtfn := get('sqrt,'simpfn);
  80. put('sqrt,'simpfn,'proper!-simpsqrt);
  81. % We need explicit settings of several switches during integral
  82. % evaluation. In addition, the current code cannot handle domains
  83. % like floating point, so we suppress it while the integral is
  84. % calculated. UNCACHED is turned on since integrator does its own
  85. % caching.
  86. % Any changes made to these settings must also be made in wstrass.
  87. if dmode!* then
  88. << % added by Alan Barnes
  89. if (cflag:=get(dmode!*, 'cmpxfn)) then onoff('complex, nil);
  90. if (dmod := get(dmode!*,'dname)) then
  91. onoff(dmod,nil)>> where !*msg := nil;
  92. begin scalar dmode!*,!*exp,!*gcd,!*keepsqrts,!*limitedfactors,!*mcd,
  93. !*rationalize,!*structure,!*uncached,kord!*,
  94. ans1,denexp,badbit,nexp,oneterm,!*precise;
  95. !*keepsqrts := !*limitedfactors := t; % !*sqrt := t;
  96. !*exp := !*gcd := !*mcd := !*structure := !*uncached := t;
  97. dmode!* := nil;
  98. if !*algint
  99. then <<
  100. % The algint code now needs precise off.
  101. % !*precise := t;
  102. % Start a clean slate (in terms of SQRTSAVE) for this
  103. % integral.
  104. sqrt!-intvar:=!*q2f simpsqrti variable;
  105. if (red sqrt!-intvar) or (lc sqrt!-intvar neq 1)
  106. or (ldeg sqrt!-intvar neq 1)
  107. then interr "Sqrt(x) not properly formed"
  108. else sqrt!-intvar:=mvar sqrt!-intvar;
  109. basic!-listofallsqrts:=listofallsqrts;
  110. basic!-listofnewsqrts:=listofnewsqrts;
  111. sqrtsave(basic!-listofallsqrts,basic!-listofnewsqrts,
  112. list(variable . variable))>>;
  113. coefft := (1 ./ 1); % Collect simple coefficients.
  114. expression := int!-simp car u;
  115. if varchange
  116. then <<depend1(car varchange,cdr varchange,t);
  117. expression := int!-subsq(expression,{varchange})>>;
  118. denexp := 1 ./ denr expression; % Get into two bits
  119. nexp := numr expression;
  120. while not atom nexp and null cdr nexp and
  121. not depends(mvar nexp,variable) do
  122. <<coefft := multsq(coefft,(((caar nexp) . 1) . nil) ./ 1);
  123. nexp := lc nexp>>;
  124. ans1 := nil;
  125. while nexp do begin % Collect by zvariables
  126. scalar x,zv,tmp;
  127. if atom nexp then << x:=!*f2q nexp; nexp:=nil >>
  128. else << x:=!*t2q car nexp; nexp:=cdr nexp >>;
  129. x := multsq(x,denexp);
  130. zv := findzvars(getvariables x,list variable,variable,nil);
  131. begin scalar oldzlist;
  132. while oldzlist neq zv do <<
  133. oldzlist := zv;
  134. foreach zz in oldzlist do
  135. zv:=findzvars(distexp(pseudodiff(zz,variable)),
  136. zv,variable,t)>>;
  137. % The following line was added to make, for example,
  138. % int(df(sin(x)/x),x) return the expected result.
  139. zv := sort(zv, function ordp)
  140. end;
  141. tmp := ans1;
  142. while tmp do
  143. <<if zv=caar tmp
  144. then <<rplacd(car tmp,addsq(cdar tmp,x));
  145. tmp := nil; zv := nil>>
  146. else tmp := cdr tmp>>;
  147. if zv then ans1 := (zv . x) . ans1
  148. end;
  149. if length ans1 = 1 then oneterm := t; % Efficiency
  150. nexp := ans1;
  151. ans := nil ./ 1;
  152. badbit:=nil ./ 1; % SQ zero
  153. while nexp do % Run down the terms
  154. <<u := cdar nexp;
  155. if !*trdint
  156. then <<princ "Integrate"; printsq u;
  157. princ "with Zvars "; print caar nexp>>;
  158. ans1 := errorset!*(list('integratesq,mkquote u,
  159. mkquote variable,mkquote loglist,
  160. mkquote caar nexp),
  161. !*backtrace);
  162. nexp := cdr nexp;
  163. if errorp ans1 then badbit := addsq(badbit,u)
  164. else <<ans := addsq(caar ans1, ans);
  165. badbit:=addsq(cdar ans1,badbit)>>>>;
  166. if !*trdint
  167. then <<prin2 "Partial answer="; printsq ans;
  168. prin2 "To do="; printsq badbit>>;
  169. % We have run down the terms. If there are any bad bits, redo
  170. % them. However, since a non-zero badbit implies that
  171. % integratesq aborted, the internal variable order may be
  172. % confused. So we reset kord!* and reorder expressions in this
  173. % case.
  174. if badbit neq '(nil . 1)
  175. then <<setkorder nil;
  176. badbit := reordsq badbit;
  177. ans := reordsq ans;
  178. coefft := reordsq coefft;
  179. if !*trdint then <<princ "Retrying..."; printsq badbit>>;
  180. if oneterm and ans = '(nil . 1) then ans1 := nil
  181. else ans1 := errorset!*(list('integratesq,mkquote badbit,
  182. mkquote variable,mkquote loglist,nil),
  183. !*backtrace);
  184. if null ans1 or errorp ans1
  185. then ans := addsq(ans,simpint1(badbit . variable . w))
  186. else <<ans := addsq(ans,caar ans1);
  187. %% FJW: It is possible for ans here to be just a
  188. %% spurious constant term, in which case we discard it.
  189. if not smemq(variable, ans) then ans := nil ./ 1;
  190. %% This may not be the best place for this fix, but I
  191. %% don't see how it can ever do any harm. [I don't
  192. %% think we need a full depend test here.]
  193. if cdar ans1 neq '(nil . 1)
  194. then ans := addsq(ans,
  195. simpint1(cdar ans1 . variable . w))
  196. >>>>;
  197. end;
  198. ans := multsq(coefft,ans); %Put back coefficient, preserving order.
  199. % if errorp ans
  200. % then return <<put('sqrt,'simpfn,sqrtfn);
  201. % if !*failhard then error1();
  202. % simpint1(expression . variable . w)>>
  203. % else ans := car ans;
  204. % expression := sqrtchk numr ans ./ sqrtchk denr ans;
  205. if !*trdint then << printc "Resimp and all that"; printsq ans >>;
  206. % We now need to check that all simplifications have been done
  207. % but we have to make sure INT is not resimplified, and that SIMP
  208. % does not complain at getting the same argument again.
  209. put('int,'simpfn,'simpiden);
  210. put('sqrt,'simpfn,sqrtfn);
  211. << if dmod then onoff(dmod,t);
  212. % added by Alan Barnes
  213. if cflag then onoff('complex,t)>> where !*msg := nil;
  214. oldvarstack := varstack!*;
  215. varstack!* := nil;
  216. % ans := errorset!*(list('resimp,mkquote ans),t);
  217. ans := errorset!*(list('int!-resub,mkquote ans,mkquote
  218. varchange),t);
  219. put('int,'simpfn,'simpint);
  220. varstack!* := oldvarstack;
  221. return if errorp ans then error1() else car ans
  222. end;
  223. symbolic procedure int!-resub(x,v);
  224. % {sq,alist} -> sq
  225. % Undo any variable change and resimplify.
  226. if v then <<x := int!-subsq(x,{revpr v}); depend1(car v,cdr v,nil);
  227. resimp x>>
  228. else resimp x;
  229. symbolic procedure int!-subsq(x,v);
  230. % {sq,alist} -> sq
  231. % A version of subsq with the int and df operators unprotected.
  232. % Intended for straightforward change of variable names only.
  233. begin scalar subfuncs,subfg!*;
  234. subfuncs := {remprop('df,'subfunc),remprop('int,'subfunc)};
  235. x := subsq(x,v);
  236. put('df,'subfunc,car subfuncs);
  237. put('int,'subfunc,cadr subfuncs);
  238. return x
  239. end;
  240. symbolic procedure numlistp u;
  241. % True if u is a list of numbers.
  242. null u or numberp car u and numlistp cdr u;
  243. % symbolic procedure sqrtchk u;
  244. % % U is a standard form. Result is another standard form with square
  245. % % roots replaced by half powers.
  246. % if domainp u then u
  247. % else if not eqcar(mvar u,'sqrt)
  248. % then addf(multpf(lpow u,sqrtchk lc u),sqrtchk red u)
  249. % % else if mvar u = '(sqrt -1)
  250. % % then addf(multpf(mksp('i,ldeg u),sqrtchk lc u),sqrtchk red u)
  251. % else addf(multpf(mksp(list('expt,cadr mvar u,'(quotient 1 2)),
  252. % ldeg u),
  253. % sqrtchk lc u),
  254. % sqrtchk red u);
  255. symbolic procedure int!-simp u;
  256. % Converts U to canonical form, including the resimplification of
  257. % *sq forms.
  258. subs2 resimp simp!* u;
  259. put('int,'simpfn,'simpint);
  260. symbolic procedure integratesq(integrand,var,xlogs,zv);
  261. begin scalar varlist,x,zlist,!*noncomp;
  262. if !*trint then <<
  263. printc "Start of Integration; integrand is ";
  264. printsq integrand >>;
  265. !*noncomp := noncomfp numr integrand
  266. or noncomfp denr integrand;
  267. varlist:=getvariables integrand;
  268. varlist:=varsinlist(xlogs,varlist); %in case more exist in xlogs
  269. if zv then zlist := zv
  270. else <<zlist := findzvars(varlist,list var,var,nil);
  271. % Important kernels.
  272. % The next section causes problems with nested exponentials or logs.
  273. begin scalar oldzlist;
  274. while oldzlist neq zlist do
  275. <<oldzlist := zlist;
  276. foreach zz in oldzlist do
  277. zlist := findzvars(distexp(pseudodiff(zz,var)),
  278. zlist,var,t)>>
  279. end>>;
  280. if !*trint then <<
  281. printc "Determination of the differential field descriptor";
  282. printc "gives the functions:";
  283. print zlist >>;
  284. %% Look for rational powers in the descriptor
  285. %% If there is make a suitable transformation and do the sub integral
  286. %% and return the revised integral
  287. x := look_for_substitute(integrand, var, zlist);
  288. if x then return x;
  289. %% End of rational patch
  290. if !*purerisch and not allowedfns zlist
  291. then return (nil ./ 1) . integrand;
  292. % If it is not suitable for Risch.
  293. varlist := setdiff(varlist,zlist);
  294. % varlist := purge(zlist,varlist);
  295. % Now zlist is list of things that depend on x, and varlist is list
  296. % of constant kernels in integrand.
  297. if !*algint and cdr zlist and algfnpl(zlist,var)
  298. then return algebraiccase(integrand,zlist,varlist)
  299. else return transcendentalcase(integrand,var,xlogs,zlist,varlist)
  300. end;
  301. symbolic procedure distexp(l);
  302. if null l then nil
  303. else if atom car l then car l . distexp cdr l
  304. else if (caar l = 'expt) and (cadar l = 'e) then
  305. begin scalar ll;
  306. ll:=caddr car l;
  307. if eqcar(ll,'plus) then <<
  308. ll:=foreach x in cdr ll collect list('expt,'e,x);
  309. return ('times . ll) . distexp cdr l >>
  310. else return car l . distexp cdr l
  311. end
  312. else distexp car l . distexp cdr l;
  313. symbolic procedure pseudodiff(a,var);
  314. if atom a then % **** Treat diffs correctly??
  315. if depends(a,var) then list prepsq simpdf(list(a,var)) else nil
  316. else if car a
  317. memq '(atan equal log plus quotient sqrt times minus)
  318. then begin scalar aa,bb;
  319. foreach zz in cdr a do <<
  320. bb:=pseudodiff(zz,var);
  321. aa:= union(bb,aa) >>;
  322. return aa
  323. end
  324. else if car a eq 'expt
  325. then if depends(cadr a,var) then
  326. if depends(caddr a,var) then
  327. prepsq simp list('log,cadr a) . %% a(x)^b(x)
  328. cadr a .
  329. caddr a .
  330. union(pseudodiff(cadr a,var),pseudodiff(caddr a,var))
  331. else cadr a . pseudodiff(cadr a,var) %% a(x)^b
  332. else caddr a . pseudodiff(caddr a,var) %% a^b(x)
  333. else list prepsq simpdf(list(a,var));
  334. symbolic procedure look_for_substitute(integrand, var, zz);
  335. % Search for rational power transformations
  336. begin
  337. scalar res;
  338. if atom zz then return nil
  339. else if (res := look_for_rational(integrand, var, zz)) then return res
  340. else if (res := look_for_quad(integrand, var, zz)) then return res
  341. else if (res := look_for_substitute(integrand, var, car zz))
  342. then return res
  343. else return look_for_substitute(integrand, var, cdr zz)
  344. end;
  345. symbolic procedure look_for_rational(integrand, var, zz);
  346. % Look for a form x^(n/m) in the field descriptor, and transform
  347. % the integral if it is found. Note that the sqrt form may be used
  348. % as well as exponentials. Return nil if no transformation
  349. if (car zz = 'sqrt and cadr zz = var) then
  350. look_for_rational1(integrand, var, 2)
  351. else if (car zz = 'expt) and (cadr zz = var) and
  352. (listp caddr zz) and (caaddr zz = 'quotient) and
  353. (numberp cadr caddr zz) and (numberp caddr caddr zz) then
  354. look_for_rational1(integrand, var, caddr caddr zz)
  355. else nil;
  356. symbolic procedure look_for_rational1(integrand, var, m);
  357. % Actually do the transformation and integral
  358. begin
  359. scalar newvar, res, ss, mn2m!-1;
  360. newvar := gensym();
  361. mn2m!-1 := !*f2q(((newvar .** (m-1)) .* m) .+ nil);
  362. %% print ("Integrand was " . integrand);
  363. % x => y^m, and dx => m y^(m-1)
  364. integrand := multsq(subsq(integrand,
  365. list(var . list('expt,newvar,m))),
  366. mn2m!-1);
  367. if !*trint then <<
  368. prin2 "Integrand is transformed to ";
  369. printsq integrand
  370. >>;
  371. begin scalar intvar;
  372. intvar := newvar; % To circumvent an algint bug.
  373. res := integratesq(integrand, newvar, nil, nil);
  374. end;
  375. ss := list(newvar . list('expt,var, list('quotient, 1, m)));
  376. res := subsq(car res, ss) .
  377. subsq(quotsq(cdr res, mn2m!-1), ss);
  378. if !*trint then <<
  379. printc "Transforming back...";
  380. printsq car res;
  381. prin2 " plus a bad part of ";
  382. printsq cdr res
  383. >>;
  384. return res
  385. end;
  386. symbolic procedure look_for_quad(integrand, var, zz);
  387. % Look for a form sqrt(a+bx+cx^2) in the field descriptor
  388. % and transform to the appropriate asin, acosh or asinh.
  389. % Return nil if no transformation found
  390. if !*algint then nil % as Algint does it better??
  391. else begin
  392. if (car zz = 'sqrt and listp cadr zz and caadr zz = 'plus) or
  393. (car zz = 'expt and listp cadr zz and caadr zz = 'plus and
  394. listp caddr zz and car caddr zz = 'quotient
  395. and fixp caddr caddr zz)
  396. then <<
  397. zz := simp cadr zz;
  398. if (cdr zz = 1) then <<
  399. zz := cdr coeff1(prepsq zz, var, nil);
  400. if length zz = 2 then return begin % Linear
  401. scalar a, b;
  402. scalar nvar, res, ss;
  403. a := car zz; b := cadr zz;
  404. if (depends(a,var) or depends(b,var)) then return nil;
  405. nvar := gensym();
  406. if !*trint then <<
  407. prin2 "Linear shift suggested ";
  408. prin2 a; prin2 " "; prin2 b; terpri();
  409. >>;
  410. integrand := subsq(integrand, % Make the substitution
  411. list(var . list('quotient,
  412. list('difference,
  413. list('expt,nvar,2),a),
  414. b)));
  415. integrand := multsq(integrand, % and the dx component
  416. simp list('quotient,list('times,nvar,2),
  417. b));
  418. % integrand := subsq(integrand,
  419. % list(var . list('difference, nvar, a)));
  420. % integrand := multsq(integrand, simp b);
  421. if !*trint then <<
  422. prin2 "Integrand is transformed by substitution to ";
  423. printsq integrand;
  424. prin2 "using substitution "; prin2 var; prin2 " -> ";
  425. printsq simp list('quotient,
  426. list('difference,list('expt,nvar,2),a),
  427. b);
  428. >>;
  429. res := integratesq(integrand, nvar, nil, nil);
  430. ss := list(nvar . list('sqrt,list('plus,list('times,var,b),
  431. a)));
  432. res := subsq(car res, ss) .
  433. subsq(multsq(cdr res, simp list('quotient,b,
  434. list('times,nvar,2))), ss);
  435. %% Should one reject if there is a bad bit??
  436. return res;
  437. end
  438. else if length zz = 3 then return begin % A quadratic
  439. scalar a, b, c;
  440. a := car zz; b := cadr zz; c:= caddr zz;
  441. if (depends(a,var) or depends(b,var) or depends(c,var)) then
  442. return nil;
  443. a := simp list('difference, a, % Re-centre
  444. list('times,b,b,
  445. list('quotient,1,list('times,4,c))));
  446. if null numr a then return nil; % Power occurred.
  447. b := simp list('quotient, b, list('times, 2, c));
  448. c := simp c;
  449. return
  450. if minusf numr c then <<
  451. if minusf numr a then begin
  452. scalar !*hyperbolic;
  453. !*hyperbolic := t;
  454. return
  455. look_for_invhyp(integrand,nil,var,a,b,c)
  456. end
  457. else look_for_asin(integrand,var,a,b,c)>>
  458. else <<
  459. if minusf numr a then look_for_invhyp(integrand,t,var,a,b,c)
  460. else look_for_invhyp(integrand,nil,var,a,b,c)
  461. >>
  462. end
  463. else if length zz = 5 then return begin % A quartic
  464. scalar a, b, c, d, e, nn, dd, mm;
  465. a := car zz; b := cadr zz; c:= caddr zz;
  466. d := cadddr zz; e := car cddddr zz;
  467. if not(b = 0) or not(d = 0) then return nil;
  468. if (depends(a,var) or depends(c,var)) or depends(e,var) then
  469. return nil;
  470. nn := numr integrand; dd := denr integrand;
  471. if denr(mm :=quotsq(nn ./ 1, !*kk2q var)) = 1 and
  472. even_power(numr mm, var) and even_power(dd, var) then <<
  473. % substitute x -> sqrt(y)
  474. return sqrt_substitute(numr mm, dd, var);
  475. >>;
  476. if denr(mm :=quotsq(dd ./ 1, !*kk2q var)) = 1 and
  477. even_power(nn, var) and even_power(numr mm, var) then <<
  478. % substitute x -> sqrt(y)
  479. return sqrt_substitute(nn, multf(dd,!*kk2f var), var);
  480. >>;
  481. return nil;
  482. end;
  483. >>>>;
  484. return nil;
  485. end;
  486. symbolic procedure look_for_asin(integrand, var, a, b, c);
  487. % Actually do the transformation and integral
  488. begin
  489. scalar newvar, res, ss, sqmn, onemth, m, n;
  490. m := prepsq a;
  491. n := prepsq c;
  492. b := prepsq b;
  493. newvar := gensym();
  494. sqmn := prepsq apply1(get('sqrt, 'simpfn),
  495. list list('quotient, list('minus,n), m));
  496. onemth := list('cos, newvar);
  497. ss := list('sin, newvar);
  498. powlis!* := list(ss, 2, '(nil . t),
  499. list('difference,1,list('expt,onemth,2)),
  500. nil) .
  501. powlis!*;
  502. integrand := subs2q
  503. multsq(subsq(integrand,
  504. list(var . list('difference,
  505. list('quotient,ss,sqmn), b))),
  506. quotsq(onemth := simp onemth, simp sqmn));
  507. if !*trint then <<
  508. prin2 "Integrand is transformed by substitution to ";
  509. printsq integrand;
  510. prin2 "using substitution "; prin2 var; prin2 " -> ";
  511. printsq simp list('difference, list('quotient, ss, sqmn), b);
  512. >>;
  513. res := integratesq(integrand, newvar, nil, nil);
  514. powlis!* := cdr powlis!*;
  515. ss:= list(newvar . list('asin,list('times,list('plus,var,b),sqmn)));
  516. res := subsq(car res, ss) . subsq(quotsq(cdr res, onemth), ss);
  517. if !*trint then <<
  518. printc "Transforming back...";
  519. printsq car res;
  520. prin2 " plus a bad part of ";
  521. printsq cdr res
  522. >>;
  523. if (car res = '(nil . 1)) then return nil;
  524. return res;
  525. end;
  526. symbolic procedure look_for_invhyp(integrand, do_acosh, var, a, b, c);
  527. % Actually do the transformation and integral; uses acosh/asinh form
  528. % depending on second argument
  529. begin
  530. scalar newvar, res, ss, sqmn, onemth, m, n, realdom;
  531. m := prepsq a;
  532. n := prepsq c;
  533. b := prepsq b;
  534. newvar := gensym();
  535. if do_acosh then <<
  536. sqmn := prepsq apply1(get('sqrt, 'simpfn),
  537. list list('quotient, n, list('minus, m)));
  538. onemth := list('sinh, newvar);
  539. ss := list('cosh, newvar)
  540. >>
  541. else <<
  542. sqmn:= prepsq apply1(get('sqrt,'simpfn),list list('quotient,n,m));
  543. onemth := list('cosh, newvar);
  544. ss := list('sinh, newvar)
  545. >>;
  546. powlis!* := list(ss, 2, '(nil . t),
  547. list((if do_acosh then 'plus else 'difference),
  548. list('expt, onemth, 2),1),
  549. nil) .
  550. powlis!*;
  551. % print ("sqmn" . sqmn); print("onemth" . onemth); print ("ss" . ss);
  552. % print cdddar powlis!*;
  553. integrand := subs2q
  554. multsq(subsq(integrand,
  555. list(var . list('difference,list('quotient,ss,sqmn),b))),
  556. quotsq(onemth := simp onemth, simp sqmn));
  557. if !*trint then <<
  558. prin2 "Integrand is transformed by substitution to ";
  559. printsq integrand;
  560. prin2 "using substitution "; prin2 var; prin2 " -> ";
  561. printsq simp list('difference, list('quotient, ss, sqmn), b);
  562. >>;
  563. realdom := not smember('(sqrt -1),integrand);
  564. % print integrand; print realdom;
  565. res := integratesq(integrand, newvar, nil, nil);
  566. powlis!* := cdr powlis!*;
  567. if !*hyperbolic then <<
  568. ss := list(if do_acosh then 'acosh else 'asinh,
  569. list('times,list('plus,var,b), sqmn));
  570. >>
  571. else <<
  572. ss := list('times,list('plus,var,b), sqmn);
  573. ss := if do_acosh then
  574. subst(ss,'ss,
  575. '(log (plus ss (sqrt (difference (times ss ss) 1)))))
  576. else
  577. subst(ss,'ss,'(log (plus ss (sqrt (plus (times ss ss) 1)))))
  578. >>;
  579. ss := list(newvar . ss);
  580. res := sqrt2top subsq(car res, ss) .
  581. sqrt2top subsq(quotsq(cdr res, onemth), ss);
  582. if !*trint then <<
  583. printc "Transforming back...";
  584. printsq car res;
  585. prin2 " plus a bad part of ";
  586. printsq cdr res
  587. >>;
  588. if (car res = '(nil . 1)) then return nil;
  589. if realdom and smember('(sqrt -1),res) then <<
  590. if !*trint then print "Wrong sheet"; return nil; % Wrong sheet?
  591. >>;
  592. return res
  593. end;
  594. symbolic procedure simpint1 u;
  595. % Varstack* rebound, since FORMLNR use can create recursive
  596. % evaluations. (E.g., with int(cos(x)/x**2,x)).
  597. begin scalar !*keepsqrts,v,varstack!*;
  598. u := 'int . prepsq car u . cdr u;
  599. if (v := formlnr u) neq u
  600. then if !*nolnr
  601. then <<v := simp subst('int!*,'int,v);
  602. return remakesf numr v ./ remakesf denr v>>
  603. else <<!*nolnr := nil . !*nolnr;
  604. v:=errorset!*(list('simp,mkquote v),!*backtrace);
  605. if pairp v then v := car v else v := simp u;
  606. !*nolnr := cdr !*nolnr;
  607. return v>>;
  608. return if (v := opmtch u) then simp v
  609. else symint u % FJW: symbolic integral
  610. end;
  611. mkop 'int!*;
  612. put('int!*,'simpfn,'simpint!*);
  613. symbolic procedure simpint!* u;
  614. begin scalar x;
  615. return if (x := opmtch('int . u)) then simp x
  616. else simpiden('int!* . u)
  617. end;
  618. symbolic procedure remakesf u;
  619. %remakes standard form U, substituting operator INT for INT!*;
  620. if domainp u then u
  621. else addf(multpf(if eqcar(mvar u,'int!*)
  622. then mksp('int . cdr mvar u,ldeg u)
  623. else lpow u,remakesf lc u),
  624. remakesf red u);
  625. symbolic procedure allowedfns u;
  626. if null u then t
  627. else if atom car u then (car u=intvar) or not depends(car u,intvar)
  628. else if (caar u = 'expt and not (cadar u = 'e)
  629. and not depends(cadar u, intvar)
  630. and depends(caddar u, intvar)) then nil
  631. else if flagp(caar u,'transcendental) then allowedfns cdr u
  632. else nil;
  633. symbolic procedure look_for_power(integrand, var);
  634. begin
  635. scalar nn, dd, mm;
  636. nn := numr integrand; dd := denr integrand;
  637. if denr(mm :=quotsq(nn ./ 1, !*kk2q var)) = 1 and
  638. even_power(numr mm, var) and even_power(dd, var) then <<
  639. % substitute x -> sqrt(y)
  640. return sqrt_substitute(numr mm, dd, var);
  641. >>;
  642. if denr(mm :=quotsq(dd ./ 1, !*kk2q var)) = 1 and
  643. even_power(nn, var) and even_power(numr mm, var) then <<
  644. % substitute x -> sqrt(y)
  645. return sqrt_substitute(nn, numr mm, var);
  646. >>;
  647. return nil;
  648. end;
  649. symbolic procedure even_power(xpr, var);
  650. if atom xpr then t
  651. else if mvar xpr = var then <<
  652. if evenp pdeg lpow xpr then even_power(lc xpr, var) and
  653. even_power(red xpr, var)
  654. else nil >>
  655. else if eqcar(mvar xpr, 'expt) and
  656. cadr mvar xpr = var and
  657. evenp caddr mvar xpr then t
  658. else if atom mvar xpr then
  659. even_power(lc xpr, var) and even_power(red xpr, var)
  660. else if even_power(red xpr, var) and even_power(lc xpr, var) then
  661. even_prep(mvar xpr, var);
  662. symbolic procedure even_prep(xpr,var);
  663. if xpr = var then nil
  664. else if atom xpr then t
  665. else if eqcar(xpr, 'expt) and cadr xpr = var and evenp caddr xpr then t
  666. else if even_prep(car xpr, var) then even_prep(cdr xpr, var);
  667. symbolic procedure sqrt_substitute(nn, dd, var);
  668. begin
  669. scalar newvar, integrand, res, ss, !*keepsqrts;
  670. newvar := gensym();
  671. integrand := subst(list('sqrt,newvar), var,
  672. list('quotient, prepsq (nn ./ dd), 2));
  673. integrand := prepsq simp integrand;
  674. integrand := simp integrand;
  675. begin scalar intvar;
  676. intvar := newvar; % To circumvent an algint bug/oddity
  677. res := integratesq(integrand, newvar, nil, nil);
  678. end;
  679. ss := list(newvar . list('expt, var, 2));
  680. res := subsq(car res, ss) . multsq((((var .^ 1) .* 2) .+ nil) ./ 1,
  681. subsq(cdr res, ss));
  682. if !*trint then <<
  683. printc "Transforming back...";
  684. printsq car res;
  685. prin2 " plus a bad part of ";
  686. printsq cdr res
  687. >>;
  688. return res
  689. end;
  690. % The following rules probably belong in other places.
  691. %-----------------------------------------------------------------------
  692. algebraic;
  693. operator ci,si; % ei.
  694. % FJW: ci,si also defined in specfn(sfint.red), so ...
  695. symbolic((algebraic operator ci,si) where !*msg=nil);
  696. intrules :=
  697. {e^(~n*acosh(~x)) => (sqrt(x^2-1)+x)^n when numberp n,
  698. e^(~n*asinh(~x)) => (sqrt(x^2+1)+x)^n when numberp n,
  699. e^(acosh(~x)) => (sqrt(x^2-1)+x),
  700. e^(asinh(~x)) => (sqrt(x^2+1)+x),
  701. cosh(log(~x)) => (x^2+1)/(2*x),
  702. sinh(log(~x)) => (x^2-1)/(2*x),
  703. % These next two are rather uncertain.
  704. int(log(~x)/(~b-x),x) => dilog(x/b),
  705. int(log(~x)/(~b*x-x^2),x) => dilog(x/b)/b + log(x)^2/(2b),
  706. %% FJW: Next 2 rules replaced by ~~ rules below
  707. %% int(e^(~x^2),x) => erf(i*x)*sqrt(pi)/(2i),
  708. %% int(1/e^(~x^2),x) => erf(x) * sqrt(pi)/2,
  709. %% FJW: Missing sqrt(b):
  710. %% int(e^(~b*~x^2),x) => erf(i*x)*sqrt(pi)/(2i*sqrt(b)),
  711. int(e^(~~b*~x^2),x) => erf(i*sqrt(b)*x)*sqrt(pi)/(2i*sqrt(b)),
  712. %% FJW: Rule missing:
  713. int(e^(~x^2/~b),x) => erf(i*x/sqrt(b))*sqrt(pi)*sqrt(b)/(2i),
  714. %% FJW: Missing sqrt(b):
  715. %% int(1/e^(~b*~x^2),x) => erf(x)*sqrt(pi)/(2sqrt(b)),
  716. int(1/e^(~~b*~x^2),x) => erf(sqrt(b)*x)*sqrt(pi)/(2sqrt(b)),
  717. %% FJW: Rule missing:
  718. int(1/e^(~x^2/~b),x) => erf(x/sqrt(b))*sqrt(pi)*sqrt(b)/2,
  719. df(ei(~x),x) => exp(x)/x,
  720. int(e^(~~b*~x)/x,x) => ei(b*x), % FJW
  721. int(e^(~x/~b)/x,x) => ei(x/b),
  722. int(1/(exp(~x*~~b)*x),x) => ei(-x*b), % FJW
  723. int(1/(exp(~x/~b)*x),x) => ei(-x/b),
  724. %% FJW: Next 2 rules replaced by ~~ rules above
  725. %% int(e^~x/x,x) => ei(x),
  726. %% int(1/(e^~x*x),x) => ei(-x),
  727. int(~a^~x/x,x) => ei(x*log(a)),
  728. int(1/((~a^~x)*x),x) => ei(-x*log(a)),
  729. df(si(~x),x) => sin(x)/x,
  730. int(sin(~~b*~x)/x,x) => si(b*x), % FJW
  731. int(sin(~x/~b)/x,x) => si(x/b), % FJW
  732. %% int(sin(~x)/x,x) => si(x), % FJW
  733. int(sin(~x)/x^2,x) => -sin(x)/x +ci(x),
  734. int(sin(~x)^2/x,x) =>(log(x)-ci(2x))/2,
  735. df(ci(~x),x) => cos(x)/x,
  736. int(cos(~~b*~x)/x,x) => ci(b*x), % FJW
  737. int(cos(~x/~b)/x,x) => ci(x/b), % FJW
  738. %% int(cos(~x)/x,x) => ci(x), % FJW
  739. int(cos(~x)/x^2,x) => -cos(x)/x -si(x),
  740. int(cos(~x)^2/x,x) =>(log(x)+ci(2x)/2),
  741. int(1/log(~~b*~x),x) => ei(log(b*x))/b, % FJW
  742. int(1/log(~x/~b),x) => ei(log(x/b))*b, % FJW
  743. %% int(1/log(~x),x) => ei(log(x)), % FJW
  744. %% int(1/log(~x+~b),x) => ei(log(x+b)), % FJW
  745. int(1/log(~~a*~x+~b),x) => ei(log(a*x+b))/b, % FJW
  746. int(1/log(~x/~a+~b),x) => ei(log(x/a+b))/b, % FJW
  747. int(~x/log(~x),x) => ei(2*log(x)),
  748. int(~x^~n/log(x),x) => ei((n+1)*log(x)) when fixp n,
  749. int(1/(~x^~n*log(x)),x) => ei((-n+1)*log(x)) when fixp n};
  750. let intrules;
  751. endmodule;
  752. end;