defintx.red 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. module defintx; % Code for definite integration using contour methods.
  2. % Author: Stanley L. Kameny <stan_kameny@rand.org>.
  3. load_package solve,misc;
  4. fluid '(!*allpoly rdon!* !*norationalgi); switch allpoly;
  5. global '(domainlist!* poles!*);
  6. algebraic <<
  7. logcomplex :=
  8. {
  9. log(~x + i) =>
  10. log(sqrt(x*x+1))+i*atan2(1/sqrt(x*x+1),x/sqrt(x*x+1))
  11. when repart(x)=x,
  12. log(~x - i) =>
  13. log(sqrt(x*x+1))-i*atan2(1/sqrt(x*x+1),x/sqrt(x*x+1))
  14. when repart(x)=x,
  15. log(~x + i*~y) =>
  16. log(sqrt(x*x+y*y))+i*atan2(y/sqrt(x*x+y*y),x/sqrt(x*x+y*y))
  17. when repart(x)=x and repart(y)=y,
  18. log(~x - i*~y) =>
  19. log(sqrt(x*x+y*y))-i*atan2(y/sqrt(x*x+y*y),x/sqrt(x*x+y*y))
  20. when repart(x)=x and repart(y)=y,
  21. log(~x/~y) => log(x) - log(y) when repart(y)=y,
  22. log(sqrt ~x) => (log x)/2,
  23. log(-1) => i*pi,
  24. log (-i) => -i*pi/2,
  25. log i => i*pi/2,
  26. log(-~x) => i*pi+log x when repart(x)=x and numberp x and x>0,
  27. log(-i*~x) => -i*pi/2 + log x
  28. when repart(x)=x and numberp x and x>0,
  29. log(i*~x) => i*pi/2 + log x when repart(x)=x and numberp x and x>0
  30. }$
  31. atan2eval :=
  32. {
  33. atan2(sqrt 3/2,1/2) => pi/3,
  34. atan2(-sqrt 3/2,1/2) => -pi/3,
  35. atan2(sqrt 3/2,-1/2) => 2*pi/3,
  36. atan2(-sqrt 3/2,-1/2) => -2*pi/3,
  37. atan2(3/(2*sqrt 3),1/2) => pi/3, % these shouldn't be needed
  38. atan2(-3/(2*sqrt 3),1/2) => -pi/3, % these shouldn't be needed
  39. atan2(3/(2*sqrt 3),-1/2) => 2*pi/3, % these shouldn't be needed
  40. atan2(-3/(2*sqrt 3),-1/2) => -2*pi/3, % these shouldn't be needed
  41. atan2(1/2,sqrt 3/2) => pi/6,
  42. atan2(-1/2,sqrt 3/2) => -pi/6,
  43. atan2(1/2,-sqrt 3/2) => 5*pi/6,
  44. atan2(-1/2,-sqrt 3/2) => -5*pi/6,
  45. atan2(1/2,3/(2*sqrt 3)) => pi/6, % these shouldn't be needed
  46. atan2(-1/2,3/(2*sqrt 3)) => -pi/6, % these shouldn't be needed
  47. atan2(1/2,-3/(2*sqrt 3)) => 5*pi/6, % these shouldn't be needed
  48. atan2(-1/2,-3*(2*sqrt 3)) => -5*pi/6, % these shouldn't be needed
  49. atan2(sqrt 2/2,sqrt 2/2) => pi/4,
  50. atan2(-sqrt 2/2,sqrt 2/2) => -pi/4,
  51. atan2(sqrt 2/2,-sqrt 2/2) => 3*pi/4,
  52. atan2(-sqrt 2/2,-sqrt 2/2) => -3*pi/4,
  53. atan2(0,-1) => pi,
  54. atan2(0,1) => 0,
  55. atan2(1,0) => pi/2,
  56. atan2(-1,0) => -pi/2
  57. }$
  58. ipower := {i^~n => cos(n*pi/2) + i*sin(n*pi/2),
  59. (-i)^~n => cos(n*pi/2) - i*sin(n*pi/2)}$
  60. >> $
  61. algebraic let ipower,atan2eval;
  62. %algebraic let logcomplex,atan2eval;
  63. fluid '(!*diffsoln zplist!! poles!# !*msg !*rounded !*complex zlist);
  64. switch diffsoln;
  65. load_package int;
  66. % put('defint,'psopfn,'defint0);
  67. symbolic procedure defint0 u;
  68. begin
  69. scalar rdon!*,!*msg,c,!*noneglogs,fac,!*norationalgi,
  70. !*combinelogs,!*rationalize;
  71. if not getd 'solvesq then load_package solve;
  72. if length u neq 4 then rederr
  73. "defint called with wrong number of args";
  74. c := !*complex; off complex; % since complex on won't work here!
  75. % on complex; % this causes trouble here, so it was moved into
  76. % defint11s after splitfactors has operated!
  77. !*noneglogs := t;
  78. algebraic (let logcomplex); %,atan2eval);
  79. fac := !*factor; on factor; !*norationalgi := t;
  80. u := errorset2 {'defint1,mkquote u};
  81. !*norationalgi := nil;
  82. if errorp u then <<u := 'failed; go to ret>> else u := car u;
  83. off factor;
  84. if !*rounded then
  85. % if approximate answer, eliminate infinitessimal real or
  86. % imaginary part.
  87. (<<off complex;
  88. if domainp numr u and denr u = 1 then
  89. (if evallessp({'times,{'abs,prepsq im},eps},
  90. {'abs,prepsq rl})
  91. then u := rl else
  92. if evallessp({'times,{'abs,prepsq rl},eps},
  93. {'abs,prepsq im})
  94. then u := addsq(u,negsq rl));
  95. u := mk!*sq u;
  96. if rdon!* then off rounded;off complex; go to ret2>>
  97. where rl=repartsq u,im=impartsq u,eps=10.0^(2-precision 0));
  98. !*rationalize := t;
  99. u := aeval prepsq u;
  100. on complex;
  101. u := simp!* u;
  102. % u := evalletsub2({'(logcomplexs),
  103. % {'simp!*,{'prepsq,mkquote u}}},nil);
  104. % if errorp u then error(99,list("error during log simp"))
  105. % else u := car u;
  106. ret: if fac then on factor;
  107. algebraic (clearrules logcomplex); %,atan2eval);
  108. if u neq 'failed then u := prepsq u;
  109. off complex; on combinelogs;
  110. if u neq 'failed then u := aeval u;
  111. ret2: if c then on complex;
  112. return u end;
  113. symbolic procedure defint1 u; defint11s(car u,cadr u,caddr u,cadddr u);
  114. symbolic procedure defint11s(exp,var,llim,ulim);
  115. % removes from integrand any factors independent of var, and passes
  116. % the dependent factors to defint11. Based on FACTOR being on.
  117. <<% off complex; % not needed here since complex is off already.
  118. exp := splitfactors(simp!* aeval exp,var);
  119. on complex; % at this point it is safe to turn complex on.
  120. multsq(simp!* car exp,
  121. defint11(cadr exp,var,llim,ulim,t))>>;
  122. symbolic procedure fxinfinity x;
  123. if x eq 'infinity then 'inf
  124. else if x = '(minus infinity) then 'minf else x;
  125. symbolic procedure defint11(exp,var,llim,ulim,dtst);
  126. if evalequal(llim := fxinfinity llim, ulim := fxinfinity ulim)
  127. or evalequal(exp,0) then nil ./ 1 else
  128. begin scalar !*norationalgi,r,p,q,poles,rlrts,cmprts,q1;
  129. scalar m,n;
  130. if ulim = 'minf or llim = 'inf then
  131. return defint11({'minus,exp},var,ulim,llim,dtst);
  132. exp := simp!* exp;
  133. % Now the lower limit must be 'minf or a finite value,
  134. % and the upper limit must be 'inf or a finite value. There are
  135. % four cases:
  136. % Upper limit is 'inf. Convert lower limit to zero if necessary,
  137. % and use methods for infinite integrals.
  138. if ulim = 'inf then
  139. <<if not(llim member '(0 minf)) then
  140. <<exp := subsq(exp,{var . {'plus,var,llim}}); llim := 0>>;
  141. go to c0>>;
  142. % lower limit is 'minf. Convert this case to upper limit 'inf.
  143. if llim = 'minf then
  144. <<off complex;
  145. exp := reval prepsq subsq(exp,{var . {'minus,var}});
  146. llim := reval {'minus,ulim};
  147. on complex;
  148. return defint11(exp,var,llim,'inf,dtst)>>;
  149. % Both limits are finite, so check for indef integral and
  150. % substitute values if it exists; else check for special forms with
  151. % finite limits, try substitutions, or abort.
  152. r := simpint {prepsq exp,var};
  153. if eqcar(prepsq r,'int) then go to c1;
  154. p := errorset2 list('subsq, mkquote r, mkquote {var . ulim});
  155. q := errorset2 list('subsq, mkquote r, mkquote {var . llim});
  156. if errorp(p) or errorp (q) then <<
  157. p:= simplimit list('limit!- ,mk!*sq(r),var,ulim);
  158. q:= simplimit list('limit!+ ,mk!*sq(r),var,llim); >>
  159. else <<p := car p; q := car q>>;
  160. return q1 := addsq(p,negsq q);
  161. c1: rederr "special forms for finite limits not implemented";
  162. c0: r := exp; p := numr r; q := denr r;
  163. % if not polynomp(q,var) then
  164. % rederr "only polynomial denominator implemented";
  165. m := degreeof(p,var); n := degreeof(q,var);
  166. if smemql('(failed infinity),m) or smemql('(failed infinity),n)
  167. then return error(99, 'failed);
  168. % Note that degreeof may return a fraction or a general complex
  169. % quantity.
  170. if not evalgreaterp(prepsq addsq(repartsq n,negsq repartsq m),1)
  171. then go to div;
  172. % this is the point at which special cases can be tested.
  173. if (q1 := specformtestint(q,p,var,llim,ulim)) then return q1;
  174. % beyond here, only rational functions are handled.
  175. if not (m := sq2int m) or not (n := sq2int n) then
  176. <<write "this irrational function case not handled"; terpri();
  177. error(99,'failed)>>;
  178. if n - m < 2 then go to div;
  179. if dtst and !*diffsoln then
  180. if (q1 := diffsol(q,p,m,n,var,llim,ulim)) then return q1;
  181. off factor; !*norationalgi := nil;
  182. poles := getpoles(q,var,llim);
  183. rlrts := append(car poles,cadr poles); cmprts := caddr poles;
  184. !*norationalgi := t;
  185. q1 := difff(q,var); q := q ./ 1; p := p ./ 1;
  186. return if llim = 0 then defint2(p,q,q1,var,rlrts,cmprts)
  187. else defint3(p,q,q1,var,rlrts,cmprts);
  188. div: % write "integral diverges"; terpri();
  189. error(99,'failed) end;
  190. symbolic procedure zpsubsq x;
  191. subsq(x,for each v in zplist!! collect (v . 0));
  192. symbolic procedure degreeof(p,var);
  193. % p is a standard form.
  194. % Note that limit returns "failed" as a structure, not an id.
  195. % Also, the limit code has problems with bessels at the present time.
  196. % if smemq('besseli,p) then !*k2q 'failed else
  197. if smemql ('(besselj besselk bessely besseli),p) then !*k2q 'failed else
  198. (if null car de then de else
  199. <<if d then onoff(d := get(d,'dname),nil);
  200. p := simp!*
  201. limit(list('quotient,list('times,var, prepsq de),prepf p),
  202. var,'infinity);
  203. if d then onoff(d,t); p>>)
  204. where d=dmode!*,de=difff(p,var);
  205. symbolic procedure genminusp x;
  206. if domainp x then !:minusp x else !:minusp topeval prepf x;
  207. symbolic procedure sq2int x;
  208. (if null numr impartsq x and denr y=1
  209. then if null z then 0 else if numberp z then z else nil)
  210. where z=numr y where y=repartsq x;
  211. symbolic procedure topeval u;
  212. <<if not r then on rounded; if not c then on complex;
  213. u := numr simp!* aeval u;
  214. if not r then off rounded;if not c then off complex; u>>
  215. where r=!*rounded,c=!*complex,!*msg=nil;
  216. symbolic procedure firstatom x;
  217. if atom x then x else firstatom car x;
  218. symbolic procedure valueof u;
  219. (if firstatom x neq 'root_of then x) where x=caar u;
  220. symbolic procedure rdsolvesq u;
  221. solvesq(subf(numr simp!* cadr x,list((caddr x) . caadr u)),
  222. caadr u,caddr u)
  223. where x=caaaar caar u;
  224. symbolic procedure defint2(p,q,q1,var,rlrts,cmprts);
  225. % Does the actual computation of integral with limits 0, inf.
  226. % Pertinent poles and their orders have been found previously.
  227. begin scalar int;
  228. p := simp!* aeval{'times,{'log,{'minus,var}},prepsq p};
  229. int := nil ./ 1;
  230. for each r in append(rlrts,cmprts) do
  231. int := addsq(int,residuum(p,q,q1,var,prepsq car r,cdr r));
  232. return negsq int end;
  233. symbolic procedure defint3(p,q,q1,var,rlrts,cmprts);
  234. % Does the actual computation of integral with limits minf, inf.
  235. % Pertinent poles and their orders have been found previously.
  236. begin scalar int,int2;
  237. int := int2 := nil ./ 1;
  238. for each r in cmprts do
  239. int := addsq(int,residuum(p,q,q1,var,prepsq car r,cdr r));
  240. int := addsq(int,int);
  241. for each r in rlrts do
  242. int2 := addsq(int2,residuum(p,q,q1,var,prepsq car r,cdr r));
  243. int := addsq(int,int2);
  244. return multsq(simp!* '(times pi i),int) end;
  245. symbolic procedure diffsqn(sq,var,n);
  246. <<if n>0 then for j := 1:n do sq := diffsq(sq,var); sq>>;
  247. symbolic procedure polypwrp(exp,var);
  248. begin scalar pol,fl; integer s,pwr;
  249. if eqcar(exp,'expt) then
  250. <<pol := cadr exp; if (pwr := caddr exp) <2 then return nil;
  251. if atom pol then
  252. if var eq pol then s := 1 else return nil
  253. else if not eqcar(pol,'plus) then return nil
  254. else for each p in cdr pol do s := max(s,termvpwr(p,var));
  255. return if s = 0 then nil else {pol,s,pwr}>>
  256. else if eqcar(exp,'times) then
  257. <<exp := for each p in cdr exp collect polypwrp(p,var);
  258. for each p in exp do
  259. <<if null p then fl := t;
  260. if not fl then pwr := gcdn(pwr,caddr p)>>;
  261. if fl then return nil;
  262. s := (for each p in exp sum cadr p * caddr p)/pwr;
  263. pol := 'times .
  264. for each p in exp collect {'expt,car p,caddr p/pwr};
  265. return {pol,s,pwr}>> end;
  266. symbolic procedure termvpwr(p,var);
  267. if freeof(p,var) then 0
  268. else if atom p then 1
  269. else if eqcar(p,'expt) and cadr p = var and
  270. numberp caddr p then caddr p
  271. else if eqcar(p,'times) then for each q in cdr p sum termvpwr(q,var)
  272. else 0;
  273. symbolic procedure diffsol(q,p,mm,nn,var,llim,ulim);
  274. % p is numerator q is denom mm is deg p nn is deg q
  275. (q := polypwrp(prepf q,var)) and
  276. begin scalar n,s,m,r,zplist!!;
  277. n := mm; s := cadr q; m := caddr q;
  278. % if s, the power of the base polynomial, > 4 then the base
  279. % polynomial won't be solved, and this approach won't work!
  280. % However, for s > 2, the approach is impractical, because the
  281. % roots of the zp!! polynomial are too complicated, so in the
  282. % following, s is tested s > 2.
  283. if s > 2 or m*s neq nn or nn - n <= 2 then return nil;
  284. r := (n+2)/s; if r*s < n+2 then r := r+1;
  285. if m = r then return nil;
  286. q := {'plus,car q,'zp!!}; zplist!! := '(zp!!);
  287. q := numr simp!*{'expt,q,r};
  288. nn :=(-1)^(m - r)*factorial(r - 1) ./ factorial(m - 1);
  289. p := defint11(prepsq(p ./ q),var,llim,ulim,nil);
  290. p := zpsubsq diffsqn(p,'zp!!,m - r);
  291. return multsq(nn,p) end;
  292. symbolic procedure residuum(p,q,q1,var,pole,m);
  293. if m=1 then subsq(quotsq(p,q1),list(var . pole))
  294. else
  295. begin integer n;
  296. q1 := nil;
  297. for each r in poles!* do
  298. <<n := cdr r; r := prepsq car r;
  299. if not evalequal(pole,r)
  300. then q1 := {'expt,{'difference,var,r},n} . q1>>;
  301. n := ((lc numr simp!* prepsq q) where !*factor=nil);
  302. q1 := 'times . (n . q1);
  303. return if ((lt numr simp!* prepsq q =
  304. lt numr simp!*{'times,{'expt,{'difference,var,pole},m},q1})
  305. where !*factor=nil)
  306. then
  307. <<q := quotsq(p,simp!* q1);
  308. q := diffsqn(q,var,m - 1);
  309. q := subsq(q,{var . pole});
  310. q := if null numr q
  311. then q else quotsq(q,factorial(m -1) ./ 1)>>
  312. else q1 := simp!* (p := limit(
  313. prepsq
  314. quotsq(diffsqn(multsq(quotsq(p,q),
  315. simp!* {'expt,{'difference,var,pole},m}),var,m - 1),
  316. factorial(m - 1) ./ 1),var,pole)) end;
  317. symbolic procedure splitfactors(u,var);
  318. % returns a list of two factors:
  319. % independent of var and dependent on var.
  320. begin scalar n,d,ni,nd,di,dd,fli,fld;
  321. n := prepf numr u;
  322. if n=0 then return {0,0};
  323. d := prepf denr u;
  324. ni := nd := di := dd := 1;
  325. if simptermp n then
  326. <<if freeof(n,var) then ni := n else nd := n; go to d>>;
  327. for each x in cdr n do
  328. if freeof(x,var) then ni := if ni = 1 then list x
  329. else <<fli := t; x . ni>>
  330. else nd := if nd = 1 then list x else <<fld := t; x . nd>>;
  331. ni := fleshoutt(ni,fli); nd := fleshoutt(nd,fld);
  332. fli := fld := nil;
  333. d: if simptermp d then
  334. <<if freeof(d,var) then di := d else dd := d; go to ret>>;
  335. for each x in cdr d do
  336. if freeof(x,var) then di := if di = 1 then list x
  337. else <<fli := t; x . di>>
  338. else dd := if dd = 1 then list x else <<fld := t; x . dd>>;
  339. di := fleshoutt(di,fli); dd := fleshoutt(dd,fld);
  340. ret: return {fleshout(ni,di),fleshout(nd,dd)} end;
  341. symbolic procedure simptermp x;
  342. atom x or ((y = 'minus and simptermp cadr x or y neq 'times)
  343. where y=car x);
  344. symbolic procedure fleshout(n,d); if d = 1 then n else {'quotient,n,d};
  345. symbolic procedure fleshoutt(n,d);
  346. if n = 1 then n else if d then 'times . n else car n;
  347. symbolic procedure specformtestint(den,num,var,llim,ulim);
  348. % This tests for defint(x^(p-1)/(a*x^n+b)^m,x,0,inf) with
  349. % m,n,p positive integers, p/n not integer and m>(p/n) and either
  350. % a*b>0 or {a*b<0,m=1}.
  351. % Since splitfactors has removed all factors which do not depend upon
  352. % var, both num and den are either 1 or products of terms which
  353. % depend upon var.
  354. begin scalar a,b,d,m,n,p,q1,q,k,z,ff;
  355. den := prepf den; num := prepf num;
  356. if not(llim=0) and ulim='inf then go to t2;
  357. % This is the test for defint(y**(q-1)/(a*y**n +b)**m,y,0,inf);
  358. % which is converted to defint(x**(p-1)/(x+z)**m,x,0,inf);
  359. % the next test is assumed to be accessed at label t2.
  360. if num = 1 then q1 := 0
  361. else if (q1 := varpwrtst(num,var))=0 then go to t2;
  362. if atom den then go to t2
  363. else if not eqcar(den,'times) then
  364. %only (a*y**n+b)**m term in den.
  365. if (k := aynbmtst(den,var)) then go to sep4 else go to t2
  366. else if length den neq 3 then go to t2;
  367. % the denominator is the product of 2 terms, one of which must be
  368. % y**q and the other an aynbm form like the previous case.
  369. d := cdr den;
  370. if not((k := aynbmtst(cadr d,var))
  371. and eqcar(q := varpwrtst(car d,var),'quotient)
  372. or
  373. (k := aynbmtst(car d,var))
  374. and eqcar(q := varpwrtst(cadr d,var),'quotient))
  375. then go to t2;
  376. sep4: n := caddr k; if not numberp n then go to t3;
  377. q := prepsq simp!* {'plus,1,q1,{'minus,q}};
  378. p := prepsq simp!* {'quotient,q,n};
  379. m := cadddr k; if not numberp m or m<1 then go to t3;
  380. a := car k;
  381. b := cadr k;
  382. z := prepsq simp!* {'quotient,b,a};
  383. if numr impartsq simp!* z then go to t2;
  384. ff := prepsq simp!* aeval {'quotient,1,{'times,n,{'expt,a,m}}};
  385. % there are two different cases:
  386. % z > 0 and m >repart p >0 m >= 1
  387. % z < 0 and m=1 (Cauchy principal value)
  388. if evalgreaterp(z,0) then if
  389. not (evalgreaterp((k := prepsq repartsq simp!* p),0) and
  390. evalgreaterp(m,k))
  391. then go to t3
  392. else
  393. <<k := prepsq simp!* aeval
  394. {'times,{'expt,-1,m+1},'pi,{'expt,z,{'difference,p,m}}};
  395. n := 1;
  396. for c := 1:(m-1) do
  397. n := prepsq simp!* aeval {'times,n,{'difference,p,c}};
  398. q := prepsq simp!* aeval
  399. {'times,{'factorial,m-1},{'sin,{'times,p,'pi}}};
  400. return simp!* aeval {'quotient,{'times,k,n,ff},q}>>;
  401. if m neq 1 then go to t3;
  402. write "Cauchy principal value"; terpri();
  403. k := prepsq simp!* aeval
  404. {'minus,{'expt,{'quotient,-1,z},{'difference,1,p}}};
  405. q := prepsq simp!* aeval
  406. {'times,ff,{'quotient,'pi,{'times,a,n}},{'cot,{'times,'pi,p}}};
  407. return simp!* aeval {'times,k,q};
  408. t3: return nil; % most (if not all) of these are divergence cases.
  409. t2: return specformtestint2(den,num,var,llim,ulim) end;
  410. symbolic procedure aynbmtst(exp,var);
  411. % test for form (a*y**n+b)**m (or degenerate forms of this) and
  412. % extract parameters a,n,b,m. b qnd m are required to be present.
  413. % car exp = 'expt or else m=1.
  414. begin scalar a,b,m,n;
  415. if not eqcar(exp,'expt) then <<m := 1; goto a2>>;
  416. m := caddr exp;
  417. exp := cadr exp;
  418. a2: if not eqcar(exp,'plus) or length exp neq 3 then return nil;
  419. b := caddr exp;
  420. if eqcar(cadr exp,'times) then
  421. <<exp := cdadr exp;
  422. if length exp neq 2 or not(
  423. numberp (a := car exp)
  424. and (n := varpwrtst(cadr exp,var)) neq 0
  425. or
  426. numberp (a := cadr exp)
  427. and (n := varpwrtst(car exp,var)) neq 0)
  428. then return nil>>
  429. else
  430. <<a := 1;
  431. if (n := varpwrtst(cadr exp,var)) = 0 then return nil>>;
  432. return {a,b,n,m} end;
  433. fluid '(!*fullpoly); switch fullpoly;
  434. symbolic procedure getpoles(q,var,llim);
  435. begin scalar poles,rt,m,rlrt,cmprt,rtv,rtvz,cpv,prlrts,nrlrts,rlrts,
  436. cmprts,!*multiplicities,!*fullroots,!*norationalgi;
  437. off factor; !*norationalgi := poles!* := nil;
  438. !*multiplicities := t;
  439. if !*fullpoly then !*fullroots := t;
  440. % if !*allpoly = 'all then
  441. % <<on rounded; rdon!* := t; write "test mode"; terpri()>>;
  442. poles := solvesq(simp!* prepf q,var,1);
  443. !*norationalgi := t;
  444. lp: if null poles then go to int;
  445. rt := car poles; poles := cdr poles; m := caddr rt;
  446. rlrt := cmprt := nil;
  447. if (rtv := valueof rt) then
  448. <<poles!* := (rtv . m) . poles!*;
  449. rtvz := zpsubsq rtv; rt := car impartsq rtvz;
  450. if null rt or
  451. (rt := topevalsetsq prepf rt) and evalequal(0,prepsq rt)
  452. then rlrt := rtv else cmprt := rtv;
  453. if llim = 0 then
  454. <<if rlrt then
  455. <<if null car rtvz then go to div
  456. else if not genminusp car rtvz then
  457. <<if m > 1 then go to div else cpv := t;
  458. prlrts := (rlrt . m) . prlrts>>
  459. else nrlrts := (rlrt . m) . nrlrts>>
  460. else cmprts := (cmprt . m) . cmprts; go to lp>>
  461. else
  462. <<if rlrt then
  463. <<if m > 1 then go to div else cpv := t;
  464. rlrts := (rlrt . m) . rlrts>>
  465. else if not genminusp car impartsq rtvz then
  466. cmprts := (cmprt . m) . cmprts>>;
  467. go to lp>>;
  468. una: if !*rounded then rederr "unable to find poles approximately";
  469. if not !*allpoly then <<write
  470. "Denominator degree > 4. Approx integral requires ON ALLPOLY";
  471. terpri(); error(99,"failed")>>
  472. else <<write "approximate integral only"; terpri()>>;
  473. on rounded; rdon!* := t;
  474. if valueof car(rt := rdsolvesq rt) then
  475. <<poles := append(rt,poles); go to lp>>;
  476. go to una;
  477. div: % write "integral diverges"; terpri();
  478. error(99,'failed);
  479. int: if cpv then <<write "Cauchy principal value"; terpri()>>;
  480. return if llim=0 then {prlrts,nrlrts,cmprts}
  481. else {rlrts,nil,cmprts} end;
  482. symbolic procedure specformtestint2(den,num,var,llim,ulim);
  483. % This checks for defint(x^k*R(x),x,0 inf) where {k != 0,-1<k<1} and
  484. % limit+(x^(k+1)*R(x),x,0)=limit(x^(k+1)*R(x),x,inf)=0 where R is
  485. % a rational function with no poles of order >1 on positive real axis.
  486. begin scalar d,k,k1,m,p,p1,q,q1,poles,prpoles,s1,s2;
  487. if not(llim=0) and ulim='inf then go to t2;
  488. p1 := polanalyz(num,var);
  489. k1 := polanalyz(den,var);
  490. if not (p1 or k1) then go to t2;
  491. k := prepsq simp!* aeval {'difference,p1,k1};
  492. if numberp k or not(evalgreaterp(k,-1) and evalgreaterp(1,k))
  493. then go to t2;%<== this was t3 but caused problem!
  494. if (d := dmode!*) then onoff(d := get(d,'dname),nil);
  495. m := prepsq simp!* aeval {'quotient,{'times,var,num},den};
  496. if numr simp!* limit!+(m,var,0)
  497. or numr simp!* limit(m,var,'infinity) then go to t3;
  498. if d then onoff(d,t);
  499. % all tests met, except for finding poles of den.
  500. % move irrational factor to numerator, changing the sign of var.
  501. p := simp!* aeval {'times,num,
  502. {'expt,var,{'times,-1,p1}},{'expt,{'minus,var},k}};
  503. % note that p in general has a non-trivial denominator.
  504. % now remove irrational factor from denominator, leaving polynomial.
  505. q := simp!* aeval {'times,den,{'expt,var,{'times,-1,k1}}};
  506. q1 := diffsq(q,var);
  507. poles := getpoles(numr q,var,llim);
  508. prpoles := car poles; poles := append(cadr poles,caddr poles);
  509. s1 := s2 := nil ./ 1;
  510. k1 := {'times,'pi,{'plus,k,1}};
  511. if poles then
  512. <<for each r in poles do
  513. s1 := addsq(s1,residuum(p,q,q1,var,prepsq car r,cdr r));
  514. s1 := {'quotient,{'times,'pi,prepsq s1},{'sin,k1}}>>
  515. else s1 := 0;
  516. if prpoles then
  517. <<for each r in prpoles do
  518. s2 := addsq(s2,residuum(p,q,q1,var,prepsq car r,cdr r));
  519. s2 := {'times,'pi,prepsq s2,{'cot,k1}}>>
  520. else s2 := 0;
  521. return simp!* aeval {'difference,s1,s2};
  522. t2: return nil; % replace by call to next test.
  523. t3: % write "integral diverges"; terpri();
  524. error(99,'failed) end;
  525. symbolic procedure polanalyz(exp,var);
  526. % test for fractional power of var in exp.
  527. if poltstp exp then
  528. ((if eqcar(
  529. exp := varpwrtst(if eqcar(ex2,'times) then cadr ex2 else ex2,var),
  530. 'quotient) then exp else 0)
  531. where ex2=if eqcar(exp,'minus) then cadr exp else exp);
  532. symbolic procedure poltstp exp;
  533. atom exp and exp or car exp member domainlist!* or
  534. car exp member '(plus times quotient minus expt sqrt) and
  535. begin scalar fg;
  536. for each c in cdr exp do if not poltstp c then fg := t;
  537. return null fg end;
  538. symbolic procedure evalmax(a,b);
  539. if numberp a and numberp b then max(a,b)
  540. else if evalgreaterp(a,b) then a else b;
  541. symbolic procedure evalplus(a,b);
  542. if numberp a and numberp b then a+b
  543. else prepsq simp!* aeval {'plus,a,b};
  544. symbolic procedure varpwrtst(exp,var);
  545. if atom exp then if exp = var then 1 else 0
  546. else if car exp eq 'minus then varpwrtst(cadr exp,var)
  547. else if car exp member '(plus,difference) then
  548. (<<for each c in cdr exp do q := evalmax(q,varpwrtst(c,var)); q>>
  549. where q=0)
  550. else if eqcar(exp,'expt) then
  551. prepsq simp!* aeval{'times,varpwrtst(cadr exp,var),caddr exp}
  552. else if eqcar(exp,'sqrt) then
  553. prepsq simp!* aeval{'times,varpwrtst(cadr exp,var),{'quotient,1,2}}
  554. else if eqcar(exp,'times) then
  555. (<<for each c in cdr exp do q := evalplus(q,varpwrtst(c,var)); q>>
  556. where q=0)
  557. else 0;
  558. endmodule;
  559. end;