compopr.red 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. module compopr; % Operators on Complex Expressions.
  2. % Author: Eberhard Schruefer.
  3. % Modifications by: Francis Wright.
  4. fluid '(!*exp !*factor kord!*);
  5. put('repart,'simpfn,'simprepart);
  6. symbolic procedure simprepart u;
  7. repartsq simp!* car u where !*factor = nil;
  8. symbolic procedure repartsq u;
  9. multsq(addsq(multsq(repartnum,repartden),
  10. multsq(impartnum,impartden)),
  11. invsq addsq(multsq(repartden,repartden),
  12. multsq(impartden,impartden)))
  13. where repartnum = car reimnum, impartnum = cdr reimnum,
  14. repartden = car reimden, impartden = cdr reimden
  15. where reimnum = splitcomplex numr u,
  16. reimden = splitcomplex denr u;
  17. put('impart,'simpfn,'simpimpart);
  18. symbolic procedure simpimpart u;
  19. impartsq simp!* car u where !*factor = nil;
  20. symbolic procedure impartsq u;
  21. multsq(addsq(multsq(impartnum,repartden),
  22. negsq multsq(repartnum,impartden)),
  23. invsq addsq(multsq(repartden,repartden),
  24. multsq(impartden,impartden)))
  25. where repartnum = car reimnum, impartnum = cdr reimnum,
  26. repartden = car reimden, impartden = cdr reimden
  27. where reimnum = splitcomplex numr u,
  28. reimden = splitcomplex denr u;
  29. put('conj,'simpfn,'simpconj);
  30. symbolic procedure simpconj u;
  31. conjsq simp!* car u;
  32. symbolic procedure conjsq u;
  33. (if null numr w then u else addsq(repartsq u,negsq multsq(simp 'i,w)))
  34. where w=impartsq u;
  35. smacro procedure idomainp; get('i,'idvalfn);
  36. % Tests if 'i' is transformed to a domain structure.
  37. symbolic procedure splitcomplex u;
  38. (begin scalar v;
  39. v := if idomainp() then expand!-imrepart u
  40. else <<if smemq('i,u) then
  41. <<setkorder('i . kord!*); u:=reorder u>>;
  42. subs2 expand!-imrepart u>>;
  43. return take!-realpart v . take!-impart v
  44. end) where kord!* = kord!*,!*exp = t;
  45. symbolic procedure expand!-imrepart u;
  46. if domainp u then u ./ 1
  47. else addsq(multsq(expand!-imrepartpow lpow u,
  48. expand!-imrepart lc u),
  49. expand!-imrepart red u);
  50. symbolic procedure expand!-imrepartpow u;
  51. % This needs to treat kernels that are standard forms smarter.
  52. % At the moment, we expand to get the required result.
  53. begin scalar !*exp,cmpxsplitfn;
  54. !*exp := t;
  55. cmpxsplitfn := null idp car u and
  56. get(car car u,'cmpxsplitfn);
  57. return
  58. exptsq(if null cmpxsplitfn
  59. then if car u eq 'i then !*k2q 'i
  60. else addsq(mkrepart car u,
  61. multsq(simp 'i,
  62. mkimpart car u))
  63. else apply1(cmpxsplitfn,car u),cdr u)
  64. end;
  65. symbolic procedure mkrepart u;
  66. if realvaluedp u then !*k2q u
  67. else if sfp u then repartsq(u ./ 1)
  68. else mksq(list('repart, u),1);
  69. symbolic procedure mkimpart u;
  70. if realvaluedp u then nil ./ 1
  71. else if sfp u then impartsq(u ./ 1)
  72. else mksq(list('impart, u),1);
  73. symbolic procedure take!-realpart u;
  74. repartf numr u ./ denr u;
  75. symbolic procedure repartf u;
  76. % We can't check for null dmode!* as there may still be complex
  77. % domain elements in the expression (e.g., e^repart x).
  78. (if domainp u
  79. then if atom u then u
  80. else if get(car u,'cmpxfn)
  81. % We now know u is of form (<tag> <re> . <im>).
  82. then int!-equiv!-chk(car u . cadr u .
  83. cadr apply1(get(car u,'i2d),0))
  84. % Otherwise we assume it is real
  85. else u
  86. else if mvar u eq 'i then repartf red u
  87. % else if null dmode!* then addf(!*t2f lt u,repartf red u)
  88. else addf(multpf(lpow u,repartf lc u),repartf red u))
  89. where u = reorder u where kord!* = 'i . kord!*;
  90. symbolic procedure take!-impart u;
  91. impartf numr u ./ denr u;
  92. symbolic procedure impartf u;
  93. % We can't check for null dmode!* as there may still be complex
  94. % domain elements in the expression.
  95. (if domainp u
  96. then if atom u then nil
  97. else if get(car u,'cmpxfn)
  98. % We now know u is of form (<tag> <re> . <im>).
  99. then int!-equiv!-chk(car u . cddr u .
  100. cadr apply1(get(car u,'i2d),0))
  101. % Otherwise we assume it is real
  102. else nil
  103. else if mvar u eq 'i then addf(lc u,impartf red u)
  104. % else if null dmode!* then impartf red u
  105. else addf(multpf(lpow u,impartf lc u),impartf red u))
  106. where u = reorder u where kord!* = 'i . kord!*;
  107. % The following code attempts to improve the way that the complex
  108. % operators CONJ, REPART and IMPART handle values that are implicitly
  109. % real, namely composed "reality-preserving" functions of explicitly
  110. % real numbers, implicitly real symbolic constants and variables that
  111. % the user has declared using the REALVALUED command defined below.
  112. % All arithmetic operations, direct trig functions and the exponential
  113. % function are "reality-preserving", but inverse trig functions and the
  114. % logarithm are "reality-preserving" only for real arguments in a
  115. % restricted range. This relates to piecewise-defined functions! This
  116. % code is believed to make the right decision about implicit reality in
  117. % straightforward cases, and otherwise errs on the side of caution and
  118. % makes no assumption at all, as does the standard REDUCE 3.4 code. It
  119. % performs only very limited numerical evaluation, which should be very
  120. % fast. It never performs any approximate numerical evaluation, or any
  121. % sophisticated analysis, both of which would be much slower and/or
  122. % complicated. The current strategy is believed to represent a
  123. % reasonable compromise, and will normally give the user what they
  124. % expect without undue overhead.
  125. rlistat '(realvalued notrealvalued); % Make user operators.
  126. symbolic procedure realvalued u;
  127. % Command to allow the user to declare functions or variables to be
  128. % implicitly real valued.
  129. <<rmsubs(); % So that an expression can be re-evaluated.
  130. for each v in u do
  131. if not idp v then typerr(v,"id")
  132. else flag(list v,'realvalued)>>;
  133. symbolic procedure notrealvalued u;
  134. % Undo realvalued declaration.
  135. % Cannot recover "complexity", so no need for rmsubs().
  136. for each v in u do
  137. if not idp v then typerr(v,"id")
  138. else remflag(list v, 'realvalued);
  139. flag('(realvaluedp),'boolean); % Make realvaluedp available in
  140. % algebraic mode.
  141. symbolic procedure realvaluedp u;
  142. % True if the true prefix kernel form u is explicitly or implicitly
  143. % real-valued.
  144. if atom u then numberp u or flagp(u, 'realvalued)
  145. else begin scalar caru; % cnd
  146. return
  147. flagp((caru := car u), 'alwaysrealvalued)
  148. % real-valued for all possible argument values
  149. or (flagp(caru, 'realvalued) and realvaluedlist cdr u)
  150. % real-valued function if arguments are real-valued,
  151. % an important common special case of condrealvalued.
  152. %% or ((cnd := get(caru, 'condrealvalued)) and apply(cnd, cdr u))
  153. % real-valued function if arguments satisfy conditions
  154. % that depend on the function
  155. or caru eq '!:rd!:; % rounded number - least likely?
  156. end;
  157. symbolic procedure realvaluedlist u;
  158. % True if every element of the list u of true prefix kernel forms
  159. % is real-valued.
  160. realvaluedp car u and (null cdr u or realvaluedlist cdr u);
  161. % Define the real valued properties
  162. % ---------------------------------
  163. % Only operators that can remain symbolic need be considered,
  164. % e.g. NOT nextprime, num, den, deg, det.
  165. % A very small number of functions are real-valued for ALL arguments:
  166. flag('(repart impart abs ceiling floor fix round max min),
  167. 'alwaysrealvalued);
  168. % Symbolic constants:
  169. flag('(pi e infinity),'realvalued);
  170. % Some functions are real-valued if all their arguments are
  171. % real-valued, without further constraints:
  172. % Arithmetic operators:
  173. flag('(plus minus times quotient), 'realvalued);
  174. % Elementary transcendental functions, etc:
  175. flag('(exp cbrt hypot sin cos tan csc sec cot sind cosd tand cscd secd
  176. cotd sinh cosh tanh csch sech coth atan atand atan2 atan2d acot
  177. acotd asinh acsch factorial),
  178. 'realvalued);
  179. % Additional such variables and functions can be declared by the user
  180. % with the REALVALUED command defined above.
  181. put('sin,'cmpxsplitfn,'reimsin);
  182. symbolic procedure reimsin u;
  183. addsq(multsq(simp list('sin,rearg),
  184. simp list('cosh,imarg)),
  185. multsq(simp 'i,
  186. multsq(simp list('cos,rearg),
  187. simp list('sinh,imarg))))
  188. where rearg = prepsq simprepart cdr u,
  189. imarg = prepsq simpimpart cdr u;
  190. put('cos,'cmpxsplitfn,'reimcos);
  191. symbolic procedure reimcos u;
  192. addsq(multsq(simp list('cos,rearg),
  193. simp list('cosh,imarg)),
  194. multsq(simp 'i,negsq
  195. multsq(simp list('sin,rearg),
  196. simp list('sinh,imarg))))
  197. where rearg = prepsq simprepart cdr u,
  198. imarg = prepsq simpimpart cdr u;
  199. put('expt,'cmpxsplitfn,'reimexpt);
  200. symbolic procedure reimexpt u;
  201. if cadr u eq 'e
  202. then addsq(reimcos list('cos,reval list('times,'i,caddr u)),
  203. multsq(simp list('minus,'i),
  204. reimsin list('sin,reval list('times,'i,caddr u))))
  205. else if fixp cadr u and cadr u > 0
  206. and eqcar(caddr u,'quotient)
  207. and fixp cadr caddr u
  208. and fixp caddr caddr u
  209. then mksq(u,1)
  210. else addsq(mkrepart u,multsq(simp 'i,mkimpart u));
  211. endmodule;
  212. end;