driver.red 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  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,!*precise;
  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;
  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 := zvars(getvariables x,zv,variable,t);
  131. tmp := ans1;
  132. while tmp do
  133. <<if zv=caar tmp
  134. then <<rplacd(car tmp,addsq(cdar tmp,x));
  135. tmp := nil; zv := nil>>
  136. else tmp := cdr tmp>>;
  137. if zv then ans1 := (zv . x) . ans1
  138. end;
  139. if length ans1 = 1 then oneterm := t; % Efficiency
  140. nexp := ans1;
  141. ans := nil ./ 1;
  142. badbit:=nil ./ 1; % SQ zero
  143. while nexp do % Run down the terms
  144. <<u := cdar nexp;
  145. if !*trdint
  146. then <<princ "Integrate"; printsq u;
  147. princ "with Zvars "; print caar nexp>>;
  148. ans1 := errorset!*(list('integratesq,mkquote u,
  149. mkquote variable,mkquote loglist,
  150. mkquote caar nexp),
  151. !*backtrace);
  152. nexp := cdr nexp;
  153. if errorp ans1 then badbit := addsq(badbit,u)
  154. else <<ans := addsq(caar ans1, ans);
  155. badbit:=addsq(cdar ans1,badbit)>>>>;
  156. if !*trdint
  157. then <<prin2 "Partial answer="; printsq ans;
  158. prin2 "To do="; printsq badbit>>;
  159. % We have run down the terms. If there are any bad bits, redo
  160. % them. However, since a non-zero badbit implies that
  161. % integratesq aborted, the internal variable order may be
  162. % confused. So we reset kord!* and reorder expressions in this
  163. % case.
  164. if badbit neq '(nil . 1)
  165. then <<setkorder nil;
  166. badbit := reordsq badbit;
  167. ans := reordsq ans;
  168. coefft := reordsq coefft;
  169. if !*trdint then <<princ "Retrying..."; printsq badbit>>;
  170. if oneterm and ans = '(nil . 1) then ans1 := nil
  171. else ans1 := errorset!*(list('integratesq,mkquote badbit,
  172. mkquote variable,mkquote loglist,nil),
  173. !*backtrace);
  174. if null ans1 or errorp ans1
  175. then ans := addsq(ans,simpint1(badbit . variable . w))
  176. else <<ans := addsq(ans,caar ans1);
  177. %% FJW: It is possible for ans here to be just a
  178. %% spurious constant term, in which case we discard it.
  179. if not smemq(variable, ans) then ans := nil ./ 1;
  180. %% This may not be the best place for this fix, but I
  181. %% don't see how it can ever do any harm. [I don't
  182. %% think we need a full depend test here.]
  183. if cdar ans1 neq '(nil . 1)
  184. then ans := addsq(ans,
  185. simpint1(cdar ans1 . variable . w))
  186. >>>>;
  187. end;
  188. ans := multsq(coefft,ans); %Put back coefficient, preserving order.
  189. % if errorp ans
  190. % then return <<put('sqrt,'simpfn,sqrtfn);
  191. % if !*failhard then error1();
  192. % simpint1(expression . variable . w)>>
  193. % else ans := car ans;
  194. % expression := sqrtchk numr ans ./ sqrtchk denr ans;
  195. if !*trdint then << printc "Resimp and all that"; printsq ans >>;
  196. % We now need to check that all simplifications have been done
  197. % but we have to make sure INT is not resimplified, and that SIMP
  198. % does not complain at getting the same argument again.
  199. put('int,'simpfn,'simpiden);
  200. put('sqrt,'simpfn,sqrtfn);
  201. << if dmod then onoff(dmod,t);
  202. % added by Alan Barnes
  203. if cflag then onoff('complex,t)>> where !*msg := nil;
  204. oldvarstack := varstack!*;
  205. varstack!* := nil;
  206. % ans := errorset!*(list('resimp,mkquote ans),t);
  207. ans := errorset!*(list('int!-resub,mkquote ans,mkquote
  208. varchange),t);
  209. put('int,'simpfn,'simpint);
  210. varstack!* := oldvarstack;
  211. return if errorp ans then error1() else car ans
  212. end;
  213. symbolic procedure int!-resub(x,v);
  214. % {sq,alist} -> sq
  215. % Undo any variable change and resimplify.
  216. if v then <<x := int!-subsq(x,{revpr v}); depend1(car v,cdr v,nil);
  217. resimp x>>
  218. else resimp x;
  219. symbolic procedure int!-subsq(x,v);
  220. % {sq,alist} -> sq
  221. % A version of subsq with the int and df operators unprotected.
  222. % Intended for straightforward change of variable names only.
  223. begin scalar subfuncs,subfg!*;
  224. subfuncs := {remprop('df,'subfunc),remprop('int,'subfunc)};
  225. x := subsq(x,v);
  226. put('df,'subfunc,car subfuncs);
  227. put('int,'subfunc,cadr subfuncs);
  228. return x
  229. end;
  230. symbolic procedure numlistp u;
  231. % True if u is a list of numbers.
  232. null u or numberp car u and numlistp cdr u;
  233. % symbolic procedure sqrtchk u;
  234. % % U is a standard form. Result is another standard form with square
  235. % % roots replaced by half powers.
  236. % if domainp u then u
  237. % else if not eqcar(mvar u,'sqrt)
  238. % then addf(multpf(lpow u,sqrtchk lc u),sqrtchk red u)
  239. % % else if mvar u = '(sqrt -1)
  240. % % then addf(multpf(mksp('i,ldeg u),sqrtchk lc u),sqrtchk red u)
  241. % else addf(multpf(mksp(list('expt,cadr mvar u,'(quotient 1 2)),
  242. % ldeg u),
  243. % sqrtchk lc u),
  244. % sqrtchk red u);
  245. symbolic procedure int!-simp u;
  246. % Converts U to canonical form, including the resimplification of
  247. % *sq forms.
  248. subs2 resimp simp!* u;
  249. put('int,'simpfn,'simpint);
  250. symbolic procedure integratesq(integrand,var,xlogs,zv);
  251. begin scalar varlist,x,zlist,!*noncomp;
  252. if !*trint then <<
  253. printc "Start of Integration; integrand is ";
  254. printsq integrand >>;
  255. !*noncomp := noncomfp numr integrand
  256. or noncomfp denr integrand;
  257. varlist:=getvariables integrand;
  258. varlist:=varsinlist(xlogs,varlist); %in case more exist in xlogs
  259. if zv then zlist := zv else zlist := zvars(varlist,zlist,var,nil);
  260. if !*trint then <<
  261. printc "Determination of the differential field descriptor";
  262. printc "gives the functions:";
  263. print zlist >>;
  264. %% Look for rational powers in the descriptor
  265. %% If there is make a suitable transformation and do the sub integral
  266. %% and return the revised integral
  267. x := look_for_substitute(integrand, var, zlist);
  268. if x then return x;
  269. %% End of rational patch
  270. if !*purerisch and not allowedfns zlist
  271. then return (nil ./ 1) . integrand;
  272. % If it is not suitable for Risch.
  273. varlist := setdiff(varlist,zlist);
  274. % varlist := purge(zlist,varlist);
  275. % Now zlist is list of things that depend on x, and varlist is list
  276. % of constant kernels in integrand.
  277. if !*algint and cdr zlist and algfnpl(zlist,var)
  278. then return algebraiccase(integrand,zlist,varlist)
  279. else return transcendentalcase(integrand,var,xlogs,zlist,varlist)
  280. end;
  281. symbolic procedure zvars(x,zv,variable,bool);
  282. % This code attempts to find all possible terms in the target
  283. % integral.
  284. % There used to be problems with nested exponentials or logs,
  285. % but that no longer seems true (10 May 00).
  286. begin scalar oldzlist; integer n;
  287. zv := findzvars(x,list variable,variable,nil);
  288. % The following loop is constrained to five passes to avoid problems
  289. % with differentiation rules such as let {df(f(~x),x) => x*f(x-1)}.
  290. % All integration tests run with just one pass through this loop, so
  291. % five passes is probably overkill.
  292. while oldzlist neq zv and n<5 do <<
  293. oldzlist := zv;
  294. foreach zz in oldzlist do
  295. % zv := findzvars(distexp(pseudodiff(zz,variable)),
  296. % zv,variable,t);
  297. zv := findzvars(pseudodiff(zz,variable),zv,variable,t);
  298. n := n+1>>;
  299. % The following line is based on experiments with the test files.
  300. % At the moment, it's not clear why it's needed, but it is!!
  301. if bool then zv := sort(zv,function ordp);
  302. return zv
  303. end;
  304. % symbolic procedure distexp(l);
  305. % if null l then nil
  306. % else if atom car l then car l . distexp cdr l
  307. % else if (caar l = 'expt) and (cadar l = 'e) then
  308. % begin scalar ll;
  309. % ll:=caddr car l;
  310. % if eqcar(ll,'plus) then <<
  311. % ll:=foreach x in cdr ll collect list('expt,'e,x);
  312. % return ('times . ll) . distexp cdr l >>
  313. % else return car l . distexp cdr l
  314. % end
  315. % else distexp car l . distexp cdr l;
  316. symbolic procedure pseudodiff(a,var);
  317. if atom a then % **** Treat diffs correctly??
  318. if depends(a,var) then list prepsq simpdf(list(a,var)) else nil
  319. else if car a
  320. memq '(atan equal log plus quotient sqrt times minus)
  321. then begin scalar aa,bb;
  322. foreach zz in cdr a do <<
  323. bb:=pseudodiff(zz,var);
  324. aa:= union(bb,aa) >>;
  325. return aa
  326. end
  327. else if car a eq 'expt
  328. then if depends(cadr a,var) then
  329. if depends(caddr a,var) then
  330. prepsq simp list('log,cadr a) . %% a(x)^b(x)
  331. cadr a .
  332. caddr a .
  333. union(pseudodiff(cadr a,var),pseudodiff(caddr a,var))
  334. else cadr a . pseudodiff(cadr a,var) %% a(x)^b
  335. else caddr a . pseudodiff(caddr a,var) %% a^b(x)
  336. else list prepsq simpdf(list(a,var));
  337. symbolic procedure look_for_substitute(integrand, var, zz);
  338. % Search for rational power transformations
  339. begin
  340. scalar res;
  341. if atom zz then return nil
  342. else if (res := look_for_rational(integrand, var, zz)) then return res
  343. else if (res := look_for_quad(integrand, var, zz)) then return res
  344. else if (res := look_for_substitute(integrand, var, car zz))
  345. then return res
  346. else return look_for_substitute(integrand, var, cdr zz)
  347. end;
  348. symbolic procedure look_for_rational(integrand, var, zz);
  349. % Look for a form x^(n/m) in the field descriptor, and transform
  350. % the integral if it is found. Note that the sqrt form may be used
  351. % as well as exponentials. Return nil if no transformation
  352. if (car zz = 'sqrt and cadr zz = var) then
  353. look_for_rational1(integrand, var, 2)
  354. else if (car zz = 'expt) and (cadr zz = var) and
  355. (listp caddr zz) and (caaddr zz = 'quotient) and
  356. (numberp cadr caddr zz) and (numberp caddr caddr zz) then
  357. look_for_rational1(integrand, var, caddr caddr zz)
  358. else nil;
  359. symbolic procedure look_for_rational1(integrand, var, m);
  360. % Actually do the transformation and integral
  361. begin
  362. scalar newvar, res, ss, mn2m!-1;
  363. newvar := gensym();
  364. mn2m!-1 := !*f2q(((newvar .** (m-1)) .* m) .+ nil);
  365. %% print ("Integrand was " . integrand);
  366. % x => y^m, and dx => m y^(m-1)
  367. integrand := multsq(subsq(integrand,
  368. list(var . list('expt,newvar,m))),
  369. mn2m!-1);
  370. if !*trint then <<
  371. prin2 "Integrand is transformed to ";
  372. printsq integrand
  373. >>;
  374. begin scalar intvar;
  375. intvar := newvar; % To circumvent an algint bug.
  376. res := integratesq(integrand, newvar, nil, nil);
  377. end;
  378. ss := list(newvar . list('expt,var, list('quotient, 1, m)));
  379. res := subsq(car res, ss) .
  380. subsq(quotsq(cdr res, mn2m!-1), ss);
  381. if !*trint then <<
  382. printc "Transforming back...";
  383. printsq car res;
  384. prin2 " plus a bad part of ";
  385. printsq cdr res
  386. >>;
  387. return res
  388. end;
  389. symbolic procedure look_for_quad(integrand, var, zz);
  390. % Look for a form sqrt(a+bx+cx^2) in the field descriptor
  391. % and transform to the appropriate asin, acosh or asinh.
  392. % Return nil if no transformation found
  393. if !*algint then nil % as Algint does it better??
  394. else begin
  395. if (car zz = 'sqrt and listp cadr zz and caadr zz = 'plus) or
  396. (car zz = 'expt and listp cadr zz and caadr zz = 'plus and
  397. listp caddr zz and car caddr zz = 'quotient
  398. and fixp caddr caddr zz)
  399. then <<
  400. zz := simp cadr zz;
  401. if (cdr zz = 1) then <<
  402. zz := cdr coeff1(prepsq zz, var, nil);
  403. if length zz = 2 then return begin % Linear
  404. scalar a, b;
  405. scalar nvar, res, ss;
  406. a := car zz; b := cadr zz;
  407. if (depends(a,var) or depends(b,var)) then return nil;
  408. nvar := gensym();
  409. if !*trint then <<
  410. prin2 "Linear shift suggested ";
  411. prin2 a; prin2 " "; prin2 b; terpri();
  412. >>;
  413. integrand := subsq(integrand, % Make the substitution
  414. list(var . list('quotient,
  415. list('difference,
  416. list('expt,nvar,2),a),
  417. b)));
  418. integrand := multsq(integrand, % and the dx component
  419. simp list('quotient,list('times,nvar,2),
  420. b));
  421. % integrand := subsq(integrand,
  422. % list(var . list('difference, nvar, a)));
  423. % integrand := multsq(integrand, simp b);
  424. if !*trint then <<
  425. prin2 "Integrand is transformed by substitution to ";
  426. printsq integrand;
  427. prin2 "using substitution "; prin2 var; prin2 " -> ";
  428. printsq simp list('quotient,
  429. list('difference,list('expt,nvar,2),a),
  430. b);
  431. >>;
  432. res := integratesq(integrand, nvar, nil, nil);
  433. ss := list(nvar . list('sqrt,list('plus,list('times,var,b),
  434. a)));
  435. res := subsq(car res, ss) .
  436. subsq(multsq(cdr res, simp list('quotient,b,
  437. list('times,nvar,2))), ss);
  438. %% Should one reject if there is a bad bit??
  439. return res;
  440. end
  441. else if length zz = 3 then return begin % A quadratic
  442. scalar a, b, c;
  443. a := car zz; b := cadr zz; c:= caddr zz;
  444. if (depends(a,var) or depends(b,var) or depends(c,var)) then
  445. return nil;
  446. a := simp list('difference, a, % Re-centre
  447. list('times,b,b,
  448. list('quotient,1,list('times,4,c))));
  449. if null numr a then return nil; % Power occurred.
  450. b := simp list('quotient, b, list('times, 2, c));
  451. c := simp c;
  452. return
  453. if minusf numr c then <<
  454. if minusf numr a then begin
  455. scalar !*hyperbolic;
  456. !*hyperbolic := t;
  457. return
  458. look_for_invhyp(integrand,nil,var,a,b,c)
  459. end
  460. else look_for_asin(integrand,var,a,b,c)>>
  461. else <<
  462. if minusf numr a then look_for_invhyp(integrand,t,var,a,b,c)
  463. else look_for_invhyp(integrand,nil,var,a,b,c)
  464. >>
  465. end
  466. else if length zz = 5 then return begin % A quartic
  467. scalar a, b, c, d, e, nn, dd, mm;
  468. a := car zz; b := cadr zz; c:= caddr zz;
  469. d := cadddr zz; e := car cddddr zz;
  470. if not(b = 0) or not(d = 0) then return nil;
  471. if (depends(a,var) or depends(c,var)) or depends(e,var) then
  472. return nil;
  473. nn := numr integrand; dd := denr integrand;
  474. if denr(mm :=quotsq(nn ./ 1, !*kk2q var)) = 1 and
  475. even_power(numr mm, var) and even_power(dd, var) then <<
  476. % substitute x -> sqrt(y)
  477. return sqrt_substitute(numr mm, dd, var);
  478. >>;
  479. if denr(mm :=quotsq(dd ./ 1, !*kk2q var)) = 1 and
  480. even_power(nn, var) and even_power(numr mm, var) then <<
  481. % substitute x -> sqrt(y)
  482. return sqrt_substitute(nn, multf(dd,!*kk2f var), var);
  483. >>;
  484. return nil;
  485. end;
  486. >>>>;
  487. return nil;
  488. end;
  489. symbolic procedure look_for_asin(integrand, var, a, b, c);
  490. % Actually do the transformation and integral
  491. begin
  492. scalar newvar, res, ss, sqmn, onemth, m, n;
  493. m := prepsq a;
  494. n := prepsq c;
  495. b := prepsq b;
  496. newvar := gensym();
  497. sqmn := prepsq apply1(get('sqrt, 'simpfn),
  498. list list('quotient, list('minus,n), m));
  499. onemth := list('cos, newvar);
  500. ss := list('sin, newvar);
  501. powlis!* := list(ss, 2, '(nil . t),
  502. list('difference,1,list('expt,onemth,2)),
  503. nil) .
  504. powlis!*;
  505. integrand := subs2q
  506. multsq(subsq(integrand,
  507. list(var . list('difference,
  508. list('quotient,ss,sqmn), b))),
  509. quotsq(onemth := simp onemth, simp sqmn));
  510. if !*trint then <<
  511. prin2 "Integrand is transformed by substitution to ";
  512. printsq integrand;
  513. prin2 "using substitution "; prin2 var; prin2 " -> ";
  514. printsq simp list('difference, list('quotient, ss, sqmn), b);
  515. >>;
  516. res := integratesq(integrand, newvar, nil, nil);
  517. powlis!* := cdr powlis!*;
  518. ss:= list(newvar . list('asin,list('times,list('plus,var,b),sqmn)));
  519. res := subsq(car res, ss) . subsq(quotsq(cdr res, onemth), ss);
  520. if !*trint then <<
  521. printc "Transforming back...";
  522. printsq car res;
  523. prin2 " plus a bad part of ";
  524. printsq cdr res
  525. >>;
  526. if (car res = '(nil . 1)) then return nil;
  527. return res;
  528. end;
  529. symbolic procedure look_for_invhyp(integrand, do_acosh, var, a, b, c);
  530. % Actually do the transformation and integral; uses acosh/asinh form
  531. % depending on second argument
  532. begin
  533. scalar newvar, res, ss, sqmn, onemth, m, n, realdom;
  534. m := prepsq a;
  535. n := prepsq c;
  536. b := prepsq b;
  537. newvar := gensym();
  538. if do_acosh then <<
  539. sqmn := prepsq apply1(get('sqrt, 'simpfn),
  540. list list('quotient, n, list('minus, m)));
  541. onemth := list('sinh, newvar);
  542. ss := list('cosh, newvar)
  543. >>
  544. else <<
  545. sqmn:= prepsq apply1(get('sqrt,'simpfn),list list('quotient,n,m));
  546. onemth := list('cosh, newvar);
  547. ss := list('sinh, newvar)
  548. >>;
  549. powlis!* := list(ss, 2, '(nil . t),
  550. list((if do_acosh then 'plus else 'difference),
  551. list('expt, onemth, 2),1),
  552. nil) .
  553. powlis!*;
  554. % print ("sqmn" . sqmn); print("onemth" . onemth); print ("ss" . ss);
  555. % print cdddar powlis!*;
  556. integrand := subs2q
  557. multsq(subsq(integrand,
  558. list(var . list('difference,list('quotient,ss,sqmn),b))),
  559. quotsq(onemth := simp onemth, simp sqmn));
  560. if !*trint then <<
  561. prin2 "Integrand is transformed by substitution to ";
  562. printsq integrand;
  563. prin2 "using substitution "; prin2 var; prin2 " -> ";
  564. printsq simp list('difference, list('quotient, ss, sqmn), b);
  565. >>;
  566. realdom := not smember('(sqrt -1),integrand);
  567. % print integrand; print realdom;
  568. res := integratesq(integrand, newvar, nil, nil);
  569. powlis!* := cdr powlis!*;
  570. if !*hyperbolic then <<
  571. ss := list(if do_acosh then 'acosh else 'asinh,
  572. list('times,list('plus,var,b), sqmn));
  573. >>
  574. else <<
  575. ss := list('times,list('plus,var,b), sqmn);
  576. ss := if do_acosh then
  577. subst(ss,'ss,
  578. '(log (plus ss (sqrt (difference (times ss ss) 1)))))
  579. else
  580. subst(ss,'ss,'(log (plus ss (sqrt (plus (times ss ss) 1)))))
  581. >>;
  582. ss := list(newvar . ss);
  583. res := sqrt2top subsq(car res, ss) .
  584. sqrt2top subsq(quotsq(cdr res, onemth), ss);
  585. if !*trint then <<
  586. printc "Transforming back...";
  587. printsq car res;
  588. prin2 " plus a bad part of ";
  589. printsq cdr res
  590. >>;
  591. if (car res = '(nil . 1)) then return nil;
  592. if realdom and smember('(sqrt -1),res) then <<
  593. if !*trint then print "Wrong sheet"; return nil; % Wrong sheet?
  594. >>;
  595. return res
  596. end;
  597. symbolic procedure simpint1 u;
  598. % Varstack* rebound, since FORMLNR use can create recursive
  599. % evaluations. (E.g., with int(cos(x)/x**2,x)).
  600. begin scalar !*keepsqrts,v,varstack!*;
  601. u := 'int . prepsq car u . cdr u;
  602. if (v := formlnr u) neq u
  603. then if !*nolnr
  604. then <<v := simp subst('int!*,'int,v);
  605. return remakesf numr v ./ remakesf denr v>>
  606. else <<!*nolnr := nil . !*nolnr;
  607. v:=errorset!*(list('simp,mkquote v),!*backtrace);
  608. if pairp v then v := car v else v := simp u;
  609. !*nolnr := cdr !*nolnr;
  610. return v>>;
  611. return if (v := opmtch u) then simp v
  612. else symint u % FJW: symbolic integral
  613. end;
  614. mkop 'int!*;
  615. put('int!*,'simpfn,'simpint!*);
  616. symbolic procedure simpint!* u;
  617. begin scalar x;
  618. return if (x := opmtch('int . u)) then simp x
  619. else simpiden('int!* . u)
  620. end;
  621. symbolic procedure remakesf u;
  622. %remakes standard form U, substituting operator INT for INT!*;
  623. if domainp u then u
  624. else addf(multpf(if eqcar(mvar u,'int!*)
  625. then mksp('int . cdr mvar u,ldeg u)
  626. else lpow u,remakesf lc u),
  627. remakesf red u);
  628. symbolic procedure allowedfns u;
  629. if null u then t
  630. else if atom car u then (car u=intvar) or not depends(car u,intvar)
  631. else if (caar u = 'expt and not (cadar u = 'e)
  632. and not depends(cadar u, intvar)
  633. and depends(caddar u, intvar)) then nil
  634. else if flagp(caar u,'transcendental) then allowedfns cdr u
  635. else nil;
  636. symbolic procedure look_for_power(integrand, var);
  637. begin
  638. scalar nn, dd, mm;
  639. nn := numr integrand; dd := denr integrand;
  640. if denr(mm :=quotsq(nn ./ 1, !*kk2q var)) = 1 and
  641. even_power(numr mm, var) and even_power(dd, var) then <<
  642. % substitute x -> sqrt(y)
  643. return sqrt_substitute(numr mm, dd, var);
  644. >>;
  645. if denr(mm :=quotsq(dd ./ 1, !*kk2q var)) = 1 and
  646. even_power(nn, var) and even_power(numr mm, var) then <<
  647. % substitute x -> sqrt(y)
  648. return sqrt_substitute(nn, numr mm, var);
  649. >>;
  650. return nil;
  651. end;
  652. symbolic procedure even_power(xpr, var);
  653. if atom xpr then t
  654. else if mvar xpr = var then <<
  655. if evenp pdeg lpow xpr then even_power(lc xpr, var) and
  656. even_power(red xpr, var)
  657. else nil >>
  658. else if eqcar(mvar xpr, 'expt) and
  659. cadr mvar xpr = var and
  660. evenp caddr mvar xpr then t
  661. else if atom mvar xpr then
  662. even_power(lc xpr, var) and even_power(red xpr, var)
  663. else if even_power(red xpr, var) and even_power(lc xpr, var) then
  664. even_prep(mvar xpr, var);
  665. symbolic procedure even_prep(xpr,var);
  666. if xpr = var then nil
  667. else if atom xpr then t
  668. else if eqcar(xpr, 'expt) and cadr xpr = var and evenp caddr xpr then t
  669. else if even_prep(car xpr, var) then even_prep(cdr xpr, var);
  670. symbolic procedure sqrt_substitute(nn, dd, var);
  671. begin
  672. scalar newvar, integrand, res, ss, !*keepsqrts;
  673. newvar := gensym();
  674. integrand := subst(list('sqrt,newvar), var,
  675. list('quotient, prepsq (nn ./ dd), 2));
  676. integrand := prepsq simp integrand;
  677. integrand := simp integrand;
  678. begin scalar intvar;
  679. intvar := newvar; % To circumvent an algint bug/oddity
  680. res := integratesq(integrand, newvar, nil, nil);
  681. end;
  682. ss := list(newvar . list('expt, var, 2));
  683. res := subsq(car res, ss) . multsq((((var .^ 1) .* 2) .+ nil) ./ 1,
  684. subsq(cdr res, ss));
  685. if !*trint then <<
  686. printc "Transforming back...";
  687. printsq car res;
  688. prin2 " plus a bad part of ";
  689. printsq cdr res
  690. >>;
  691. return res
  692. end;
  693. % The following rules probably belong in other places.
  694. %-----------------------------------------------------------------------
  695. algebraic;
  696. operator ci,si; % ei.
  697. % FJW: ci,si also defined in specfn(sfint.red), so ...
  698. symbolic((algebraic operator ci,si) where !*msg=nil);
  699. intrules :=
  700. {e^(~n*acosh(~x)) => (sqrt(x^2-1)+x)^n when numberp n,
  701. e^(~n*asinh(~x)) => (sqrt(x^2+1)+x)^n when numberp n,
  702. e^(acosh(~x)) => (sqrt(x^2-1)+x),
  703. e^(asinh(~x)) => (sqrt(x^2+1)+x),
  704. cosh(log(~x)) => (x^2+1)/(2*x),
  705. sinh(log(~x)) => (x^2-1)/(2*x),
  706. % These next two are rather uncertain.
  707. int(log(~x)/(~b-x),x) => dilog(x/b),
  708. int(log(~x)/(~b*x-x^2),x) => dilog(x/b)/b + log(x)^2/(2b),
  709. %% FJW: Next 2 rules replaced by ~~ rules below
  710. %% int(e^(~x^2),x) => erf(i*x)*sqrt(pi)/(2i),
  711. %% int(1/e^(~x^2),x) => erf(x) * sqrt(pi)/2,
  712. %% FJW: Missing sqrt(b):
  713. %% int(e^(~b*~x^2),x) => erf(i*x)*sqrt(pi)/(2i*sqrt(b)),
  714. int(e^(~~b*~x^2),x) => erf(i*sqrt(b)*x)*sqrt(pi)/(2i*sqrt(b)),
  715. %% FJW: Rule missing:
  716. int(e^(~x^2/~b),x) => erf(i*x/sqrt(b))*sqrt(pi)*sqrt(b)/(2i),
  717. %% FJW: Missing sqrt(b):
  718. %% int(1/e^(~b*~x^2),x) => erf(x)*sqrt(pi)/(2sqrt(b)),
  719. int(1/e^(~~b*~x^2),x) => erf(sqrt(b)*x)*sqrt(pi)/(2sqrt(b)),
  720. %% FJW: Rule missing:
  721. int(1/e^(~x^2/~b),x) => erf(x/sqrt(b))*sqrt(pi)*sqrt(b)/2,
  722. df(ei(~x),x) => exp(x)/x,
  723. int(e^(~~b*~x)/x,x) => ei(b*x), % FJW
  724. int(e^(~x/~b)/x,x) => ei(x/b),
  725. int(1/(exp(~x*~~b)*x),x) => ei(-x*b), % FJW
  726. int(1/(exp(~x/~b)*x),x) => ei(-x/b),
  727. %% FJW: Next 2 rules replaced by ~~ rules above
  728. %% int(e^~x/x,x) => ei(x),
  729. %% int(1/(e^~x*x),x) => ei(-x),
  730. int(~a^~x/x,x) => ei(x*log(a)),
  731. int(1/((~a^~x)*x),x) => ei(-x*log(a)),
  732. df(si(~x),x) => sin(x)/x,
  733. int(sin(~~b*~x)/x,x) => si(b*x), % FJW
  734. int(sin(~x/~b)/x,x) => si(x/b), % FJW
  735. %% int(sin(~x)/x,x) => si(x), % FJW
  736. int(sin(~x)/x^2,x) => -sin(x)/x +ci(x),
  737. int(sin(~x)^2/x,x) =>(log(x)-ci(2x))/2,
  738. df(ci(~x),x) => cos(x)/x,
  739. int(cos(~~b*~x)/x,x) => ci(b*x), % FJW
  740. int(cos(~x/~b)/x,x) => ci(x/b), % FJW
  741. %% int(cos(~x)/x,x) => ci(x), % FJW
  742. int(cos(~x)/x^2,x) => -cos(x)/x -si(x),
  743. int(cos(~x)^2/x,x) =>(log(x)+ci(2x)/2),
  744. int(1/log(~~b*~x),x) => ei(log(b*x))/b, % FJW
  745. int(1/log(~x/~b),x) => ei(log(x/b))*b, % FJW
  746. %% int(1/log(~x),x) => ei(log(x)), % FJW
  747. %% int(1/log(~x+~b),x) => ei(log(x+b)), % FJW
  748. int(1/log(~~a*~x+~b),x) => ei(log(a*x+b))/b, % FJW
  749. int(1/log(~x/~a+~b),x) => ei(log(x/a+b))/b, % FJW
  750. int(~x/log(~x),x) => ei(2*log(x)),
  751. int(~x^~n/log(x),x) => ei((n+1)*log(x)) when fixp n,
  752. int(1/(~x^~n*log(x)),x) => ei((-n+1)*log(x)) when fixp n};
  753. let intrules;
  754. endmodule;
  755. end;