simp.red 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384
  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. 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
  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. else u := cadr u;
  350. return simpexpt1(u,n,flg)>>
  351. else if car u eq 'sqrt and not !*keepsqrts
  352. then return simpexpt2(cadr u, multsq(1 ./ 2,n),flg)
  353. % We need the !*precise check for, say, sqrt((1+a)^2*y*z).
  354. else if car u eq 'times and not !*precise
  355. then <<x := 1 ./ 1;
  356. for each z in cdr u do x := multsq(simpexpt1(z,n,flg),x);
  357. return x>>
  358. % For a product under *precise we isolate positive factors.
  359. else if car u eq 'times and (y:=split!-sign cdr u) and car y
  360. then <<x := simpexpt1(retimes append(cadr y,cddr y),n,flg);
  361. for each z in car y do x := multsq(simpexpt1(z,n,flg),x);
  362. return x>>
  363. else if car u eq 'quotient
  364. % The next lines did not allow, e.g., sqrt(a/b) => sqrt(a)/sqrt(b).
  365. % when precise is on and there is a risk of
  366. % E.g., sqrt(a/b) neq sqrt(a)/sqrt(b) when a=1, b=-1.
  367. % We allow however the denominator to be a positive number.
  368. and (not !*precise
  369. % or alg_constant_exptp(cadr u,n)
  370. % or alg_constant_exptp(caddr u,n)
  371. or posnump caddr u and posnump prepsq n
  372. )
  373. then <<if not flg and !*mcd then
  374. return simpexpt1(prepsq simp!* u,n,t);
  375. n := prepsq n;
  376. return quotsq(simpexpt{cadr u,n},simpexpt{caddr u,n})>>
  377. % Special case of (-expression)^(1/2).
  378. % else if car u eq 'minus
  379. % and (n = '(1 . 2) or n = '((!:rd!: . 0.5) . 1)
  380. % or n = '((!:rd!: 5 . -1) . 1)
  381. % or n = '((!:rn!: 1 . 2) . 1))
  382. % then return simptimes list('i,list('expt,cadr u,prepsq n))>>;
  383. % else if car u eq 'minus and numberp m and denr n=1
  384. % then return multsq(simpexpt list(-1,m),
  385. % simpexpt list(cadr u,m))>>;
  386. else if car u eq 'minus and not !*precise and not(cadr u = 1)
  387. then return (multsq(simpexpt list(-1,expon),
  388. simpexpt list(cadr u,expon))) where expon=prepsq n>>;
  389. if null flg
  390. then <<% Don't expand say e and pi, since whole expression is not
  391. % numerical.
  392. if null(dmode!* and idp u and get(u,dmode!*))
  393. then u := prepsq simp!* u;
  394. return simpexpt1(u,n,t)>>
  395. else if numberp u and zerop u then return nil ./ 1
  396. else if not numberp m then m := prepf m;
  397. n := prepf denr n;
  398. if m memq frlis!* and n=1 then return list ((u . m) . 1) . 1;
  399. % "power" is not unique here.
  400. if !*mcd or not numberp m or n neq 1
  401. or atom u or denr simp!* u neq 1 then return simpx1(u,m,n)
  402. else return mksq(u,m) % To make pattern matching work.
  403. end;
  404. symbolic procedure posnump u;
  405. % True if u is a positive number. Test is naive but correct.
  406. if atom u then (numberp u and u>0) or u memq '(e pi)
  407. else if car u memq '(expt plus quotient sqrt times)
  408. then posnumlistp cdr u
  409. else nil;
  410. symbolic procedure posnumlistp u;
  411. null u or posnump car u and posnumlistp cdr u;
  412. % symbolic procedure alg_constant_exptp(u,v);
  413. % % U an expression, v a standard quotient.
  414. % alg_constantp u and alg_constantp car v and alg_constantp cdr v;
  415. % symbolic procedure alg_constantp u;
  416. % % True if u is an algebraic constant whose surd is unique.
  417. % if atom u then numberp u
  418. % else if car u memq
  419. % '(difference expt plus minus quotient sqrt times)
  420. % then alg_constant_listp cdr u
  421. % else nil;
  422. % symbolic procedure alg_constant_listp u;
  423. % null u or alg_constantp car u and alg_constant_listp cdr u;
  424. put('expt,'simpfn,'simpexpt);
  425. symbolic procedure split!-sign u;
  426. % U is a list of factors. Split into positive, negative
  427. % and unknown sign part. Nil if no sign is known.
  428. begin scalar p,n,w,s;
  429. for each f in u do
  430. if 1=(s:=sign!-of f) then p:=f.p else if -1=s then n:=f.n
  431. else w:=f.w;
  432. if null p and null n then return nil;
  433. return p.n.w;
  434. end;
  435. symbolic procedure conv2gid(u,d);
  436. if null u or numberp u or eqcar(u,'!:gi!:) then d
  437. else if domainp u
  438. then if eqcar(u,'!:crn!:) then lcm(d,lcm(cdadr u,cdddr u))
  439. else if eqcar(u,'!:rn!:) then lcm(d,cddr u) else d
  440. else conv2gid(lc u,conv2gid(red u,d));
  441. symbolic procedure conv2gi2 u;
  442. if null u then u
  443. else if numberp u then u * den!*
  444. else if eqcar(u,'!:gi!:) then '!:gi!:.((den!**cadr u).(den!**cddr u))
  445. else if eqcar(u,'!:crn!:)
  446. then <<u := cdr u;
  447. u:= '!:gi!: . ((den!*/cdar u*caar u).(den!*/cddr u*cadr u))>>
  448. else if eqcar(u,'!:rn!:) then den!*/cddr u*cadr u
  449. else if domainp u then rerror(alg,16,list("strange domain",u))
  450. else lpow u .* conv2gi2(lc u) .+ conv2gi2(red u);
  451. symbolic procedure simpx1(u,m,n);
  452. % U,M and N are prefix expressions.
  453. % Value is the standard quotient expression for U**(M/N).
  454. % FLG is true if we have seen a "-" in M.
  455. begin scalar flg,x,z;
  456. % Check for imaginary result.
  457. if eqcar(u,'!*minus!*)
  458. then if m=1 and fixp n and remainder(n,2)=0
  459. or n=1 and eqcar(m,'quotient) and cadr m=1 and fixp caddr m
  460. and remainder(caddr m,2)=0
  461. then return multsq(simp list('expt,'i,
  462. list('quotient,1,n/2)),
  463. simpexpt list(cadr u,list('quotient,m,n)))
  464. % and for negative result.
  465. else if m=1 and fixp n % n must now be odd.
  466. then return negsq
  467. simpexpt list(cadr u,list('quotient,m,n));
  468. if numberp m and numberp n
  469. or null(smemqlp(frlis!*,m) or smemqlp(frlis!*,n))
  470. then go to a;
  471. % exptp!* := t;
  472. return mksq(list('expt,u,if n=1 then m
  473. else list('quotient,m,n)),1);
  474. a:
  475. if numberp m then
  476. if minusp m then <<m := -m; go to mns>>
  477. else if fixp m then
  478. if fixp n then <<
  479. if flg then m := -m;
  480. z := m;
  481. if !*mcd and (fixp u or null !*notseparate)
  482. then <<z := z-n*(m := m/n);
  483. if z<0 then <<m := m-1; z := z+n>>>>
  484. else m := 0;
  485. x := simpexpt list(u,m);
  486. if z=0 then return x
  487. else if n=2 and !*keepsqrts
  488. then <<x := multsq(x,apply1(get('sqrt,'simpfn),
  489. list u));
  490. % z can be 1 or -1. I'm not sure if other
  491. % values can occur.
  492. if z<0 then <<x := invsq x; z := -z>>;
  493. return exptsq(x,z)>>
  494. % Note the indirect call: the integrator rebinds this property.
  495. % JHD understands this interaction - don't change without
  496. % consulting him. Note that, since KEEPSQRTS is true, SIMPSQRT
  497. % won't recurse on SIMPEXPT1.
  498. else return
  499. multsq(x,exptsq(simprad(simp!* u,n),z))>>
  500. else <<z := m; m := 1>>
  501. else z:=1
  502. else if atom m then z:=1
  503. else if car m eq 'minus then <<m := cadr m; go to mns>>
  504. else if car m eq 'plus and !*expandexpt then <<
  505. z := 1 ./ 1;
  506. for each x in cdr m do
  507. z := multsq(simpexpt list(u,
  508. list('quotient,if flg then list('minus,x)
  509. else x,n)),
  510. z);
  511. return z >>
  512. %% else if car m eq 'times and fixp cadr m and numberp n
  513. %% then <<
  514. %% z := gcdn(n,cadr m);
  515. %% n := n/z;
  516. %% z := cadr m/z;
  517. %% m := retimes cddr m >>
  518. %% BEGIN modification by Francis J. Wright:
  519. else if car m eq 'times and fixp cadr m
  520. then <<
  521. if numberp n
  522. then <<z := gcdn(n,cadr m); n := n/z; z := cadr m/z>>
  523. else z := cadr m;
  524. % retimes seems to me to be overkill here, so try just ...
  525. m := if cdddr m then 'times . cddr m else caddr m>>
  526. %% END modification by FJW.
  527. else if car m eq 'quotient and n=1 and !*expandexpt
  528. then <<n := caddr m; m := cadr m; go to a>>
  529. else z := 1;
  530. if idp u and not flagp(u,'used!*) then flag(list u,'used!*);
  531. if u = '(minus 1)
  532. and n=1
  533. and null numr simp list('difference,m,'(quotient 1 2))
  534. then <<u := simp 'i; return if flg then negsq u else u>>;
  535. u := list('expt,u,if n=1 then m else list('quotient,m,n));
  536. return mksq(u,if flg then -z else z); %U is already in lowest terms;
  537. mns: %if numberp m and numberp n and !*rationalizeflag
  538. % then return multsq(simpx1(u,n-m,n),invsq simp u) else
  539. % return invsq simpx1(u,m,n)
  540. if !*mcd then return invsq simpx1(u,m,n);
  541. flg := not flg;
  542. go to a;
  543. end;
  544. symbolic procedure expf(u,n);
  545. %U is a standard form. Value is standard form of U raised to
  546. %negative integer power N. MCD is assumed off;
  547. %what if U is invertable?;
  548. if null u then nil
  549. else if u=1 then u
  550. else if atom u then mkrn(1,u**(-n))
  551. else if domainp u then !:expt(u,n)
  552. else if red u then mksp!*(u,n)
  553. else (lambda x; if x>0 and sfp mvar u
  554. then multf(exptf(mvar u,x),expf(lc u,n))
  555. else mvar u .** x .* expf(lc u,n) .+ nil)
  556. (ldeg u*n);
  557. % ******* The "radical simplifier" section ******
  558. symbolic procedure simprad(u,n);
  559. % Simplifies radical expressions.
  560. begin scalar iflag,x,y,z;
  561. if !*reduced then <<
  562. % it is legitimate to treat NUM and DEN separately.
  563. x := radf(numr u,n);
  564. y := radf(denr u,n);
  565. z := multsq(if !*precise and evenp n
  566. then car x ./ 1 % mkabsf0 car x
  567. else car x ./ 1,1 ./ car y);
  568. z := multsq(multsq(mkrootlsq(cdr x,n),invsq mkrootlsq(cdr y,n)),
  569. z);
  570. return z >>
  571. else <<
  572. if !*rationalize then << % Move all radicands into numerator.
  573. y:=list(denr u,1); % A partitioned expression.
  574. u:=multf(numr u, exptf(denr u,n-1)) ./ 1 >>
  575. else y := radf(denr u,n);
  576. if 2 = n and minusf numr u then << % Should this be 'evenp n'?
  577. iflag := t;
  578. x := radf(negf numr u,n) >>
  579. else x := radf(numr u,n);
  580. z := simp list('quotient,retimes cdr x, retimes cdr y);
  581. if domainp numr z and domainp denr z
  582. % This test allows transformations like sqrt(2/3)=>sqrt(2)/sqrt(3)
  583. % whereas we really don't want to do this for symbolic elements
  584. % since we can introduce paradoxes that way.
  585. then z := multsq(mkrootsq(prepf numr z,n),
  586. invsq mkrootsq(prepf denr z,n))
  587. else <<
  588. if iflag then <<
  589. iflag := nil; % We must absorb the "i" in square root.
  590. z := negsq z >>;
  591. z := mkrootsq(prepsq z,n) >>;
  592. z := multsq(multsq(if !*precise and evenp n
  593. then car x ./ 1 % mkabsf0 car x
  594. else car x ./ 1, 1 ./ car y), z);
  595. if iflag then z := multsq(z,mkrootsq(-1,2));
  596. return z >>
  597. end;
  598. symbolic procedure mkrootlsq(u,n);
  599. % U is a list of prefix expressions, N an integer.
  600. % Value is standard quotient for U**(1/N);
  601. % NOTE we need the REVAL call so that PREPSQXX is properly called on
  602. % the argument for consistency with the pattern matcher. Otherwise
  603. % for all x,y let sqrt(x)*sqrt(y)=sqrt(x*y); sqrt(30*(l+1))*sqrt 5;
  604. % goes into an infinite loop.
  605. if null u then !*d2q 1
  606. else if null !*reduced then mkrootsq(reval retimes u,n)
  607. else mkrootlsq1(u,n);
  608. symbolic procedure mkrootlsq1(u,n);
  609. if null u then !*d2q 1
  610. else multsq(mkrootsq(car u,n),mkrootlsq1(cdr u,n));
  611. symbolic procedure mkrootsq(u,n);
  612. % U is a prefix expression, N an integer.
  613. % Value is a standard quotient for U**(1/N).
  614. if u=1 then !*d2q 1
  615. else if n=2 and (u= -1 or u= '(minus 1)) then simp 'i
  616. else if eqcar(u,'expt) and fixp caddr u
  617. then exptsq(mkrootsq(cadr u,n),caddr u)
  618. else begin scalar x,y;
  619. if fixp u and not minusp u
  620. and (length(x :=
  621. zfactor1(u,u<factorbound!* or !*ifactor))>1
  622. or cdar x>1)
  623. then return mkrootsql(x,n);
  624. x := if n=2 then mksqrt u
  625. else list('expt,u,list('quotient,1,n));
  626. if y := opmtch x then return simp y
  627. else return mksq(x,1)
  628. end;
  629. symbolic procedure mkrootsql(u,n);
  630. if null u then !*d2q 1
  631. else if cdar u>1
  632. then multsq(exptsq(mkrootsq(caar u,n),cdar u),mkrootsql(cdr u,n))
  633. else multsq(mkrootsq(caar u,n),mkrootsql(cdr u,n));
  634. comment The following four procedures return a partitioned root
  635. expression, which is a dotted pair of integral part (a standard
  636. form) and radical part (a list of prefix expressions). The whole
  637. structure represents U**(1/N);
  638. symbolic procedure check!-radf!-sign(rad,result,n);
  639. % Changes the sign of result if result**n = -rad. rad and result are
  640. % s.f.'s, n is an integer.
  641. (if evenp n and s = -1 or
  642. not evenp n and numberp s and
  643. ((numberp s1 and s neq s1)
  644. where s1 = reval {'sign,mk!*sq !*f2q rad})
  645. then negf result
  646. else result)
  647. where s = reval{'sign,mk!*sq !*f2q result};
  648. symbolic procedure radf(u,n);
  649. % U is a standard form, N a positive integer. Value is a partitioned
  650. % root expression for U**(1/N).
  651. begin scalar ipart,rpart,x,y,z,!*gcd,!*mcd;
  652. if null u then return list u;
  653. !*gcd := !*mcd := t; % mcd cannot be off in this code.
  654. ipart := 1;
  655. z := 1;
  656. while not domainp u do
  657. <<y := comfac u;
  658. if car y
  659. then <<x := divide(pdeg car y,n);
  660. if car x neq 0
  661. then ipart := multf(
  662. if evenp car x
  663. then !*p2f(mvar u .** car x)
  664. % else if !*precise
  665. % then !*p2f mksp(numr
  666. % then exptf(numr
  667. % simp list('abs,if sfp mvar u
  668. % then prepf mvar u
  669. % else mvar u),
  670. else check!-radf!-sign(!*p2f(mvar u .** pdeg car y),
  671. !*p2f(mvar u .** car x),
  672. n),
  673. ipart);
  674. if cdr x neq 0
  675. then rpart := mkexpt(sfchk mvar u,cdr x) . rpart>>;
  676. x := quotf(u,comfac!-to!-poly y); % We need *exp on here.
  677. u := cdr y;
  678. if !*reduced and minusf x
  679. then <<x := negf x; u := negf u>>;
  680. if flagp(dmode!*,'field) then
  681. <<y := lnc x;
  682. if y neq 1 then <<x := quotf(x,y); z := multd(y,z)>>>>;
  683. if x neq 1
  684. then <<x := radf1(sqfrf x,n);
  685. y := car x;
  686. if y neq 1 then
  687. <<%if !*precise and evenp n
  688. % then y := !*kk2f {'abs,prepf y};
  689. ipart := multf(y,ipart)>>;
  690. rpart := append(rpart,cdr x)>>>>;
  691. if u neq 1
  692. then <<x := radd(u,n);
  693. ipart := multf(car x,ipart);
  694. rpart := append(cdr x,rpart)>>;
  695. if z neq 1
  696. then if !*numval
  697. and (y := domainvalchk('expt,
  698. list(!*f2q z,!*f2q !:recip n)))
  699. then ipart := multd(!*q2f y,ipart)
  700. else rpart := prepf z . rpart; % was aconc(rpart,z).
  701. return ipart . rpart
  702. end;
  703. symbolic procedure radf1(u,n);
  704. %U is a form_power list, N a positive integer. Value is a
  705. %partitioned root expression for U**(1/N);
  706. begin scalar ipart,rpart,x;
  707. ipart := 1;
  708. for each z in u do
  709. <<x := divide(cdr z,n);
  710. if not(car x=0)
  711. then ipart := multf(
  712. check!-radf!-sign(!*p2f z,exptf(car z,car x),n),ipart);
  713. if not(cdr x=0)
  714. then rpart := mkexpt(prepsq!*(car z ./ 1),cdr x)
  715. . rpart>>;
  716. return ipart . rpart
  717. end;
  718. symbolic procedure radd(u,n);
  719. %U is a domain element, N an integer.
  720. %Value is a partitioned root expression for U**(1/N);
  721. begin scalar bool,ipart,x;
  722. if not atom u then return list(1,prepf u);
  723. % then if x := integer!-equiv u then u := x
  724. % else return list(1,prepf u);
  725. if u<0 and evenp n then <<bool := t; u := -u>>;
  726. x := nrootnn(u,n);
  727. if bool then if !*reduced and n=2
  728. then <<ipart := multd(car x,!*k2f 'i);
  729. x := cdr x>>
  730. else <<ipart := car x; x := -cdr x>>
  731. else <<ipart := car x; x := cdr x>>;
  732. return if x=1 then list ipart else list(ipart,x)
  733. end;
  734. % symbolic procedure iroot(m,n);
  735. % %M and N are positive integers.
  736. % %If M**(1/N) is an integer, this value is returned, otherwise NIL;
  737. % begin scalar x,x1,bk;
  738. % if m=0 then return m;
  739. % x := 10**iroot!-ceiling(lengthc m,n); %first guess;
  740. % a: x1 := x**(n-1);
  741. % bk := x-m/x1;
  742. % if bk<0 then return nil
  743. % else if bk=0 then return if x1*x=m then x else nil;
  744. % x := x - iroot!-ceiling(bk,n);
  745. % go to a
  746. % end;
  747. symbolic procedure iroot(n,r);
  748. % N, r are integers; r >= 1. If n is an exact rth power then its
  749. % rth root is returned, otherwise NIL.
  750. begin scalar tmp;
  751. tmp := irootn(n,r);
  752. return if tmp**r = n then tmp else nil
  753. end;
  754. symbolic procedure iroot!-ceiling(m,n);
  755. %M and N are positive integers. Value is ceiling of (M/N) (i.e.,
  756. %least integer greater or equal to M/N);
  757. (lambda x; if cdr x=0 then car x else car x+1) divide(m,n);
  758. symbolic procedure mkexpt(u,n);
  759. if n=1 then u else list('expt,u,n);
  760. % The following definition is due to Eberhard Schruefer.
  761. symbolic procedure nrootn(n,x);
  762. % N is an integer, x a positive integer. Value is a pair
  763. % of integers r,s such that r*s**(1/x)=n**(1/x).
  764. begin scalar fl,r,s,m,signn;
  765. r := 1;
  766. s := 1;
  767. if n<0 then <<n := -n; if evenp x then signn := t else r := -1>>;
  768. fl := zfactor n;
  769. for each j in fl do
  770. <<m := divide(cdr j,x);
  771. r := car j**car m*r;
  772. s := car j**cdr m*s>>;
  773. if signn then s := -s;
  774. return r . s
  775. end;
  776. % symbolic procedure nrootn(n,x);
  777. % % N is an integer, X a positive integer. Value is a pair
  778. % % of integers I,J such that I*J**(1/X)=N**(1/X).
  779. % begin scalar i,j,r,signn;
  780. % r := 1;
  781. % if n<0 then <<n := -n; if evenp x then signn := t else r := -1>>;
  782. % j := 2**x;
  783. % while remainder(n,j)=0 do <<n := n/j; r := r*2>>;
  784. % i := 3;
  785. % j := 3**x;
  786. % while j<=n do
  787. % <<while remainder(n,j)=0 do <<n := n/j; r := r*i>>;
  788. % if remainder(i,3)=1 then i := i+4 else i := i+2;
  789. % j := i**x>>;
  790. % if signn then n := -n;
  791. % return r . n
  792. % end;
  793. % ***** simplification functions for other explicit operators *****
  794. symbolic procedure simpiden u;
  795. % Convert the operator expression U to a standard quotient.
  796. % Note: we must use PREPSQXX and not PREPSQ* here, since the REVOP1
  797. % in SUBS3T uses PREPSQXX, and terms must be consistent to prevent a
  798. % loop in the pattern matcher.
  799. begin scalar bool,fn,x,y,z;
  800. fn := car u; u := cdr u;
  801. % Allow prefix ops with names of symbolic functions.
  802. if (get(fn,'!:rn!:) or get(fn,'!:rd!:)) and (x := valuechk(fn,u))
  803. then return x;
  804. % Keep list arguments in *SQ form.
  805. if u and eqcar(car u,'list) and null cdr u
  806. then return mksq(list(fn,aeval car u),1);
  807. x := for each j in u collect aeval j;
  808. u := for each j in x collect
  809. if eqcar(j,'!*sq) then prepsqxx cadr j
  810. else if numberp j then j
  811. else <<bool := t; j>>;
  812. % if u and car u=0 and (flagp(fn,'odd) or flagp(fn,'oddreal))
  813. if u and car u=0 and flagp(fn,'odd)
  814. and not flagp(fn,'nonzero)
  815. then return nil ./ 1;
  816. u := fn . u;
  817. if flagp(fn,'noncom) then ncmp!* := t;
  818. if null subfg!* then go to c
  819. else if flagp(fn,'linear) and (z := formlnr u) neq u
  820. then return simp z
  821. else if z := opmtch u then return simp z;
  822. % else if z := get(car u,'opvalfn) then return apply1(z,u);
  823. % else if null bool and (z := domainvalchk(fn,
  824. % for each j in x collect simp j))
  825. % then return z;
  826. c: if flagp(fn,'symmetric) then u := fn . ordn cdr u
  827. else if flagp(fn,'antisymmetric)
  828. then <<if repeats cdr u then return (nil ./ 1)
  829. else if not permp(z:= ordn cdr u,cdr u) then y := t;
  830. % The following patch was contributed by E. Schruefer.
  831. fn := car u . z;
  832. if z neq cdr u and (z := opmtch fn)
  833. then return if y then negsq simp z else simp z;
  834. u := fn>>;
  835. % if (flagp(fn,'even) or flagp(fn,'odd))
  836. % and x and minusf numr(x := simp car x)
  837. % then <<if flagp(fn,'odd) then y := not y;
  838. % if (flagp(fn,'even) or flagp(fn,'odd) or flagp(fn,'oddreal)
  839. % and x and not_imag_num car x)
  840. if (flagp(fn,'even) or flagp(fn,'odd))
  841. and x and minusf numr(x := simp car x)
  842. then <<if not flagp(fn,'even) then y := not y;
  843. u := fn . prepsqxx negsq x . cddr u;
  844. if z := opmtch u
  845. then return if y then negsq simp z else simp z>>;
  846. u := mksq(u,1);
  847. return if y then negsq u else u
  848. end;
  849. switch rounded;
  850. symbolic procedure not_imag_num a;
  851. % Tests true if a is a number that is not a pure imaginary number.
  852. % Rebinds sqrtfn and *keepsqrts to make integrator happy.
  853. begin scalar !*keepsqrts,!*msg,!*numval,dmode,sqrtfn;
  854. dmode := dmode!*;
  855. !*numval := t;
  856. sqrtfn := get('sqrt,'simpfn);
  857. put('sqrt,'simpfn,'simpsqrt);
  858. on rounded,complex;
  859. a := resimp simp a;
  860. a := numberp denr a and domainp numr a and numr repartsq a;
  861. off rounded,complex;
  862. if dmode then onoff(get(dmode,'dname),t);
  863. put('sqrt,'simpfn,sqrtfn);
  864. return a
  865. end;
  866. flagop even,odd,nonzero;
  867. symbolic procedure domainvalchk(fn,u);
  868. begin scalar x;
  869. if (x := get(dmode!*,'domainvalchk)) then return apply2(x,fn,u);
  870. % The later arguments tend to be smaller ...
  871. u := reverse u;
  872. a: if null u then return valuechk(fn,x)
  873. else if denr car u neq 1 then return nil;
  874. x := mk!*sq car u . x;
  875. u := cdr u;
  876. go to a
  877. end;
  878. symbolic procedure valuechk(fn,u);
  879. begin scalar n;
  880. if (n := get(fn,'number!-of!-args)) and length u neq n
  881. or not n
  882. and u and cdr u and (get(fn,'!:rd!:) or get(fn,'!:rn!:))
  883. then rerror(alg,17,list("Wrong number of arguments to",fn));
  884. u := opfchk!!(fn . u);
  885. if u then return znumrnil
  886. ((if eqcar(u,'list) then list((u . 1) . 1) else u) ./ 1)
  887. end;
  888. symbolic procedure znumrnil u; if znumr u then nil ./ 1 else u;
  889. symbolic procedure znumr u;
  890. null (u := numr u) or numberp u and zerop u
  891. or not atom u and domainp u and
  892. (y and apply1(y,u) where y=get(car u,'zerop));
  893. symbolic procedure opfchk!! u;
  894. begin scalar fn,fn1,sf,sc,int,ce; fn1 := fn := car u; u := cdr u;
  895. % first save fn and check to see whether fn is defined.
  896. % Integer functions are defined in !:rn!:,
  897. % real functions in !:rd!:, and complex functions in !:cr!:.
  898. fn := if flagp(fn,'integer) then <<int := t; get(fn,'!:rn!:)>>
  899. else if !*numval and dmode!* memq '(!:rd!: !:cr!:)
  900. then get(fn,'!:rd!:);
  901. if not fn then return nil;
  902. sf := if int then 'simprn
  903. else if (sf := get(fn,'simparg)) then sf else 'simprd;
  904. % real function fn is defined. now check for complex argument.
  905. if int or not !*complex then go to s; % the simple case.
  906. % mode is complex, so check for complex argument.
  907. % list argument causes a slight complication.
  908. if eqcar(car u,'list)
  909. then if (sc := simpcr revlis cdar u) and eqcar(sc,nil)
  910. then go to err else go to s;
  911. if not (u := simpcr revlis u) then return nil
  912. % if fn1 = 'expt, then evaluate complex function only; else
  913. % if argument is real, evaluate real function, but if error
  914. % occurs, then evaluate complex function.
  915. else if eqcar(u,nil) or
  916. fn1 eq 'expt and rd!:minusp caar u then u := cdr u
  917. else <<ce := cdr u; u := car u; go to s>>;
  918. % argument is complex or real function failed.
  919. % now check whether complex fn is defined.
  920. evc: if fn := get(fn1,'!:cr!:) then go to a;
  921. err: rerror(alg,18,list(fn1,"is not defined as complex function"));
  922. s: if not (u := apply1(sf, revlis u)) then return nil;
  923. a: u := errorset!*(list('apply,mkquote fn,mkquote u),nil);
  924. if errorp u then
  925. if ce then <<u := ce; ce := nil; go to evc>> else return nil
  926. else return if int then intconv car u else car u
  927. end;
  928. symbolic procedure intconv x;
  929. if null dmode!* or dmode!* memq '(!:rd!: !:cr!:) then x
  930. else apply1(get(dmode!*,'i2d),x);
  931. symbolic procedure simpcr x;
  932. % Returns simprd x if all args are real, else nil . "simpcr" x.
  933. if atom x then nil else
  934. <<(<<if not errorp y then z := car y;
  935. y := simplist x where dmode!* = '!:cr!:;
  936. if y then z . y else z>>)
  937. where z=nil,y=errorset!*(list('simprd,mkquote x),nil)>>;
  938. symbolic procedure simprd x;
  939. % Converts any argument list that can be converted to list of rd's.
  940. if atom x then nil else <<simplist x where dmode!* = '!:rd!:>>;
  941. symbolic procedure simplist x;
  942. begin scalar fl,c; c := get(dmode!*,'i2d);
  943. x := for each a in x collect (not fl and
  944. <<if null (a := mconv numr b) then a := 0;
  945. if numberp a then a := apply1(c,a)
  946. else if not(domainp a and eqcar(a,dmode!*)) then fl := t;
  947. if not fl and
  948. (numberp(b := mconv denr b) and (b := apply1(c,b))
  949. or domainp b and eqcar(b,dmode!*))
  950. then apply2(get(dmode!*,'quotient),a,b) else fl := t>>
  951. where b=simp!* a);
  952. if not fl then return x
  953. end;
  954. symbolic procedure mconv v; <<dmconv0 dmode!*; mconv1 v>>;
  955. symbolic procedure dmconv0 dmd;
  956. dmd!* := if null dmd then '!:rn!:
  957. else if dmd eq '!:gi!: then '!:crn!: else dmd;
  958. symbolic procedure dmconv1 v;
  959. if null v or eqcar(v,dmd!*) then v
  960. else if atom v then if flagp(dmd!*,'convert)
  961. then apply1(get(dmd!*,'i2d),v) else v
  962. else if domainp v then apply1(get(car v,dmd!*),v)
  963. else lpow v .* dmconv1(lc v) .+ dmconv1(red v);
  964. symbolic procedure mconv1 v;
  965. if domainp v then drnconv v
  966. else lpow v .* mconv1(lc v) .+ mconv1(red v);
  967. symbolic procedure drnconv v;
  968. if null v or numberp v or eqcar(v,dmd!*) then v else
  969. <<(if y and atom y then apply1(y,v) else v)
  970. where y=get(car v,dmd!*)>>;
  971. % Absolute Value Function.
  972. symbolic procedure simpabs u;
  973. if null u or cdr u then mksq('abs . revlis u, 1) % error?.
  974. else begin scalar x;
  975. u := car u;
  976. if numberp u then return abs u ./ 1
  977. else if x := sign!-abs u then return x;
  978. u := simp!* u;
  979. return if null numr u then nil ./ 1
  980. else quotsq(simpabs1 numr u, simpabs1 denr u);
  981. end;
  982. symbolic procedure simpabs1 u;
  983. % Currently abs(sqrt(2)) does not simplify, whereas it clearly
  984. % should simplify to just sqrt(2). The facts that abs(i) -> 1 and
  985. % abs(sqrt(-2)) -> abs(sqrt(2)) imply that REDUCE regards abs as
  986. % the complex modulus function, in which case I think it is always
  987. % correct to commute abs and sqrt. However, I will do this only if
  988. % the result is a simplification. FJW, 18 July 1998
  989. begin scalar x,y,w;
  990. x:=prepf u; u := u ./ 1;
  991. if eqcar(x,'minus) then x:=cadr x;
  992. % FJW: abs sqrt y -> sqrt abs y if abs y simplifies.
  993. if eqcar(x,'sqrt) then
  994. return !*kk2q if eqcar(y:=reval('abs.cdr x), 'abs)
  995. then {'abs, x} else {'sqrt, y};
  996. %% if eqcar(x,'times) and (y:=split!-sign cdr x) then
  997. %% <<w:=simp!* retimes car y; u:=quotsq(u,w);
  998. %% if cadr y then
  999. %% <<y:=simp!* retimes cadr y; u:=quotsq(u,y);
  1000. %% w:=multsq(negsq y,w)>>
  1001. %% >>;
  1002. if eqcar(x,'times) then
  1003. begin scalar abslist, noabs;
  1004. for each fac in cdr x do
  1005. % FJW: abs sqrt y -> sqrt abs y if abs y simplifies.
  1006. if eqcar(fac,'sqrt)
  1007. and not eqcar(y:=reval('abs.cdr fac), 'abs)
  1008. then noabs := {'sqrt, y} . noabs
  1009. else abslist := fac . abslist;
  1010. abslist := reversip abslist;
  1011. if noabs then
  1012. u := quotsq(u, noabs := simp!*('times . reversip noabs));
  1013. if (y:=split!-sign abslist) then
  1014. <<w:=simp!* retimes car y; u:=quotsq(u,w);
  1015. if cadr y then
  1016. <<y:=simp!* retimes cadr y; u:=quotsq(u,y);
  1017. w:=multsq(negsq y,w)>>;
  1018. if noabs then w := multsq(noabs, w)
  1019. >>
  1020. else w := noabs
  1021. end;
  1022. if numr u neq 1 or denr u neq 1 then
  1023. u:=quotsq(mkabsf1 absf numr u,mkabsf1 denr u);
  1024. if w then u:=multsq(w,u);
  1025. return u
  1026. end;
  1027. %symbolic procedure rd!-abs u;
  1028. % % U is a prefix expression. If it represents a constant, return the
  1029. % % abs of u.
  1030. % (if !*rounded or not constant_exprp u then nil
  1031. % else begin scalar x,y,dmode!*;
  1032. % setdmode('rounded,t) where !*msg := nil;
  1033. % x := aeval u;
  1034. % if evalnumberp x
  1035. % then if null !*complex or 0=reval {'impart,x}
  1036. % then y := if evalgreaterp(x,0) then u
  1037. % else if evalequal(x,0) then 0
  1038. % else {'minus,u};
  1039. % setdmode('rounded,nil) where !*msg := nil;
  1040. % return if y then simp y else nil
  1041. % end) where alglist!*=alglist!*;
  1042. symbolic procedure sign!-abs u;
  1043. % Sign based evaluation of abs - includes the above rd!-abs
  1044. % method as sub-branch.
  1045. <<if not numberp n then nil else
  1046. simp if n<0 then {'minus,u} else if n=0 then 0 else u
  1047. >> where n=sign!-of u;
  1048. symbolic procedure constant_exprp u;
  1049. % True if u evaluates to a constant (i.e., number).
  1050. if atom u
  1051. then numberp u or flagp(u,'constant) or u eq 'i and idomainp()
  1052. else (flagp(car u,'realvalued)
  1053. or flagp(car u,'alwaysrealvalued)
  1054. or car u memq '(plus minus difference times quotient)
  1055. or get(car u,'!:rd!:)
  1056. or !*complex and get(car u,'!:cr!:))
  1057. and not atom cdr u
  1058. and constant_expr_listp cdr u;
  1059. symbolic procedure constant_expr_listp u;
  1060. % True if all members of u are constant_exprp.
  1061. % U can be a dotted pair as well as a list.
  1062. if atom u
  1063. then null u or numberp u or flagp(u,'constant)
  1064. or u eq 'i and idomainp()
  1065. else constant_exprp car u and constant_expr_listp cdr u;
  1066. symbolic procedure mkabsf0 u; simp{'abs,mk!*sq !*f2q u};
  1067. symbolic procedure mkabsf1 u;
  1068. if domainp u then mkabsfd u
  1069. else begin scalar x,y,v;
  1070. x := comfac!-to!-poly comfac u;
  1071. u := quotf1(u,x);
  1072. y := split!-comfac!-part x;
  1073. x := cdr y;
  1074. y := car y;
  1075. if positive!-sfp u then <<y := multf(u,y); u := 1>>;
  1076. u := multf(u,x);
  1077. v := lnc y;
  1078. y := quotf1(y,v);
  1079. v := multsq(mkabsfd v,y ./ 1);
  1080. return if u = 1 then v
  1081. else multsq(v,simpiden list('abs,prepf absf u))
  1082. end;
  1083. symbolic procedure mkabsfd u;
  1084. if null get('i,'idvalfn) then absf u ./ 1
  1085. else (simpexpt list(prepsq nrm,'(quotient 1 2))
  1086. where nrm = addsq(multsq(car us,car us),
  1087. multsq(cdr us,cdr us))
  1088. where us = splitcomplex u);
  1089. symbolic procedure positive!-sfp u;
  1090. if domainp u
  1091. then if get('i,'idvalfn)
  1092. then !:zerop impartf u and null !:minusp repartf u
  1093. else null !:minusp u
  1094. else positive!-powp lpow u and positive!-sfp lc u
  1095. and positive!-sfp red u;
  1096. symbolic procedure positive!-powp u;
  1097. not atom car u and caar u memq '(abs norm);
  1098. % symbolic procedure positive!-powp u;
  1099. % % This definition allows for the testing of positive valued vars.
  1100. % if atom car u then flagp(car u, 'positive)
  1101. % else ((if x then apply2(x,car u,cdr u) else nil)
  1102. % where x = get(caar u,'positivepfn));
  1103. symbolic procedure split!-comfac!-part u;
  1104. split!-comfac(u,1,1);
  1105. symbolic procedure split!-comfac(u,v,w);
  1106. if domainp u then multd(u,v) . w
  1107. else if red u then
  1108. if positive!-sfp u then multf(u,v) . w
  1109. else v . multf(u,w)
  1110. else if mvar u eq 'i then split!-comfac(lc u,v,w)
  1111. else if positive!-powp lpow u
  1112. then split!-comfac(lc u,multpf(lpow u,v),w)
  1113. else split!-comfac(lc u,v,multpf(lpow u,w));
  1114. put('abs,'simpfn,'simpabs);
  1115. symbolic procedure simpdiff u;
  1116. <<ckpreci!# u; addsq(simpcar u,simpminus cdr u)>>;
  1117. put('difference,'simpfn,'simpdiff);
  1118. symbolic procedure simpminus u;
  1119. negsq simp carx(u,'minus);
  1120. put('minus,'simpfn,'simpminus);
  1121. symbolic procedure simpplus u;
  1122. begin scalar z;
  1123. if length u=2 then ckpreci!# u;
  1124. z := nil ./ 1;
  1125. a: if null u then return z;
  1126. z := addsq(simpcar u,z);
  1127. u := cdr u;
  1128. go to a
  1129. end;
  1130. put('plus,'simpfn,'simpplus);
  1131. symbolic procedure ckpreci!# u;
  1132. % Screen for complex number input.
  1133. !*complex
  1134. and (if a and not b then ckprec2!#(cdar u,cadr u)
  1135. else if b and not a then ckprec2!#(cdadr u,car u))
  1136. where a=timesip car u,b=timesip cadr u;
  1137. symbolic procedure timesip x; eqcar(x,'times) and 'i memq cdr x;
  1138. symbolic procedure ckprec2!#(im,rl);
  1139. % Strip im and rl to domains.
  1140. <<im := if car im eq 'i then cadr im else car im;
  1141. if eqcar(im,'minus) then im := cadr im;
  1142. if eqcar(rl,'minus) then rl := cadr rl;
  1143. if domainp im and domainp rl and not(atom im and atom rl)
  1144. then ckprec3!#(!?a2bf im,!?a2bf rl)>>;
  1145. remflag('(!?a2bf),'lose); % Until things stabilize.
  1146. symbolic smacro procedure make!:ibf (mt, ep);
  1147. '!:rd!: . (mt . ep);
  1148. symbolic smacro procedure i2bf!: u; make!:ibf (u, 0);
  1149. symbolic procedure !?a2bf a;
  1150. % Convert decimal or integer to bfloat.
  1151. if atom a then if numberp a then i2bf!: a else nil
  1152. else if eqcar(a,'!:dn!:) then a;
  1153. symbolic procedure ckprec3!#(x,y);
  1154. % if inputs are valid, check for precision increase.
  1155. if x and y then
  1156. precmsg max(length explode abs cadr x+cddr x,
  1157. length explode abs cadr y+cddr y);
  1158. symbolic procedure simpquot q;
  1159. (if null numr u
  1160. then if null numr v then rerror(alg,19,"0/0 formed")
  1161. else rerror(alg,20,"Zero divisor")
  1162. else if dmode!* memq '(!:rd!: !:cr!:) and domainp numr u
  1163. and domainp denr u and domainp denr v
  1164. and !:onep denr u and !:onep denr v
  1165. then (if null numr v then nil else divd(numr v,numr u)) ./ 1
  1166. else <<q := multsq(v,simprecip cdr q);
  1167. if !*modular and null denr q
  1168. then rerror(alg,201,"Zero divisor");
  1169. q>>)
  1170. where v=simpcar q,u=simp cadr q;
  1171. put('quotient,'simpfn,'simpquot);
  1172. symbolic procedure simprecip u;
  1173. if null !*mcd then simpexpt list(carx(u,'recip),-1)
  1174. else invsq simp carx(u,'recip);
  1175. put('recip,'simpfn,'simprecip);
  1176. symbolic procedure simpset u;
  1177. begin scalar x;
  1178. x := prepsq simp!* car u;
  1179. if null x % or not idp x
  1180. then typerr(x,"set variable");
  1181. let0 list(list('equal,x,mk!*sq(u := simp!* cadr u)));
  1182. return u
  1183. end;
  1184. put ('set, 'simpfn, 'simpset);
  1185. symbolic procedure simpsqrt u;
  1186. if u=0 then nil ./ 1 else
  1187. if null !*keepsqrts
  1188. then simpexpt1(car u, simpexpon '(quotient 1 2), nil)
  1189. else begin scalar x,y;
  1190. x := xsimp car u;
  1191. return if null numr x then nil ./ 1
  1192. else if denr x=1 and domainp numr x and !:minusp numr x
  1193. then if numr x=-1 then simp 'i
  1194. else multsq(simp 'i,
  1195. simpsqrt list prepd !:minus numr x)
  1196. else if y := domainvalchk('sqrt,list x) then y
  1197. else simprad(x,2)
  1198. end;
  1199. symbolic procedure xsimp u; expchk simp!* u;
  1200. symbolic procedure simptimes u;
  1201. begin scalar x,y;
  1202. if null u then return 1 ./ 1;
  1203. if tstack!* neq 0 or null mul!* then go to a0;
  1204. y := mul!*;
  1205. mul!* := nil;
  1206. a0: tstack!* := tstack!*+1;
  1207. x := simpcar u;
  1208. a: u := cdr u;
  1209. if null numr x then go to c
  1210. else if null u then go to b;
  1211. x := multsq(x,simpcar u);
  1212. go to a;
  1213. b: if null mul!* or tstack!*>1 then go to c;
  1214. x:= apply1(car mul!*,x);
  1215. alglist!* := nil . nil; % since we may need MUL!* set again.
  1216. mul!*:= cdr mul!*;
  1217. go to b;
  1218. c: tstack!* := tstack!*-1;
  1219. if tstack!* = 0 then mul!* := y;
  1220. return x;
  1221. end;
  1222. put('times,'simpfn,'simptimes);
  1223. symbolic procedure resimp u;
  1224. % U is a standard quotient.
  1225. % Value is the resimplified standard quotient.
  1226. resimp1 u where varstack!*=nil;
  1227. symbolic procedure resimp1 u;
  1228. begin
  1229. u := quotsq(subf1(numr u,nil),subf1(denr u,nil));
  1230. !*sub2 := t;
  1231. return u
  1232. end;
  1233. symbolic procedure simp!*sq u;
  1234. if cadr u and null !*resimp then car u else resimp1 car u;
  1235. put('!*sq,'simpfn,'simp!*sq);
  1236. endmodule;
  1237. end;