simp.red 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391
  1. module simp; % Functions to convert prefix forms into canonical forms.
  2. % Author: Anthony C. Hearn.
  3. % Modifications by: J.H. Davenport, F. Kako, S. Kameny, E. Schruefer and
  4. % Francis J. Wright.
  5. % Copyright (c) 1998, Anthony C. Hearn. All rights reserved.
  6. fluid '(!*allfac !*div);
  7. fluid '(!*asymp!* !*complex !*exp !*gcd !*ifactor !*keepsqrts !*mcd
  8. !*mode !*modular !*notseparate !*numval !*precise !*rationalize
  9. !*reduced !*resimp !*sub2 !*uncached alglist!* dmd!* dmode!*
  10. varstack!* !*combinelogs !*expandexpt !*msg frlis!* subfg!*
  11. !*norationalgi factorbound!* ncmp!* powlis1!* !*nospurp
  12. !*ncmp);
  13. global '(!*match
  14. den!*
  15. % exptl!* No-one else refers to this variable - just slows us
  16. initl!*
  17. mul!*
  18. simpcount!*
  19. simplimit!*
  20. tstack!*
  21. ws);
  22. switch expandexpt; % notseparate;
  23. !*expandexpt := t;
  24. % The NOTSEPARATE switch inhibits an expression such as x^(4/3) to
  25. % become x*x^(1/3). At the present time, no one is using this.
  26. factorbound!* := 10000; % Limit for factoring with IFACTOR off.
  27. % !*KEEPSQRTS uses SQRT rather than EXPT for square roots.
  28. % Normally set TRUE in the integrator, false elsewhere.
  29. put('ifactor,'simpfg,'((t (rmsubs))));
  30. put('alglist!*,'initl,'(cons nil nil));
  31. put('simpcount!*,'initl,0);
  32. initl!* := union('(alglist!* simpcount!*),initl!*);
  33. simplimit!* := 1000;
  34. symbolic procedure noncom u;
  35. % Declare vars u to be noncom.
  36. <<rmsubs(); for each j in u do noncom1 j>>;
  37. symbolic procedure noncom1 u;
  38. <<!*ncmp := t; flag(list u,'noncom)>>;
  39. put('noncom,'stat,'rlis);
  40. symbolic procedure simp!* u;
  41. begin scalar !*asymp!*,x;
  42. if eqcar(u,'!*sq) and caddr u and null !*resimp
  43. then return cadr u;
  44. x := mul!* . !*sub2; % Save current environment.
  45. mul!* := nil;
  46. u:= simp u;
  47. if !*nospurp then mul!* := union(mul!*,'(isimpq));
  48. for each j in mul!* do u:= apply1(j,u);
  49. mul!* := car x;
  50. u := subs2 u;
  51. if !*combinelogs then u := clogsq!* u;
  52. % Must be here, since clogsq!* can upset girationalizesq!:.
  53. % For defint, it is necessary to turn off girationalizesq - SLK.
  54. if dmode!* eq '!:gi!: and not !*norationalgi
  55. then u := girationalize!: u
  56. else if !*rationalize then u := rationalizesq u
  57. else u := rationalizei u;
  58. !*sub2 := cdr x;
  59. % If any leading terms have cancelled, a gcd check is required.
  60. if !*asymp!* and !*rationalize then u := gcdchk u;
  61. return u
  62. end;
  63. symbolic procedure rationalizei u;
  64. % Remove overall factor of i in denominator.
  65. begin scalar v,w;
  66. if domainp (v := denr u) or not smemq('i,v) then return u;
  67. v := reordsq u where kord!* = 'i . kord!*;
  68. return if lpow (w := denr v) = '(i . 1) and null red w
  69. then negf multf(!*k2f 'i,reorder numr v) ./ reorder lc w
  70. else u
  71. end;
  72. symbolic procedure subs2 u;
  73. begin scalar xexp,v,w,x;
  74. if null subfg!* then return u
  75. else if !*sub2 or powlis1!* then u := subs2q u;
  76. u := exptchksq u;
  77. x := get('slash,'opmtch);
  78. if null (!*match or x) or null numr u then return u
  79. else if null !*exp
  80. then <<xexp:= t; !*exp := t; v := u; w := u := resimp u>>;
  81. u := subs3q u;
  82. if xexp then <<!*exp := nil; if u=w then u := v>>;
  83. if x then u := subs4q u;
  84. return u
  85. end;
  86. symbolic procedure simp u;
  87. (begin scalar x,y;
  88. % This case is sufficiently common it is done first.
  89. if fixp u
  90. then if u=0 then return nil ./ 1
  91. else if not dmode!* then return u ./ 1
  92. else nil
  93. else if u member varstack!* then recursiveerror u;
  94. varstack!* := u . varstack!*;
  95. if simpcount!*>simplimit!*
  96. then <<simpcount!* := 0;
  97. rerror(alg,12,"Simplification recursion too deep")>>
  98. else if eqcar(u,'!*sq) and caddr u and null !*resimp
  99. then return cadr u
  100. else if null !*uncached and (x := assoc(u,car alglist!*))
  101. then return <<if cadr x then !*sub2 := t; cddr x>>;
  102. simpcount!* := simpcount!*+1; % undone by returning through !*SSAVE.
  103. if atom u then return !*ssave(simpatom u,u)
  104. else if not idp car u or null car u
  105. then if atom car u then typerr(car u,"operator")
  106. else if idp caar u and (x := get(caar u,'name))
  107. then return !*ssave(u,u) %%% not yet correct
  108. else if eqcar(car u,'mat)
  109. and numlis(x := revlis cdr u) and length x=2
  110. then return !*ssave(simp nth(nth(cdar u,car x),cadr x),u)
  111. else errpri2(u,t)
  112. else if flagp(car u,'opfn)
  113. then if null(y := getrtype(x := opfneval u))
  114. then return !*ssave(simp_without_resimp x,u)
  115. else if y eq 'yetunknowntype and null getrtype(x := reval x)
  116. then return simp x
  117. else typerr(u,"scalar")
  118. else if x := get(car u,'psopfn)
  119. then if getrtype(x := apply1(x,cdr argnochk u))
  120. then typerr(u,"scalar")
  121. else if x=u then return !*ssave(!*k2q x,u)
  122. else return !*ssave(simp_without_resimp x,u)
  123. % Note in above that the psopfn MUST return a *sq form,
  124. % otherwise an infinite recursion occurs.
  125. else if x := get(car u,'polyfn)
  126. then return
  127. <<argnochk u;
  128. !*ssave(!*f2q lispapply(x,
  129. for each j in cdr u collect !*q2f simp!* j),
  130. u)>>
  131. else if get(car u,'opmtch)
  132. and not(get(car u,'simpfn) eq 'simpiden)
  133. and (x := opmtchrevop u)
  134. then return !*ssave(simp x,u)
  135. else if x := get(car u,'simpfn)
  136. then return !*ssave(apply1(x,
  137. if x eq 'simpiden or flagp(car u,'full)
  138. then argnochk u
  139. else cdr argnochk u),
  140. u)
  141. else if (x := get(car u,'rtype)) and (x := get(x,'getelemfn))
  142. then return !*ssave(simp apply1(x,u),u)
  143. else if flagp(car u,'boolean) or get(car u,'infix)
  144. then typerr(if x := get(car u,'prtch) then x else car u,
  145. "algebraic operator")
  146. else if flagp(car u,'nochange)
  147. then return !*ssave(simp lispeval u,u)
  148. else if get(car u,'psopfn) or get(car u,'rtypefn)
  149. then typerr(u,"scalar")
  150. else <<redmsg(car u,"operator");
  151. mkop car u;
  152. varstack!* := delete(u,varstack!*);
  153. return !*ssave(simp u,u)>>;
  154. end) where varstack!* = varstack!*;
  155. symbolic procedure opmtchrevop u;
  156. % The following structure is designed to make index mu; p1.mu^2;
  157. % work. It also introduces a redundant revlis in most cases.
  158. if null !*val or smemq('cons,u) then opmtch u
  159. else opmtch(car u . revlis cdr u);
  160. symbolic procedure simp_without_resimp u;
  161. simp u where !*resimp := nil;
  162. put('array,'getelemfn,'getelv);
  163. put('array,'setelemfn,'setelv);
  164. symbolic procedure getinfix u;
  165. %finds infix symbol for U if it exists;
  166. begin scalar x; return if x := get(u,'prtch) then x else u end;
  167. symbolic procedure !*ssave(u,v);
  168. % We keep !*sub2 as well, since there may be an unsubstituted
  169. % power in U.
  170. begin
  171. if not !*uncached
  172. then rplaca(alglist!*,(v . (!*sub2 . u)) . car alglist!*);
  173. simpcount!* := simpcount!*-1;
  174. return u
  175. end;
  176. symbolic procedure numlis u;
  177. null u or (numberp car u and numlis cdr u);
  178. symbolic procedure simpatom u;
  179. % if null u then typerr("NIL","algebraic identifier")
  180. if null u then nil ./ 1 % Allow NIL as default 0.
  181. else if numberp u
  182. then if u=0 then nil ./ 1
  183. else if not fixp u then ('!:rd!: . cdr fl2bf u) ./ 1
  184. % we assume that a non-fixp number is a float.
  185. else if flagp(dmode!*,'convert) and u neq 1 % Don't convert 1
  186. then !*d2q apply1(get(dmode!*,'i2d),u)
  187. else u ./ 1
  188. else if stringp u then typerr(list("String",u),"identifier")
  189. else if flagp(u,'share) then
  190. <<(if x eq u then mksq(u,1) else simp x) where x=lispeval u>>
  191. else begin scalar z;
  192. if z := get(u,'idvalfn) then return apply1(z,u)
  193. else if !*numval and dmode!* and flagp(u,'constant)
  194. and (z := get(u,dmode!*))
  195. and not errorp(z := errorset!*(list('lispapply,mkquote z,nil),
  196. nil))
  197. then return !*d2q car z
  198. else if getrtype u then typerr(u,'scalar)
  199. else return mksq(u,1) end;
  200. flag('(e pi),'constant);
  201. symbolic procedure mkop u;
  202. begin scalar x;
  203. if null u then typerr("Local variable","operator")
  204. else if (x := gettype u) eq 'operator
  205. then lprim list(u,"already defined as operator")
  206. else if x and not(x memq '(fluid global procedure))
  207. then typerr(u,'operator)
  208. % else if u memq frlis!* then typerr(u,"free variable")
  209. else put(u,'simpfn,'simpiden)
  210. end;
  211. symbolic procedure operatorp u;
  212. gettype u eq 'operator;
  213. symbolic procedure simpcar u;
  214. simp car u;
  215. put('quote,'simpfn,'simpcar);
  216. symbolic procedure share u;
  217. begin scalar y;
  218. for each v in u do
  219. if not idp v then typerr(v,"id")
  220. else if flagp(v,'share) then nil
  221. else if flagp(v,'reserved) then rsverr v
  222. else if (y := getrtype v) and y neq 'list
  223. then rerror(alg,13,list(y,v,"cannot be shared"))
  224. else
  225. % if algebraic value exists, transfer to symbolic.
  226. <<if y then remprop(v,'rtype);
  227. if y := get(v,'avalue)
  228. then <<setifngfl(v,cadr y); remprop(v,'avalue)>>
  229. % if no algebraic value but symbolic value, leave unchanged.
  230. else if not boundp v then setifngfl(v,v);
  231. % if previously unset, set symbolic self pointer.
  232. flag(list v,'share)>>
  233. end;
  234. symbolic procedure boundp u;
  235. % Determines if the id u has a value.
  236. % NB: this function must be redefined in many systems (e.g., CL).
  237. null errorp errorset!*(u,nil);
  238. symbolic procedure setifngfl(v,y);
  239. <<if not globalp v then fluid list v; set(v,y)>>;
  240. rlistat '(share);
  241. flag('(ws !*mode),'share);
  242. flag('(share),'eval);
  243. % ***** SIMPLIFICATION FUNCTIONS FOR EXPLICIT OPERATORS - EXP *****
  244. symbolic procedure simpexpon u;
  245. % Exponents must not use non-integer arithmetic unless NUMVAL is on,
  246. % in which case DOMAINVALCHK must know the mode.
  247. simpexpon1(u,'simp!*);
  248. symbolic procedure simpexpon1(u,v);
  249. if !*numval and (dmode!* eq '!:rd!: or dmode!* eq '!:cr!:)
  250. then apply1(v,u)
  251. else begin scalar dmode!*,alglist!*; return apply1(v,u) end;
  252. symbolic procedure simpexpt u;
  253. % We suppress reordering during exponent evaluation, otherwise
  254. % internal parts (as in e^(a*b)) can have wrong order.
  255. begin scalar expon;
  256. expon := simpexpon carx(cdr u,'expt) where kord!*=nil;
  257. % We still need the right order, else
  258. % explog := {sqrt(e)**(~x*log(~y)/~z) => y**(x/z/2)};
  259. % on ezgcd,gcd; let explog; fails.
  260. expon := simpexpon1(expon,'resimp);
  261. return simpexpt1(car u,expon,nil)
  262. end;
  263. symbolic procedure simpexpt1(u,n,flg);
  264. % FLG indicates whether we have done a PREPSQ SIMP!* U or not: we
  265. % don't want to do it more than once.
  266. begin scalar !*allfac,!*div,m,x,y;
  267. if onep u then return 1 ./ 1;
  268. !*allfac := t;
  269. m := numr n;
  270. if m=1 and denr n=1 then return simp u;
  271. % this simplifies e^(n log x) -> x^n for all n,x.
  272. if u eq 'e and domainp denr n and not domainp m and ldeg m=1
  273. and null red m and eqcar(mvar m,'log) then return
  274. simpexpt1(prepsq!* simp!* cadr mvar m,lc m ./ denr n,nil);
  275. if not domainp m or not domainp denr n
  276. then return simpexpt11(u,n,flg);
  277. x := simp u;
  278. if null m
  279. then return if null numr x then rerror(alg,14,"0**0 formed")
  280. else 1 ./ 1;
  281. % We could use simp!* here, except it messes up the handling of
  282. % gamma matrix expressions.
  283. % if denr x=1 and not domainp numr x and not(denr n=1)
  284. % then <<y := sqfrf numr x;
  285. %% then <<y := fctrf numr x;
  286. %% if car y=1 then y := cdr y
  287. %% else if minusp car y then y := {1};
  288. % if length y>1 then return simpexptfctr(y,n)>>;
  289. return if null numr x
  290. then if domainp m and minusf m
  291. then rerror(alg,15,"Zero divisor")
  292. else nil ./ 1
  293. else if atom m and denr n=1 and domainp numr x
  294. and denr x=1
  295. then if atom numr x and m>0 then !*d2q(numr x**m)
  296. else <<x := !:expt(numr x,m) ./ 1;
  297. %remove rationals where possible.
  298. if !*mcd then resimp x else x>>
  299. else if y := domainvalchk('expt,list(x,n)) then y
  300. else if atom m and denr n=1
  301. then <<if not(m<0) then exptsq(x,m)
  302. else if !*mcd then invsq exptsq(x,-m)
  303. else multf(expf(numr x,m),mksfpf(denr x,-m))
  304. ./ 1>> % This uses OFF EXP option.
  305. % There may be a pattern matching problem though.
  306. % We need the subs2 in the next line to take care of power and
  307. % product simplification left over from the call of simp on u.
  308. else simpexpt11(if flg then u else prepsq!* subs2!* x,n,t)
  309. end;
  310. symbolic procedure simpexptfctr(u,n);
  311. begin scalar x;
  312. x := 1 ./ 1;
  313. for each j in u do
  314. x:= multsq(simpexpt1(prepf car j,multsq(cdr j ./ 1,n),nil),x);
  315. return x
  316. end;
  317. symbolic procedure simpexpt11(u,n,flg);
  318. % Expand exponent to put expression in canonical form.
  319. begin scalar x;
  320. return if domainp denr n
  321. or not(car(x := qremf(numr n,denr n)) and cdr x)
  322. then simpexpt2(u,n,flg)
  323. else multsq(simpexpt1(u,car x ./ 1,flg),
  324. simpexpt1(u,cdr x ./ denr n,flg))
  325. end;
  326. symbolic procedure simpexpt2(u,n,flg);
  327. % The "non-numeric exponent" case. FLG indicates whether we have
  328. % done a PREPSQ SIMP!* U or not: we don't want to do it more than
  329. % once.
  330. begin scalar m,n,x,y;
  331. if u=1 then return 1 ./ 1;
  332. % The following is now handled in mkrootsq.
  333. % else if fixp u and u>0 and (u<factorbound!* or !*ifactor)
  334. % and (length(x := zfactor u)>1 or cdar x>1)
  335. % then <<y := 1 ./ 1;
  336. % for each j in x do
  337. % y := multsq(simpexpt list(car j,
  338. % prepsq multsq(cdr j ./ 1,n)),
  339. % y);
  340. % return y>>;
  341. m:=numr n;
  342. if pairp u then <<
  343. if car u eq 'expt
  344. then <<n:=multsq(m:=simp caddr u,n);
  345. if !*precise
  346. % and numberp numr m and evenp numr m
  347. % and numberp numr n and not evenp numr n
  348. % then u := cadr u % list('abs,cadr u)
  349. then u := list('abs,cadr u)
  350. else u := cadr u;
  351. return simpexpt1(u,n,flg)>>
  352. else if car u eq 'sqrt and not !*keepsqrts
  353. then return simpexpt2(cadr u, multsq(1 ./ 2,n),flg)
  354. % We need the !*precise check for, say, sqrt((1+a)^2*y*z).
  355. else if car u eq 'times and not !*precise
  356. then <<x := 1 ./ 1;
  357. for each z in cdr u do x := multsq(simpexpt1(z,n,flg),x);
  358. return x>>
  359. % For a product under *precise we isolate positive factors.
  360. else if car u eq 'times and (y:=split!-sign cdr u) and car y
  361. then <<x := simpexpt1(retimes append(cadr y,cddr y),n,flg);
  362. for each z in car y do x := multsq(simpexpt1(z,n,flg),x);
  363. return x>>
  364. else if car u eq 'quotient
  365. % The next lines did not allow, e.g., sqrt(a/b) => sqrt(a)/sqrt(b).
  366. % when precise is on and there is a risk of
  367. % E.g., sqrt(a/b) neq sqrt(a)/sqrt(b) when a=1, b=-1.
  368. % We allow however the denominator to be a positive number.
  369. and (not !*precise
  370. % or alg_constant_exptp(cadr u,n)
  371. % or alg_constant_exptp(caddr u,n)
  372. or posnump caddr u and posnump prepsq n
  373. )
  374. then <<if not flg and !*mcd then
  375. return simpexpt1(prepsq simp!* u,n,t);
  376. n := prepsq n;
  377. return quotsq(simpexpt{cadr u,n},simpexpt{caddr u,n})>>
  378. % Special case of (-expression)^(1/2).
  379. % else if car u eq 'minus
  380. % and (n = '(1 . 2) or n = '((!:rd!: . 0.5) . 1)
  381. % or n = '((!:rd!: 5 . -1) . 1)
  382. % or n = '((!:rn!: 1 . 2) . 1))
  383. % then return simptimes list('i,list('expt,cadr u,prepsq n))>>;
  384. % else if car u eq 'minus and numberp m and denr n=1
  385. % then return multsq(simpexpt list(-1,m),
  386. % simpexpt list(cadr u,m))>>;
  387. else if car u eq 'minus and not !*precise and not(cadr u = 1)
  388. then return (multsq(simpexpt list(-1,expon),
  389. simpexpt list(cadr u,expon))) where expon=prepsq n>>;
  390. if null flg
  391. then <<% Don't expand say e and pi, since whole expression is not
  392. % numerical.
  393. if null(dmode!* and idp u and get(u,dmode!*))
  394. then u := prepsq simp!* u;
  395. return simpexpt1(u,n,t)>>
  396. else if numberp u and zerop u then return nil ./ 1
  397. else if not numberp m then m := prepf m;
  398. n := prepf denr n;
  399. if m memq frlis!* and n=1 then return list ((u . m) . 1) . 1;
  400. % "power" is not unique here.
  401. if !*mcd or not numberp m or n neq 1
  402. or atom u or denr simp!* u neq 1 then return simpx1(u,m,n)
  403. else return mksq(u,m) % To make pattern matching work.
  404. end;
  405. symbolic procedure posnump u;
  406. % True if u is a positive number. Test is naive but correct.
  407. if atom u then (numberp u and u>0) or u memq '(e pi)
  408. else if car u memq '(expt plus quotient sqrt times)
  409. then posnumlistp cdr u
  410. else nil;
  411. symbolic procedure posnumlistp u;
  412. null u or posnump car u and posnumlistp cdr u;
  413. % symbolic procedure alg_constant_exptp(u,v);
  414. % % U an expression, v a standard quotient.
  415. % alg_constantp u and alg_constantp car v and alg_constantp cdr v;
  416. % symbolic procedure alg_constantp u;
  417. % % True if u is an algebraic constant whose surd is unique.
  418. % if atom u then numberp u
  419. % else if car u memq
  420. % '(difference expt plus minus quotient sqrt times)
  421. % then alg_constant_listp cdr u
  422. % else nil;
  423. % symbolic procedure alg_constant_listp u;
  424. % null u or alg_constantp car u and alg_constant_listp cdr u;
  425. put('expt,'simpfn,'simpexpt);
  426. symbolic procedure split!-sign u;
  427. % U is a list of factors. Split into positive, negative
  428. % and unknown sign part. Nil if no sign is known.
  429. begin scalar p,n,w,s;
  430. for each f in u do
  431. if 1=(s:=sign!-of f) then p:=f.p else if -1=s then n:=f.n
  432. else w:=f.w;
  433. if null p and null n then return nil;
  434. return p.n.w;
  435. end;
  436. symbolic procedure conv2gid(u,d);
  437. if null u or numberp u or eqcar(u,'!:gi!:) then d
  438. else if domainp u
  439. then if eqcar(u,'!:crn!:) then lcm(d,lcm(cdadr u,cdddr u))
  440. else if eqcar(u,'!:rn!:) then lcm(d,cddr u) else d
  441. else conv2gid(lc u,conv2gid(red u,d));
  442. symbolic procedure conv2gi2 u;
  443. if null u then u
  444. else if numberp u then u * den!*
  445. else if eqcar(u,'!:gi!:) then '!:gi!:.((den!**cadr u).(den!**cddr u))
  446. else if eqcar(u,'!:crn!:)
  447. then <<u := cdr u;
  448. u:= '!:gi!: . ((den!*/cdar u*caar u).(den!*/cddr u*cadr u))>>
  449. else if eqcar(u,'!:rn!:) then den!*/cddr u*cadr u
  450. else if domainp u then rerror(alg,16,list("strange domain",u))
  451. else lpow u .* conv2gi2(lc u) .+ conv2gi2(red u);
  452. symbolic procedure simpx1(u,m,n);
  453. % U,M and N are prefix expressions.
  454. % Value is the standard quotient expression for U**(M/N).
  455. % FLG is true if we have seen a "-" in M.
  456. begin scalar flg,x,z;
  457. % Check for imaginary result.
  458. if eqcar(u,'!*minus!*)
  459. then if m=1 and fixp n and remainder(n,2)=0
  460. or n=1 and eqcar(m,'quotient) and cadr m=1 and fixp caddr m
  461. and remainder(caddr m,2)=0
  462. then return multsq(simp list('expt,'i,
  463. list('quotient,1,n/2)),
  464. simpexpt list(cadr u,list('quotient,m,n)))
  465. % and for negative result.
  466. else if m=1 and fixp n % n must now be odd.
  467. then return negsq
  468. simpexpt list(cadr u,list('quotient,m,n));
  469. if numberp m and numberp n
  470. or null(smemqlp(frlis!*,m) or smemqlp(frlis!*,n))
  471. then go to a;
  472. % exptp!* := t;
  473. return mksq(list('expt,u,if n=1 then m
  474. else list('quotient,m,n)),1);
  475. a:
  476. if numberp m then
  477. if minusp m then <<m := -m; go to mns>>
  478. else if fixp m then
  479. if fixp n then <<
  480. if flg then m := -m;
  481. z := m;
  482. if !*mcd and (fixp u or null !*notseparate)
  483. then <<z := z-n*(m := m/n);
  484. if z<0 then <<m := m-1; z := z+n>>>>
  485. else m := 0;
  486. x := simpexpt list(u,m);
  487. if z=0 then return x
  488. else if n=2 and !*keepsqrts
  489. then <<x := multsq(x,apply1(get('sqrt,'simpfn),
  490. list u));
  491. % z can be 1 or -1. I'm not sure if other
  492. % values can occur.
  493. if z<0 then <<x := invsq x; z := -z>>;
  494. return exptsq(x,z)>>
  495. % Note the indirect call: the integrator rebinds this property.
  496. % JHD understands this interaction - don't change without
  497. % consulting him. Note that, since KEEPSQRTS is true, SIMPSQRT
  498. % won't recurse on SIMPEXPT1.
  499. else return
  500. multsq(x,exptsq(simprad(simp!* u,n),z))>>
  501. else <<z := m; m := 1>>
  502. else z:=1
  503. else if atom m then z:=1
  504. else if car m eq 'minus then <<m := cadr m; go to mns>>
  505. else if car m eq 'plus and !*expandexpt then <<
  506. z := 1 ./ 1;
  507. for each x in cdr m do
  508. z := multsq(simpexpt list(u,
  509. list('quotient,if flg then list('minus,x)
  510. else x,n)),
  511. z);
  512. return z >>
  513. %% else if car m eq 'times and fixp cadr m and numberp n
  514. %% then <<
  515. %% z := gcdn(n,cadr m);
  516. %% n := n/z;
  517. %% z := cadr m/z;
  518. %% m := retimes cddr m >>
  519. %% BEGIN modification by Francis J. Wright:
  520. else if car m eq 'times and fixp cadr m
  521. then <<
  522. if numberp n
  523. then <<z := gcdn(n,cadr m); n := n/z; z := cadr m/z>>
  524. else z := cadr m;
  525. % retimes seems to me to be overkill here, so try just ...
  526. m := if cdddr m then 'times . cddr m else caddr m>>
  527. %% END modification by FJW.
  528. else if car m eq 'quotient and n=1 and !*expandexpt
  529. then <<n := caddr m; m := cadr m; go to a>>
  530. else z := 1;
  531. if idp u and not flagp(u,'used!*) then flag(list u,'used!*);
  532. if u = '(minus 1)
  533. and n=1
  534. and null numr simp list('difference,m,'(quotient 1 2))
  535. then <<u := simp 'i; return if flg then negsq u else u>>;
  536. u := list('expt,u,if n=1 then m else list('quotient,m,n));
  537. return mksq(u,if flg then -z else z); %U is already in lowest terms;
  538. mns: %if numberp m and numberp n and !*rationalizeflag
  539. % then return multsq(simpx1(u,n-m,n),invsq simp u) else
  540. % return invsq simpx1(u,m,n)
  541. if !*mcd then return invsq simpx1(u,m,n);
  542. flg := not flg;
  543. go to a;
  544. end;
  545. symbolic procedure expf(u,n);
  546. %U is a standard form. Value is standard form of U raised to
  547. %negative integer power N. MCD is assumed off;
  548. %what if U is invertable?;
  549. if null u then nil
  550. else if u=1 then u
  551. else if atom u then mkrn(1,u**(-n))
  552. else if domainp u then !:expt(u,n)
  553. else if red u then mksp!*(u,n)
  554. else (lambda x; if x>0 and sfp mvar u
  555. then multf(exptf(mvar u,x),expf(lc u,n))
  556. else mvar u .** x .* expf(lc u,n) .+ nil)
  557. (ldeg u*n);
  558. % ******* The "radical simplifier" section ******
  559. symbolic procedure simprad(u,n);
  560. % Simplifies radical expressions.
  561. if !*reduced then multsq(radfa(numr u,n),invsq radfa(denr u,n))
  562. else begin scalar iflag,x,y,z;
  563. if !*rationalize then << % Move all radicands into numerator.
  564. y:=list(denr u,1); % A partitioned expression.
  565. u:=multf(numr u, exptf(denr u,n-1)) ./ 1 >>
  566. else y := radf(denr u,n);
  567. if n=2 and minusf numr u % Should this be 'evenp n'?
  568. then <<iflag := t; x := radf(negf numr u,n)>>
  569. else x := radf(numr u,n);
  570. z := simp list('quotient,retimes cdr x, retimes cdr y);
  571. if domainp numr z and domainp denr z
  572. % This test allows transformations like sqrt(2/3)=>sqrt(2)/sqrt(3)
  573. % whereas we really don't want to do this for symbolic elements
  574. % since we can introduce paradoxes that way.
  575. then z := multsq(mkrootsq(prepf numr z,n),
  576. invsq mkrootsq(prepf denr z,n))
  577. else <<if iflag
  578. then <<iflag := nil; % Absorb the "i" in square root.
  579. z := negsq z>>;
  580. z := mkrootsq(prepsq z,n)>>;
  581. z := multsq(multsq(if !*precise and evenp n
  582. then car x ./ 1 % mkabsf0 car x
  583. else car x ./ 1, 1 ./ car y), z);
  584. if iflag then z := multsq(z,mkrootsq(-1,2));
  585. return z
  586. end;
  587. symbolic procedure radfa(u,n);
  588. begin scalar x,y;
  589. x := fctrf u;
  590. if numberp car x then x := append(zfactor car x,cdr x)
  591. else x := (car x ./ 1) . cdr x;
  592. y := 1 ./ 1;
  593. for each j in x do y := multsq(y,radfb(car j,cdr j,n));
  594. return y
  595. end;
  596. symbolic procedure radfb(u,m,n);
  597. begin scalar x,y;
  598. x := radf(u,n);
  599. % if !*precise and evenp n then y := mkabsf0 car x ./ 1 else
  600. y := exptf(car x,m) ./ 1;
  601. return multsq(exptsq(mkrootlsq(cdr x,n),m),y)
  602. end;
  603. symbolic procedure mkrootlsq(u,n);
  604. % U is a list of prefix expressions, N an integer.
  605. % Value is standard quotient for U**(1/N);
  606. % NOTE we need the REVAL call so that PREPSQXX is properly called on
  607. % the argument for consistency with the pattern matcher. Otherwise
  608. % for all x,y let sqrt(x)*sqrt(y)=sqrt(x*y); sqrt(30*(l+1))*sqrt 5;
  609. % goes into an infinite loop.
  610. if null u then !*d2q 1
  611. else if null !*reduced then mkrootsq(reval retimes u,n)
  612. else mkrootlsq1(u,n);
  613. symbolic procedure mkrootlsq1(u,n);
  614. if null u then !*d2q 1
  615. else multsq(mkrootsq(car u,n),mkrootlsq1(cdr u,n));
  616. symbolic procedure mkrootsq(u,n);
  617. % U is a prefix expression, N an integer.
  618. % Value is a standard quotient for U**(1/N).
  619. if u=1 then !*d2q 1
  620. else if n=2 and (u= -1 or u= '(minus 1)) then simp 'i
  621. else if eqcar(u,'expt) and fixp caddr u
  622. then exptsq(mkrootsq(cadr u,n),caddr u)
  623. else begin scalar x,y;
  624. if fixp u and not minusp u
  625. and (length(x :=
  626. zfactor1(u,u<factorbound!* or !*ifactor))>1
  627. or cdar x>1)
  628. then return mkrootsql(x,n);
  629. x := if n=2 then mksqrt u
  630. else list('expt,u,list('quotient,1,n));
  631. if y := opmtch x then return simp y
  632. else return mksq(x,1)
  633. end;
  634. symbolic procedure mkrootsql(u,n);
  635. if null u then !*d2q 1
  636. else if cdar u>1
  637. then multsq(exptsq(mkrootsq(caar u,n),cdar u),mkrootsql(cdr u,n))
  638. else multsq(mkrootsq(caar u,n),mkrootsql(cdr u,n));
  639. comment The following four procedures return a partitioned root
  640. expression, which is a dotted pair of integral part (a standard
  641. form) and radical part (a list of prefix expressions). The whole
  642. structure represents U**(1/N);
  643. symbolic procedure check!-radf!-sign(rad,result,n);
  644. % Changes the sign of result if result**n = -rad. rad and result are
  645. % s.f.'s, n is an integer.
  646. (if evenp n and s = -1 or
  647. not evenp n and numberp s and
  648. ((numberp s1 and s neq s1)
  649. where s1 = reval {'sign,mk!*sq !*f2q rad})
  650. then negf result
  651. else result)
  652. where s = reval{'sign,mk!*sq !*f2q result};
  653. symbolic procedure radf(u,n);
  654. % U is a standard form, N a positive integer. Value is a partitioned
  655. % root expression for U**(1/N).
  656. begin scalar ipart,rpart,x,y,z,!*gcd,!*mcd;
  657. if null u then return list u;
  658. !*gcd := !*mcd := t; % mcd cannot be off in this code.
  659. ipart := 1;
  660. z := 1;
  661. while not domainp u do
  662. <<y := comfac u;
  663. if car y
  664. then <<x := divide(pdeg car y,n);
  665. if car x neq 0
  666. then ipart := multf(
  667. if evenp car x
  668. then !*p2f(mvar u .** car x)
  669. % else if !*precise
  670. % then !*p2f mksp(numr
  671. % then exptf(numr
  672. % simp list('abs,if sfp mvar u
  673. % then prepf mvar u
  674. % else mvar u),
  675. else check!-radf!-sign(!*p2f(mvar u .** pdeg car y),
  676. !*p2f(mvar u .** car x),
  677. n),
  678. ipart);
  679. if cdr x neq 0
  680. then rpart := mkexpt(sfchk mvar u,cdr x) . rpart>>;
  681. x := quotf(u,comfac!-to!-poly y); % We need *exp on here.
  682. u := cdr y;
  683. if !*reduced and minusf x
  684. then <<x := negf x; u := negf u>>;
  685. if flagp(dmode!*,'field) then
  686. <<y := lnc x;
  687. if y neq 1 then <<x := quotf(x,y); z := multd(y,z)>>>>;
  688. if x neq 1
  689. then <<x := radf1(sqfrf x,n);
  690. y := car x;
  691. if y neq 1 then
  692. <<%if !*precise and evenp n
  693. % then y := !*kk2f {'abs,prepf y};
  694. ipart := multf(y,ipart)>>;
  695. rpart := append(rpart,cdr x)>>>>;
  696. if u neq 1
  697. then <<x := radd(u,n);
  698. ipart := multf(car x,ipart);
  699. rpart := append(cdr x,rpart)>>;
  700. if z neq 1
  701. then if !*numval
  702. and (y := domainvalchk('expt,
  703. list(!*f2q z,!*f2q !:recip n)))
  704. then ipart := multd(!*q2f y,ipart)
  705. else rpart := prepf z . rpart; % was aconc(rpart,z).
  706. return ipart . rpart
  707. end;
  708. symbolic procedure radf1(u,n);
  709. %U is a form_power list, N a positive integer. Value is a
  710. %partitioned root expression for U**(1/N);
  711. begin scalar ipart,rpart,x;
  712. ipart := 1;
  713. for each z in u do
  714. <<x := divide(cdr z,n);
  715. if not(car x=0)
  716. then ipart := multf(
  717. check!-radf!-sign(!*p2f z,exptf(car z,car x),n),ipart);
  718. if not(cdr x=0)
  719. then rpart := mkexpt(prepsq!*(car z ./ 1),cdr x)
  720. . rpart>>;
  721. return ipart . rpart
  722. end;
  723. symbolic procedure radd(u,n);
  724. %U is a domain element, N an integer.
  725. %Value is a partitioned root expression for U**(1/N);
  726. begin scalar bool,ipart,x;
  727. if not atom u then return list(1,prepf u);
  728. % then if x := integer!-equiv u then u := x
  729. % else return list(1,prepf u);
  730. if u<0 and evenp n then <<bool := t; u := -u>>;
  731. x := nrootnn(u,n);
  732. if bool then if !*reduced and n=2
  733. then <<ipart := multd(car x,!*k2f 'i);
  734. x := cdr x>>
  735. else <<ipart := car x; x := -cdr x>>
  736. else <<ipart := car x; x := cdr x>>;
  737. return if x=1 then list ipart else list(ipart,x)
  738. end;
  739. % symbolic procedure iroot(m,n);
  740. % %M and N are positive integers.
  741. % %If M**(1/N) is an integer, this value is returned, otherwise NIL;
  742. % begin scalar x,x1,bk;
  743. % if m=0 then return m;
  744. % x := 10**iroot!-ceiling(lengthc m,n); %first guess;
  745. % a: x1 := x**(n-1);
  746. % bk := x-m/x1;
  747. % if bk<0 then return nil
  748. % else if bk=0 then return if x1*x=m then x else nil;
  749. % x := x - iroot!-ceiling(bk,n);
  750. % go to a
  751. % end;
  752. symbolic procedure iroot(n,r);
  753. % N, r are integers; r >= 1. If n is an exact rth power then its
  754. % rth root is returned, otherwise NIL.
  755. begin scalar tmp;
  756. tmp := irootn(n,r);
  757. return if tmp**r = n then tmp else nil
  758. end;
  759. symbolic procedure iroot!-ceiling(m,n);
  760. %M and N are positive integers. Value is ceiling of (M/N) (i.e.,
  761. %least integer greater or equal to M/N);
  762. (lambda x; if cdr x=0 then car x else car x+1) divide(m,n);
  763. symbolic procedure mkexpt(u,n);
  764. if n=1 then u else list('expt,u,n);
  765. % The following definition is due to Eberhard Schruefer.
  766. symbolic procedure nrootn(n,x);
  767. % N is an integer, x a positive integer. Value is a pair
  768. % of integers r,s such that r*s**(1/x)=n**(1/x).
  769. begin scalar fl,r,s,m,signn;
  770. r := 1;
  771. s := 1;
  772. if n<0 then <<n := -n; if evenp x then signn := t else r := -1>>;
  773. fl := zfactor n;
  774. for each j in fl do
  775. <<m := divide(cdr j,x);
  776. r := car j**car m*r;
  777. s := car j**cdr m*s>>;
  778. if signn then s := -s;
  779. return r . s
  780. end;
  781. % symbolic procedure nrootn(n,x);
  782. % % N is an integer, X a positive integer. Value is a pair
  783. % % of integers I,J such that I*J**(1/X)=N**(1/X).
  784. % begin scalar i,j,r,signn;
  785. % r := 1;
  786. % if n<0 then <<n := -n; if evenp x then signn := t else r := -1>>;
  787. % j := 2**x;
  788. % while remainder(n,j)=0 do <<n := n/j; r := r*2>>;
  789. % i := 3;
  790. % j := 3**x;
  791. % while j<=n do
  792. % <<while remainder(n,j)=0 do <<n := n/j; r := r*i>>;
  793. % if remainder(i,3)=1 then i := i+4 else i := i+2;
  794. % j := i**x>>;
  795. % if signn then n := -n;
  796. % return r . n
  797. % end;
  798. % ***** simplification functions for other explicit operators *****
  799. symbolic procedure simpiden u;
  800. % Convert the operator expression U to a standard quotient.
  801. % Note: we must use PREPSQXX and not PREPSQ* here, since the REVOP1
  802. % in SUBS3T uses PREPSQXX, and terms must be consistent to prevent a
  803. % loop in the pattern matcher.
  804. begin scalar bool,fn,x,y,z;
  805. fn := car u; u := cdr u;
  806. % Allow prefix ops with names of symbolic functions.
  807. if (get(fn,'!:rn!:) or get(fn,'!:rd!:)) and (x := valuechk(fn,u))
  808. then return x;
  809. % Keep list arguments in *SQ form.
  810. if u and eqcar(car u,'list) and null cdr u
  811. then return mksq(list(fn,aeval car u),1);
  812. x := for each j in u collect aeval j;
  813. u := for each j in x collect
  814. if eqcar(j,'!*sq) then prepsqxx cadr j
  815. else if numberp j then j
  816. else <<bool := t; j>>;
  817. % if u and car u=0 and (flagp(fn,'odd) or flagp(fn,'oddreal))
  818. if u and car u=0 and flagp(fn,'odd)
  819. and not flagp(fn,'nonzero)
  820. then return nil ./ 1;
  821. u := fn . u;
  822. if flagp(fn,'noncom) then ncmp!* := t;
  823. if null subfg!* then go to c
  824. else if flagp(fn,'linear) and (z := formlnr u) neq u
  825. then return simp z
  826. else if z := opmtch u then return simp z;
  827. % else if z := get(car u,'opvalfn) then return apply1(z,u);
  828. % else if null bool and (z := domainvalchk(fn,
  829. % for each j in x collect simp j))
  830. % then return z;
  831. c: if flagp(fn,'symmetric) then u := fn . ordn cdr u
  832. else if flagp(fn,'antisymmetric)
  833. then <<if repeats cdr u then return (nil ./ 1)
  834. else if not permp(z:= ordn cdr u,cdr u) then y := t;
  835. % The following patch was contributed by E. Schruefer.
  836. fn := car u . z;
  837. if z neq cdr u and (z := opmtch fn)
  838. then return if y then negsq simp z else simp z;
  839. u := fn>>;
  840. % if (flagp(fn,'even) or flagp(fn,'odd))
  841. % and x and minusf numr(x := simp car x)
  842. % then <<if flagp(fn,'odd) then y := not y;
  843. % if (flagp(fn,'even) or flagp(fn,'odd) or flagp(fn,'oddreal)
  844. % and x and not_imag_num car x)
  845. if (flagp(fn,'even) or flagp(fn,'odd))
  846. and x and minusf numr(x := simp car x)
  847. then <<if not flagp(fn,'even) then y := not y;
  848. u := fn . prepsqxx negsq x . cddr u;
  849. if z := opmtch u
  850. then return if y then negsq simp z else simp z>>;
  851. u := mksq(u,1);
  852. return if y then negsq u else u
  853. end;
  854. switch rounded;
  855. symbolic procedure not_imag_num a;
  856. % Tests true if a is a number that is not a pure imaginary number.
  857. % Rebinds sqrtfn and *keepsqrts to make integrator happy.
  858. begin scalar !*keepsqrts,!*msg,!*numval,dmode,sqrtfn;
  859. dmode := dmode!*;
  860. !*numval := t;
  861. sqrtfn := get('sqrt,'simpfn);
  862. put('sqrt,'simpfn,'simpsqrt);
  863. on rounded,complex;
  864. a := resimp simp a;
  865. a := numberp denr a and domainp numr a and numr repartsq a;
  866. off rounded,complex;
  867. if dmode then onoff(get(dmode,'dname),t);
  868. put('sqrt,'simpfn,sqrtfn);
  869. return a
  870. end;
  871. flagop even,odd,nonzero;
  872. symbolic procedure domainvalchk(fn,u);
  873. begin scalar x;
  874. if (x := get(dmode!*,'domainvalchk)) then return apply2(x,fn,u);
  875. % The later arguments tend to be smaller ...
  876. u := reverse u;
  877. a: if null u then return valuechk(fn,x)
  878. else if denr car u neq 1 then return nil;
  879. x := mk!*sq car u . x;
  880. u := cdr u;
  881. go to a
  882. end;
  883. symbolic procedure valuechk(fn,u);
  884. begin scalar n;
  885. if (n := get(fn,'number!-of!-args)) and length u neq n
  886. or not n
  887. and u and cdr u and (get(fn,'!:rd!:) or get(fn,'!:rn!:))
  888. then rerror(alg,17,list("Wrong number of arguments to",fn));
  889. u := opfchk!!(fn . u);
  890. if u then return znumrnil
  891. ((if eqcar(u,'list) then list((u . 1) . 1) else u) ./ 1)
  892. end;
  893. symbolic procedure znumrnil u; if znumr u then nil ./ 1 else u;
  894. symbolic procedure znumr u;
  895. null (u := numr u) or numberp u and zerop u
  896. or not atom u and domainp u and
  897. (y and apply1(y,u) where y=get(car u,'zerop));
  898. symbolic procedure opfchk!! u;
  899. begin scalar fn,fn1,sf,sc,int,ce; fn1 := fn := car u; u := cdr u;
  900. % first save fn and check to see whether fn is defined.
  901. % Integer functions are defined in !:rn!:,
  902. % real functions in !:rd!:, and complex functions in !:cr!:.
  903. fn := if flagp(fn,'integer) then <<int := t; get(fn,'!:rn!:)>>
  904. else if !*numval and dmode!* memq '(!:rd!: !:cr!:)
  905. then get(fn,'!:rd!:);
  906. if not fn then return nil;
  907. sf := if int then 'simprn
  908. else if (sf := get(fn,'simparg)) then sf else 'simprd;
  909. % real function fn is defined. now check for complex argument.
  910. if int or not !*complex then go to s; % the simple case.
  911. % mode is complex, so check for complex argument.
  912. % list argument causes a slight complication.
  913. if eqcar(car u,'list)
  914. then if (sc := simpcr revlis cdar u) and eqcar(sc,nil)
  915. then go to err else go to s;
  916. if not (u := simpcr revlis u) then return nil
  917. % if fn1 = 'expt, then evaluate complex function only; else
  918. % if argument is real, evaluate real function, but if error
  919. % occurs, then evaluate complex function.
  920. else if eqcar(u,nil) or
  921. fn1 eq 'expt and rd!:minusp caar u then u := cdr u
  922. else <<ce := cdr u; u := car u; go to s>>;
  923. % argument is complex or real function failed.
  924. % now check whether complex fn is defined.
  925. evc: if fn := get(fn1,'!:cr!:) then go to a;
  926. err: rerror(alg,18,list(fn1,"is not defined as complex function"));
  927. s: if not (u := apply1(sf, revlis u)) then return nil;
  928. a: u := errorset!*(list('apply,mkquote fn,mkquote u),nil);
  929. if errorp u then
  930. if ce then <<u := ce; ce := nil; go to evc>> else return nil
  931. else return if int then intconv car u else car u
  932. end;
  933. symbolic procedure intconv x;
  934. if null dmode!* or dmode!* memq '(!:rd!: !:cr!:) then x
  935. else apply1(get(dmode!*,'i2d),x);
  936. symbolic procedure simpcr x;
  937. % Returns simprd x if all args are real, else nil . "simpcr" x.
  938. if atom x then nil else
  939. <<(<<if not errorp y then z := car y;
  940. y := simplist x where dmode!* = '!:cr!:;
  941. if y then z . y else z>>)
  942. where z=nil,y=errorset!*(list('simprd,mkquote x),nil)>>;
  943. symbolic procedure simprd x;
  944. % Converts any argument list that can be converted to list of rd's.
  945. if atom x then nil else <<simplist x where dmode!* = '!:rd!:>>;
  946. symbolic procedure simplist x;
  947. begin scalar fl,c; c := get(dmode!*,'i2d);
  948. x := for each a in x collect (not fl and
  949. <<if null (a := mconv numr b) then a := 0;
  950. if numberp a then a := apply1(c,a)
  951. else if not(domainp a and eqcar(a,dmode!*)) then fl := t;
  952. if not fl and
  953. (numberp(b := mconv denr b) and (b := apply1(c,b))
  954. or domainp b and eqcar(b,dmode!*))
  955. then apply2(get(dmode!*,'quotient),a,b) else fl := t>>
  956. where b=simp!* a);
  957. if not fl then return x
  958. end;
  959. symbolic procedure mconv v; <<dmconv0 dmode!*; mconv1 v>>;
  960. symbolic procedure dmconv0 dmd;
  961. dmd!* := if null dmd then '!:rn!:
  962. else if dmd eq '!:gi!: then '!:crn!: else dmd;
  963. symbolic procedure dmconv1 v;
  964. if null v or eqcar(v,dmd!*) then v
  965. else if atom v then if flagp(dmd!*,'convert)
  966. then apply1(get(dmd!*,'i2d),v) else v
  967. else if domainp v then apply1(get(car v,dmd!*),v)
  968. else lpow v .* dmconv1(lc v) .+ dmconv1(red v);
  969. symbolic procedure mconv1 v;
  970. if domainp v then drnconv v
  971. else lpow v .* mconv1(lc v) .+ mconv1(red v);
  972. symbolic procedure drnconv v;
  973. if null v or numberp v or eqcar(v,dmd!*) then v else
  974. <<(if y and atom y then apply1(y,v) else v)
  975. where y=get(car v,dmd!*)>>;
  976. % Absolute Value Function.
  977. symbolic procedure simpabs u;
  978. if null u or cdr u then mksq('abs . revlis u, 1) % error?.
  979. else begin scalar x;
  980. u := car u;
  981. if numberp u then return abs u ./ 1
  982. else if x := sign!-abs u then return x;
  983. u := simp!* u;
  984. return if null numr u then nil ./ 1
  985. else quotsq(simpabs1 numr u, simpabs1 denr u);
  986. end;
  987. symbolic procedure simpabs1 u;
  988. % Currently abs(sqrt(2)) does not simplify, whereas it clearly
  989. % should simplify to just sqrt(2). The facts that abs(i) -> 1 and
  990. % abs(sqrt(-2)) -> abs(sqrt(2)) imply that REDUCE regards abs as
  991. % the complex modulus function, in which case I think it is always
  992. % correct to commute abs and sqrt. However, I will do this only if
  993. % the result is a simplification. FJW, 18 July 1998
  994. begin scalar x,y,w;
  995. x:=prepf u; u := u ./ 1;
  996. if eqcar(x,'minus) then x:=cadr x;
  997. % FJW: abs sqrt y -> sqrt abs y if abs y simplifies.
  998. if eqcar(x,'sqrt) then
  999. return !*kk2q if eqcar(y:=reval('abs.cdr x), 'abs)
  1000. then {'abs, x} else {'sqrt, y};
  1001. %% if eqcar(x,'times) and (y:=split!-sign cdr x) then
  1002. %% <<w:=simp!* retimes car y; u:=quotsq(u,w);
  1003. %% if cadr y then
  1004. %% <<y:=simp!* retimes cadr y; u:=quotsq(u,y);
  1005. %% w:=multsq(negsq y,w)>>
  1006. %% >>;
  1007. if eqcar(x,'times) then
  1008. begin scalar abslist, noabs;
  1009. for each fac in cdr x do
  1010. % FJW: abs sqrt y -> sqrt abs y if abs y simplifies.
  1011. if eqcar(fac,'sqrt)
  1012. and not eqcar(y:=reval('abs.cdr fac), 'abs)
  1013. then noabs := {'sqrt, y} . noabs
  1014. else abslist := fac . abslist;
  1015. abslist := reversip abslist;
  1016. if noabs then
  1017. u := quotsq(u, noabs := simp!*('times . reversip noabs));
  1018. if (y:=split!-sign abslist) then
  1019. <<w:=simp!* retimes car y; u:=quotsq(u,w);
  1020. if cadr y then
  1021. <<y:=simp!* retimes cadr y; u:=quotsq(u,y);
  1022. w:=multsq(negsq y,w)>>;
  1023. if noabs then w := multsq(noabs, w)
  1024. >>
  1025. else w := noabs
  1026. end;
  1027. if numr u neq 1 or denr u neq 1 then
  1028. u:=quotsq(mkabsf1 absf numr u,mkabsf1 denr u);
  1029. if w then u:=multsq(w,u);
  1030. return u
  1031. end;
  1032. %symbolic procedure rd!-abs u;
  1033. % % U is a prefix expression. If it represents a constant, return the
  1034. % % abs of u.
  1035. % (if !*rounded or not constant_exprp u then nil
  1036. % else begin scalar x,y,dmode!*;
  1037. % setdmode('rounded,t) where !*msg := nil;
  1038. % x := aeval u;
  1039. % if evalnumberp x
  1040. % then if null !*complex or 0=reval {'impart,x}
  1041. % then y := if evalgreaterp(x,0) then u
  1042. % else if evalequal(x,0) then 0
  1043. % else {'minus,u};
  1044. % setdmode('rounded,nil) where !*msg := nil;
  1045. % return if y then simp y else nil
  1046. % end) where alglist!*=alglist!*;
  1047. symbolic procedure sign!-abs u;
  1048. % Sign based evaluation of abs - includes the above rd!-abs
  1049. % method as sub-branch.
  1050. <<if not numberp n then nil else
  1051. simp if n<0 then {'minus,u} else if n=0 then 0 else u
  1052. >> where n=sign!-of u;
  1053. symbolic procedure constant_exprp u;
  1054. % True if u evaluates to a constant (i.e., number).
  1055. if atom u
  1056. then numberp u or flagp(u,'constant) or u eq 'i and idomainp()
  1057. else (flagp(car u,'realvalued)
  1058. or flagp(car u,'alwaysrealvalued)
  1059. or car u memq '(plus minus difference times quotient)
  1060. or get(car u,'!:rd!:)
  1061. or !*complex and get(car u,'!:cr!:))
  1062. and not atom cdr u
  1063. and constant_expr_listp cdr u;
  1064. symbolic procedure constant_expr_listp u;
  1065. % True if all members of u are constant_exprp.
  1066. % U can be a dotted pair as well as a list.
  1067. if atom u
  1068. then null u or numberp u or flagp(u,'constant)
  1069. or u eq 'i and idomainp()
  1070. else constant_exprp car u and constant_expr_listp cdr u;
  1071. symbolic procedure mkabsf0 u; simp{'abs,mk!*sq !*f2q u};
  1072. symbolic procedure mkabsf1 u;
  1073. if domainp u then mkabsfd u
  1074. else begin scalar x,y,v;
  1075. x := comfac!-to!-poly comfac u;
  1076. u := quotf1(u,x);
  1077. y := split!-comfac!-part x;
  1078. x := cdr y;
  1079. y := car y;
  1080. if positive!-sfp u then <<y := multf(u,y); u := 1>>;
  1081. u := multf(u,x);
  1082. v := lnc y;
  1083. y := quotf1(y,v);
  1084. v := multsq(mkabsfd v,y ./ 1);
  1085. return if u = 1 then v
  1086. else multsq(v,simpiden list('abs,prepf absf u))
  1087. end;
  1088. symbolic procedure mkabsfd u;
  1089. if null get('i,'idvalfn) then absf u ./ 1
  1090. else (simpexpt list(prepsq nrm,'(quotient 1 2))
  1091. where nrm = addsq(multsq(car us,car us),
  1092. multsq(cdr us,cdr us))
  1093. where us = splitcomplex u);
  1094. symbolic procedure positive!-sfp u;
  1095. if domainp u
  1096. then if get('i,'idvalfn)
  1097. then !:zerop impartf u and null !:minusp repartf u
  1098. else null !:minusp u
  1099. else positive!-powp lpow u and positive!-sfp lc u
  1100. and positive!-sfp red u;
  1101. symbolic procedure positive!-powp u;
  1102. not atom car u and caar u memq '(abs norm);
  1103. % symbolic procedure positive!-powp u;
  1104. % % This definition allows for the testing of positive valued vars.
  1105. % if atom car u then flagp(car u, 'positive)
  1106. % else ((if x then apply2(x,car u,cdr u) else nil)
  1107. % where x = get(caar u,'positivepfn));
  1108. symbolic procedure split!-comfac!-part u;
  1109. split!-comfac(u,1,1);
  1110. symbolic procedure split!-comfac(u,v,w);
  1111. if domainp u then multd(u,v) . w
  1112. else if red u then
  1113. if positive!-sfp u then multf(u,v) . w
  1114. else v . multf(u,w)
  1115. else if mvar u eq 'i then split!-comfac(lc u,v,w)
  1116. else if positive!-powp lpow u
  1117. then split!-comfac(lc u,multpf(lpow u,v),w)
  1118. else split!-comfac(lc u,v,multpf(lpow u,w));
  1119. put('abs,'simpfn,'simpabs);
  1120. symbolic procedure simpdiff u;
  1121. <<ckpreci!# u; addsq(simpcar u,simpminus cdr u)>>;
  1122. put('difference,'simpfn,'simpdiff);
  1123. symbolic procedure simpminus u;
  1124. negsq simp carx(u,'minus);
  1125. put('minus,'simpfn,'simpminus);
  1126. symbolic procedure simpplus u;
  1127. begin scalar z;
  1128. if length u=2 then ckpreci!# u;
  1129. z := nil ./ 1;
  1130. a: if null u then return z;
  1131. z := addsq(simpcar u,z);
  1132. u := cdr u;
  1133. go to a
  1134. end;
  1135. put('plus,'simpfn,'simpplus);
  1136. symbolic procedure ckpreci!# u;
  1137. % Screen for complex number input.
  1138. !*complex
  1139. and (if a and not b then ckprec2!#(cdar u,cadr u)
  1140. else if b and not a then ckprec2!#(cdadr u,car u))
  1141. where a=timesip car u,b=timesip cadr u;
  1142. symbolic procedure timesip x; eqcar(x,'times) and 'i memq cdr x;
  1143. symbolic procedure ckprec2!#(im,rl);
  1144. % Strip im and rl to domains.
  1145. <<im := if car im eq 'i then cadr im else car im;
  1146. if eqcar(im,'minus) then im := cadr im;
  1147. if eqcar(rl,'minus) then rl := cadr rl;
  1148. if domainp im and domainp rl and not(atom im and atom rl)
  1149. then ckprec3!#(!?a2bf im,!?a2bf rl)>>;
  1150. remflag('(!?a2bf),'lose); % Until things stabilize.
  1151. symbolic smacro procedure make!:ibf (mt, ep);
  1152. '!:rd!: . (mt . ep);
  1153. symbolic smacro procedure i2bf!: u; make!:ibf (u, 0);
  1154. symbolic procedure !?a2bf a;
  1155. % Convert decimal or integer to bfloat.
  1156. if atom a then if numberp a then i2bf!: a else nil
  1157. else if eqcar(a,'!:dn!:) then a;
  1158. symbolic procedure ckprec3!#(x,y);
  1159. % if inputs are valid, check for precision increase.
  1160. if x and y then
  1161. precmsg max(length explode abs cadr x+cddr x,
  1162. length explode abs cadr y+cddr y);
  1163. symbolic procedure simpquot q;
  1164. (if null numr u
  1165. then if null numr v then rerror(alg,19,"0/0 formed")
  1166. else rerror(alg,20,"Zero divisor")
  1167. else if dmode!* memq '(!:rd!: !:cr!:) and domainp numr u
  1168. and domainp denr u and domainp denr v
  1169. and !:onep denr u and !:onep denr v
  1170. then (if null numr v then nil else divd(numr v,numr u)) ./ 1
  1171. else <<q := multsq(v,simprecip cdr q);
  1172. if !*modular and null denr q
  1173. then rerror(alg,201,"Zero divisor");
  1174. q>>)
  1175. where v=simpcar q,u=simp cadr q;
  1176. put('quotient,'simpfn,'simpquot);
  1177. symbolic procedure simprecip u;
  1178. if null !*mcd then simpexpt list(carx(u,'recip),-1)
  1179. else invsq simp carx(u,'recip);
  1180. put('recip,'simpfn,'simprecip);
  1181. symbolic procedure simpset u;
  1182. begin scalar x;
  1183. x := prepsq simp!* car u;
  1184. if null x % or not idp x
  1185. then typerr(x,"set variable");
  1186. let0 list(list('equal,x,mk!*sq(u := simp!* cadr u)));
  1187. return u
  1188. end;
  1189. put ('set, 'simpfn, 'simpset);
  1190. symbolic procedure simpsqrt u;
  1191. if u=0 then nil ./ 1 else
  1192. if null !*keepsqrts
  1193. then simpexpt1(car u, simpexpon '(quotient 1 2), nil)
  1194. else begin scalar x,y;
  1195. x := xsimp car u;
  1196. return if null numr x then nil ./ 1
  1197. else if denr x=1 and domainp numr x and !:minusp numr x
  1198. then if numr x=-1 then simp 'i
  1199. else multsq(simp 'i,
  1200. simpsqrt list prepd !:minus numr x)
  1201. else if y := domainvalchk('sqrt,list x) then y
  1202. else simprad(x,2)
  1203. end;
  1204. symbolic procedure xsimp u; expchk simp!* u;
  1205. symbolic procedure simptimes u;
  1206. begin scalar x,y;
  1207. if null u then return 1 ./ 1;
  1208. if tstack!* neq 0 or null mul!* then go to a0;
  1209. y := mul!*;
  1210. mul!* := nil;
  1211. a0: tstack!* := tstack!*+1;
  1212. x := simpcar u;
  1213. a: u := cdr u;
  1214. if null numr x then go to c
  1215. else if null u then go to b;
  1216. x := multsq(x,simpcar u);
  1217. go to a;
  1218. b: if null mul!* or tstack!*>1 then go to c;
  1219. x:= apply1(car mul!*,x);
  1220. alglist!* := nil . nil; % since we may need MUL!* set again.
  1221. mul!*:= cdr mul!*;
  1222. go to b;
  1223. c: tstack!* := tstack!*-1;
  1224. if tstack!* = 0 then mul!* := y;
  1225. return x;
  1226. end;
  1227. put('times,'simpfn,'simptimes);
  1228. symbolic procedure resimp u;
  1229. % U is a standard quotient.
  1230. % Value is the resimplified standard quotient.
  1231. resimp1 u where varstack!*=nil;
  1232. symbolic procedure resimp1 u;
  1233. begin
  1234. u := quotsq(subf1(numr u,nil),subf1(denr u,nil));
  1235. !*sub2 := t;
  1236. return u
  1237. end;
  1238. symbolic procedure simp!*sq u;
  1239. if cadr u and null !*resimp then car u else resimp1 car u;
  1240. put('!*sq,'simpfn,'simp!*sq);
  1241. endmodule;
  1242. end;