isolve.red 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. module isolve; % Routines for solving the final reduction equation.
  2. % Author: Mary Ann Moore and Arthur C. Norman.
  3. % Modifications by: John P. Fitch.
  4. fluid '(!*trint
  5. badpart
  6. ccount
  7. cmap
  8. cmatrix
  9. cval
  10. indexlist
  11. lhs!*
  12. lorder
  13. orderofelim
  14. power!-list!*
  15. pt
  16. rhs!*
  17. sillieslist
  18. tanlist
  19. ulist
  20. zlist);
  21. global '(!*number!* !*statistics);
  22. exports solve!-for!-u;
  23. imports nth,findpivot,gcdf,int!-gensym1,mkvect,interr,multdfconst,
  24. !*multf!*,negdf,orddf,plusdf,printdf,printsf,printspreadc,printsq,
  25. quotf,putv,spreadc,subst4eliminatedcs,mknill,pnth,domainp,addf,
  26. invsq,multsq;
  27. symbolic procedure uterm(powu,rhs!*);
  28. % Finds the contribution from RHS!* of reduction equation, of the
  29. % U-coefficient given by POWU. Result is in D.F.
  30. if null rhs!* then nil
  31. else begin scalar coef,power;
  32. power:=addinds(powu,lpow rhs!*);
  33. coef:=evaluatecoeffts(numr lc rhs!*,powu);
  34. if null coef then return uterm(powu,red rhs!*);
  35. coef:=coef ./ denr lc rhs!*;
  36. return plusdf((power .* coef) .+ nil,uterm(powu,red rhs!*))
  37. end;
  38. symbolic procedure solve!-for!-u(rhs!*,lhs!*,ulist);
  39. % Solves the reduction eqn LHS!*=RHS!*. Returns list of U-coeffs
  40. % and their values (ULIST are those we have so far), and a list of
  41. % C-equations to be solved (CLIST are the eqns we have so far).
  42. begin
  43. top:
  44. if null lhs!* then return ulist
  45. else begin scalar u,lpowlhs;
  46. lpowlhs := lpow lhs!*;
  47. begin scalar ll,m1,chge;
  48. ll:=maxorder(power!-list!*,zlist,0);
  49. m1:=lorder;
  50. while m1 do << if car ll < car m1 then
  51. << chge:=t; rplaca(m1,car ll) >>;
  52. ll:=cdr ll; m1:=cdr m1 >>;
  53. if !*trint and chge then <<
  54. princ
  55. "Maximum order for undetermined coefficients is reduced to ";
  56. printc lorder >>
  57. end;
  58. u:=pickupu(rhs!*,lpow lhs!*,t);
  59. if null u then
  60. << if !*trint then <<
  61. printc "***** Equation for a constant to be solved:";
  62. printsf numr lc lhs!*;
  63. printc " = 0";
  64. printc " ">>;
  65. % Remove a zero constant from the lhs, rather than use
  66. % Gauss Elim;
  67. if gausselimn(numr lc lhs!*,lt lhs!*) then <<
  68. lhs!*:=squashconstants(red lhs!*); u := t >>
  69. else lhs!*:=red lhs!* >>
  70. else
  71. << ulist:=(car u .
  72. subs2q multsq(coefdf(lhs!*,lpowlhs),invsq cdr u)).ulist;
  73. % used to be !*multsq. However, i^2 was not handled
  74. % correctly.
  75. if !*statistics then !*number!*:=!*number!*+1;
  76. if !*trint then <<
  77. printc "A coefficient of numerator has been determined";
  78. prin2 "***** U"; prin2 car u; prin2t " =";
  79. printsq multsq(coefdf(lhs!*,lpowlhs),invsq cdr u);
  80. printc " ">>;
  81. lhs!*:=plusdf(lhs!*,
  82. negdf multdfconst(cdar ulist,uterm(car u,rhs!*)))>>;
  83. if !*trint and u
  84. then <<printc "Terms remaining are:"; printdf lhs!*;
  85. printc " ">>
  86. end;
  87. go to top
  88. end;
  89. symbolic procedure squashconstants(express);
  90. begin scalar constlst,ii,xp,cl,subby,cmt,xx;
  91. constlst:=reverse cmap;
  92. cmt:=cmatrix;
  93. xxx: xx:=car cmt; % Look at next row of Cmatrix
  94. cl:=constlst; % and list of the names.
  95. ii:=1; % will become index of removed constant.
  96. while not getv(xx,ii) do
  97. << ii:=ii+1; cl:=cdr cl >>;
  98. subby:=caar cl; %II is now index, and SUBBY the name.
  99. if member(subby,sillieslist) then
  100. <<cmt:=cdr cmt; go to xxx>>; %This loop must terminate.
  101. % This is because at least one constant remains.
  102. xp:=prepsq !*f2q getv(xx,0); % start to build up the answer.
  103. cl:=cdr cl;
  104. if not (ccount=ii) then for jj:=ii+1:ccount do <<
  105. if getv(xx,jj) then
  106. xp:=list('plus,xp,
  107. list('times,caar cl,
  108. prepsq !*f2q getv(xx,jj)));
  109. cl:=cdr cl >>;
  110. xp:=list('quotient,list('minus,xp),
  111. prepsq !*f2q getv(xx,ii));
  112. if !*trint then <<
  113. prin2 "Replace constant "; prin2 subby;
  114. prin2 " by "; printsq simp xp >>;
  115. sillieslist:=subby . sillieslist;
  116. return subdf(express,xp,subby)
  117. end;
  118. symbolic procedure checku(ulst,u);
  119. % Checks that U is not already in ULST - ie. that this u-coeff
  120. % has not already been given a value.
  121. ulst and (car u = caar ulst or checku(cdr ulst,u));
  122. symbolic procedure checku1(powu,rhs!*);
  123. % Checks that use of a particular U-term will not cause trouble
  124. % by introducing negative exponents into lhs when it is used.
  125. begin
  126. top:
  127. if null rhs!* then return nil;
  128. if negind(powu,lpow rhs!*) then
  129. if not null evaluatecoeffts(numr lc rhs!*,powu) then return t;
  130. rhs!*:=red rhs!*;
  131. go to top
  132. end;
  133. symbolic procedure negind(pu,pr);
  134. % Check if substituting index values in power gives rise to -ve
  135. % exponents.
  136. pu and ((car pu+caar pr)<0 or negind(cdr pu,cdr pr));
  137. symbolic procedure evaluatecoeffts(coefft,indlist);
  138. % Substitutes the values of the i,j,k,...'s that appear in the S.F.
  139. % COEFFT (=coefficient of r.h.s. of reduction equation). Result is S.F.
  140. if null coefft or domainp coefft then
  141. if coefft=0 then nil else coefft
  142. else begin scalar temp;
  143. if mvar coefft member indexlist then
  144. temp:=valuecoefft(mvar coefft,indlist,indexlist)
  145. else temp:=!*p2f lpow coefft;
  146. temp:=!*multf(temp,evaluatecoeffts(lc coefft,indlist));
  147. return addf(temp,evaluatecoeffts(red coefft,indlist))
  148. end;
  149. symbolic procedure valuecoefft(var,indvalues,indlist);
  150. % Finds the value of VAR, which should be in INDLIST, given INDVALUES,
  151. % the corresponding values of INDLIST variables.
  152. if null indlist then interr "Valuecoefft - no value"
  153. else if var eq car indlist then
  154. if car indvalues=0 then nil
  155. else car indvalues
  156. else valuecoefft(var,cdr indvalues,cdr indlist);
  157. symbolic procedure addinds(powu,powrhs);
  158. % Adds indices in POWU to those in POWRHS. Result is LPOW of D.F.
  159. if null powu then if null powrhs then nil
  160. else interr "Powrhs too long"
  161. else if null powrhs then interr "Powu too long"
  162. else (car powu + caar powrhs).addinds(cdr powu,cdr powrhs);
  163. symbolic procedure pickupu(rhs!*,powlhs,flg);
  164. % Picks up the 'lowest' U coefficient from RHS!* if it exists and
  165. % returns it in the form of LT of D.F..
  166. % Returns NIL if no legal term in RHS!* can be found.
  167. % POWLHS is the power we want to match (LPOW of D.F).
  168. % and COEFFU is the list of previous coefficients that must be zero.
  169. begin scalar coeffu,u;
  170. pt:=rhs!*;
  171. top:
  172. if null pt then return nil; %no term found - failed.
  173. u:=nextu(lt pt,powlhs); %check this term...
  174. if null u then go to notthisone;
  175. if not testord(car u,lorder) then go to neverthisone;
  176. if not checkcoeffts(coeffu,car u) then go to notthisone;
  177. %that inhibited clobbering things already passed over.
  178. if checku(ulist,u) then go to notthisone;
  179. %that avoided redefining a u value.
  180. if checku1(car u,rhs!*) then go to neverthisone;
  181. %avoid introduction of negative exponents.
  182. if flg then
  183. u:=patchuptan(list u,powlhs,red pt,rhs!*);
  184. return u;
  185. neverthisone:
  186. coeffu:=(lc pt) . coeffu;
  187. notthisone:
  188. pt:=red pt;
  189. go to top
  190. end;
  191. symbolic procedure patchuptan(u,powlhs,rpt,rhs!*);
  192. begin
  193. scalar uu,cc,dd,tanlist,redu,redu1,mesgiven,needsquash;
  194. pt:=rpt;
  195. while pt do <<
  196. if (uu:=pickupu(pt,powlhs,nil))
  197. and testord(car uu,lorder) then <<
  198. % Nasty found, patch it up.
  199. cc:=(int!-gensym1 'c . caar u) . cc;
  200. % CC is an alist of constants.
  201. if !*trint then <<
  202. if not mesgiven then << %% Changed by JPff
  203. prin2t
  204. "*** Introduce new constants for coefficients";
  205. mesgiven := t >>;
  206. prin2 "***** U";
  207. prin2 caar u;
  208. prin2t " =";
  209. print caar cc >>;
  210. redu:=plusdf(redu,
  211. multdfconst(!*k2q caar cc,uterm(caar u,rhs!*)));
  212. u:=uu.u
  213. >>;
  214. if pt then pt:=red pt >>;
  215. redu1:=redu;
  216. while redu1 do begin scalar xx; xx:=car redu1;
  217. if !*trint
  218. then << prin2 "Introduced terms: ";
  219. prin2 car xx; princ "*(";
  220. printsq cdr xx; printc ")">>;
  221. if (not testord(car xx,lorder)) then <<
  222. if !*trint then printc " = 0";
  223. if dd:=killsingles(cadr xx,cc) then <<
  224. redu:=subdf(redu,0,car dd);
  225. redu1:=subdf(redu1,0,car dd);
  226. ulist:=((cdr dd).(nil ./ 1)).ulist;
  227. u:=rmve(u,cdr dd);
  228. cc:=purgeconst(cc,dd) >>
  229. else <<
  230. needsquash := t;
  231. redu1 :=cdr redu1
  232. >>
  233. >>
  234. else redu1:=cdr redu1 end;
  235. for each xx in redu do <<
  236. if (not testord(car xx,lorder)) then <<
  237. while cc do <<
  238. addctomap(caar cc);
  239. ulist:=((cdar cc).(!*k2q caar cc))
  240. . ulist;
  241. if !*statistics
  242. then !*number!*:=!*number!*+1;
  243. cc:=cdr cc >>;
  244. gausselimn(numr lc redu,lt redu)>> >>;
  245. if redu then << while cc do << addctomap(caar cc);
  246. ulist:=((cdar cc).(!*k2q caar cc)).ulist;
  247. if !*statistics then !*number!*:=!*number!*+1;
  248. cc:=cdr cc >>;
  249. lhs!*:=plusdf(lhs!*,negdf redu);
  250. if needsquash then lhs!*:=squashconstants(lhs!*) >>;
  251. return car u
  252. end;
  253. symbolic procedure killsingles(xx,cc);
  254. if atom xx then nil
  255. else if not (cdr xx eq nil) then nil
  256. else begin scalar dd;
  257. dd:=assoc(caaar xx,cc);
  258. if dd then return dd;
  259. return killsingles(cdar xx,cc)
  260. end;
  261. symbolic procedure rmve(l,x);
  262. if caar l=x then cdr l else cons(car l,rmve(cdr l,x));
  263. symbolic procedure subdf(a,b,c);
  264. % Substitute b for c into the df a. Used to get rid of silly constants
  265. % introduced.
  266. if a=nil then nil else
  267. begin scalar x;
  268. x:=subs2q subf(numr lc a,list (c . b)) ;
  269. if x=(nil . 1) then return subdf(red a,b,c)
  270. else return plusdf(
  271. list ((lpow a).((car x).!*multf(cdr x,denr lc a))),
  272. subdf(red a,b,c))
  273. end;
  274. symbolic procedure testord(a,b);
  275. % Test order of two DF's in recursive fashion.
  276. if null a then t
  277. else if car a leq car b then testord(cdr a,cdr b)
  278. else nil;
  279. symbolic procedure tansfrom(rhs,z,indexlist,n);
  280. % We notice that in all bad cases we have (j-num)tan**j...;
  281. % Extract the num to get list of all maxima;
  282. if null z then nil else
  283. begin scalar zz,r, rr, ans;
  284. r:=rhs;
  285. zz := car z;
  286. ans := 0;
  287. if not(atom zz) and car zz = 'tan then
  288. while r do <<
  289. rr:=caar r; % The list of powers;
  290. for i:=1:n do rr:=cdr rr;
  291. if fixp caar rr then
  292. ans := max(ans,tanextract(car indexlist,prepsq cdar r));
  293. r:=cdr r;
  294. >>;
  295. return cons(ans,tansfrom(rhs, cdr z,cdr indexlist,n+1))
  296. end;
  297. symbolic procedure tanextract(var, exp);
  298. % Find the value of the variable which makes the expression vanish.
  299. % The coefficients must be linear.
  300. begin scalar ans, c0, c1;
  301. ans := cdr coeff1(exp,var,nil);
  302. if length ans = 2 and
  303. not(car ans = 0) then <<
  304. c0 := car ans; c1 := cadr ans;
  305. if eqcar(c0,'!*sq) then c0 := cadr c0 else c0 := c0 ./ 1;
  306. if eqcar(c1,'!*sq) then c1 := cadr c1 else c1 := c1 ./ 1;
  307. ans := multsq(c0, invsq c1);
  308. if atom ans then return 0;
  309. if (cdr ans = 1) and fixp (car ans) then return -(car ans);
  310. return 0 >>;
  311. return 0;
  312. end;
  313. symbolic procedure coefdf(y,u);
  314. if y=nil then nil
  315. else if lpow y=u then lc y
  316. else coefdf(red y,u);
  317. symbolic procedure purgeconst(a,b);
  318. % Remove a constant from and expression. May be the same as DELETE?
  319. if null a then nil
  320. else if car a=b then purgeconst(cdr a,b)
  321. else cons(car a,purgeconst(cdr a,b));
  322. symbolic procedure maxorder(minpowers,z,n);
  323. % Find a limit on the order of terms, this is ad hoc;
  324. if null z then nil
  325. else if eqcar(car z,'sqrt) then
  326. cons(1,maxorder(cdr minpowers,cdr z,n+1))
  327. else if (atom car z) or (caar z neq 'tan) then
  328. cons(maxfrom(lhs!*,n)+1,maxorder(cdr minpowers,cdr z,n+1))
  329. else cons(max(car minpowers, maxfrom(lhs!*,n)),
  330. maxorder(cdr minpowers,cdr z,n+1));
  331. symbolic procedure maxfrom(l,n); maxfrom1(l,n+1,0);
  332. symbolic procedure maxfrom1(l,n,v);
  333. % Largest order in the nth variable.
  334. if null l then v
  335. else <<v := max(nth(caar l,n),v); maxfrom1(cdr l,n,v)>>;
  336. symbolic procedure addctomap cc;
  337. begin
  338. scalar ncval;
  339. ccount:=ccount+1;
  340. ncval:=mkvect(ccount);
  341. for i:=0:(ccount-1) do putv(ncval,i,getv(cval,i));
  342. putv(ncval,ccount,nil ./ 1);
  343. cval:=ncval;
  344. cmap:=(cc . ccount).cmap;
  345. if !*trint then << prin2 "Constant map changed to "; print cmap >>;
  346. cmatrix := for each j in cmatrix collect addtovector j
  347. end;
  348. symbolic procedure addtovector v;
  349. begin scalar vv;
  350. vv:=mkvect(ccount);
  351. for i:=0:(ccount-1) do putv(vv,i,getv(v,i));
  352. putv(vv,ccount,nil);
  353. return vv
  354. end;
  355. symbolic procedure checkcoeffts(cl,indv);
  356. % checks to see that the coefficients in CL (coefficient list - S.Q.s)
  357. % are zero when the i,j,k,... are given values in INDV (LPOW of
  358. % D.F.). if so the result is true else NIL=false.
  359. if null cl then t
  360. else begin scalar res;
  361. res:=evaluatecoeffts(numr car cl,indv);
  362. if not(null res or res=0) then return nil
  363. else return checkcoeffts(cdr cl,indv)
  364. end;
  365. symbolic procedure nextu(ltrhs,powlhs);
  366. % picks out the appropriate U coefficients for term: LTRHS to match the
  367. % powers of the z-variables given in POWLHS (= exponent list of D.F.).
  368. % return this coefficient in form LT of D.F. If U coefficient does
  369. % not exist then result is NIL. If it is multiplied by a zero then
  370. % result is NIL.
  371. if null ltrhs then nil
  372. else begin scalar indlist,ucoefft;
  373. indlist:=subtractinds(powlhs,car ltrhs,nil);
  374. if null indlist then return nil;
  375. ucoefft:=evaluatecoeffts(numr cdr ltrhs,indlist);
  376. if null ucoefft or ucoefft=0 then return nil;
  377. return indlist .* (ucoefft ./ denr cdr ltrhs)
  378. end;
  379. symbolic procedure subtractinds(powlhs,l,sofar);
  380. % subtract the indices in list L from those in POWLHS to find
  381. % appropriate values for i,j,k,... when equating coefficients of terms
  382. % on lhs of reduction eqn. SOFAR is the resulting value list we have
  383. % constructed so far. if any i,j,k,... value is -ve then result is NIL.
  384. if null l then reversip sofar
  385. else if ((car powlhs)-(caar l))<0 then nil
  386. else subtractinds(cdr powlhs,cdr l,
  387. ((car powlhs)-(caar l)) . sofar);
  388. symbolic procedure gausselimn(equation,tokill);
  389. % Performs Gaussian elimination on the matrix for the c-equations
  390. % as each c-equation is found. EQUATION is the next one to deal with.
  391. begin scalar newrow,pivot;
  392. if ccount=0 then go to noway; % failure.
  393. newrow:=mkvect(ccount);
  394. spreadc(equation,newrow,1);
  395. subst4eliminatedcs(newrow,reverse orderofelim,reverse cmatrix);
  396. pivot:=findpivot newrow;
  397. if null pivot then go to nopivotfound;
  398. orderofelim:=pivot . orderofelim;
  399. newrow:=makeprim newrow; % remove hcf from new equation.
  400. cmatrix:=newrow . cmatrix;
  401. % if !*trint then printspreadc newrow;
  402. return t;
  403. nopivotfound:
  404. if null getv(newrow,0) then <<
  405. if !*trint then printc "This equation adds no new information";
  406. return nil>>; % equation was 0=0.
  407. noway:
  408. badpart:=tokill . badpart; % non-integrable term.
  409. if !*trint then
  410. <<printc "Inconsistency in equations for constants,";
  411. printc " so non integrable">>;
  412. return nil
  413. end;
  414. symbolic procedure makeprim row;
  415. begin scalar g;
  416. g:=getv(row,0);
  417. for i:=1:ccount do g:=gcdf(g,getv(row,i));
  418. if g neq 1 then
  419. for i:=0:ccount do putv(row,i,quotf(getv(row,i),g));
  420. for i := 0:ccount do
  421. <<g := getv(row,i);
  422. if g and not domainp g
  423. then putv(row,i,numr resimp((rootextractf g) ./ 1))>>;
  424. return row
  425. end;
  426. endmodule;
  427. end;