extout.red 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. module extout; % Extended output package for expressions.
  2. % Author: Anthony C. Hearn.
  3. % Copyright (c) 1991 RAND. All rights reserved.
  4. fluid '(!*allfac !*div !*mcd !*noequiv !*pri !*rat factors!* kord!*
  5. !*combinelogs wtl!*);
  6. global '(dnl!* ordl!* upl!*);
  7. switch allfac,div,pri,rat;
  8. !*allfac := t; % factoring option for this package
  9. !*pri := t; % to activate this package
  10. % dnl!* := nil; % output control flag: puts powers in denom
  11. % factors!* := nil; % list of output factors
  12. % ordl!* := nil; % list of kernels introduced by ORDER statement
  13. % upl!* := nil; % output control flag: puts denom powers in
  14. % numerator
  15. % !*div := nil; % division option in this package
  16. % !*rat := nil; % flag indicating rational mode for output.
  17. symbolic procedure factor u;
  18. factor1(u,t,'factors!*);
  19. symbolic procedure factor1(u,v,w);
  20. begin scalar x,y,z,r;
  21. y := lispeval w;
  22. for each j in u do
  23. if (x := getrtype j) and (z := get(x,'factor1fn))
  24. then apply2(z,u,v)
  25. else <<while eqcar(j:=reval j,'list) and cdr j do
  26. <<r:=append(r,cddr j); j:=cadr j>>;
  27. x := !*a2kwoweight j;
  28. if v then y := aconc!*(delete(x,y),x)
  29. else if not(x member y)
  30. then msgpri(nil,j,"not found",nil,nil)
  31. else y := delete(x,y)>>;
  32. set(w,y);
  33. if r then return factor1(r,v,w)
  34. end;
  35. symbolic procedure remfac u;
  36. factor1(u,nil,'factors!*);
  37. rlistat '(factor remfac);
  38. symbolic procedure order u;
  39. <<rmsubs(); % Since order of terms in an operator argument can
  40. % affect simplification.
  41. if u and null car u and null cdr u then (ordl!* := nil)
  42. else for each x in kernel!-list u do
  43. <<if x member ordl!* then ordl!* := delete(x,ordl!*);
  44. ordl!* := aconc!*(ordl!*,x)>>>>;
  45. rlistat '(order);
  46. symbolic procedure up u;
  47. factor1(u,t,'upl!*);
  48. symbolic procedure down u;
  49. factor1(u,t,'dnl!*);
  50. % rlistat '(up down); % Omitted since not documented.
  51. symbolic procedure formop u;
  52. if domainp u then u
  53. else raddf(multop(lpow u,formop lc u),formop red u);
  54. symbolic procedure multop(u,v);
  55. if null kord!* then multpf(u,v)
  56. else if car u eq 'k!* then v
  57. else rmultpf(u,v);
  58. symbolic smacro procedure lcx u;
  59. % Returns leading coefficient of a form with zero reductum, or an
  60. % error otherwise.
  61. cdr carx(u,'lcx);
  62. symbolic procedure quotof(p,q);
  63. % P is a standard form, Q a standard form which is either a domain
  64. % element or has zero reductum.
  65. % Returns the quotient of P and Q for output purposes.
  66. if null p then nil
  67. else if p=q then 1
  68. else if q=1 then p
  69. else if domainp q then quotofd(p,q)
  70. else if domainp p
  71. % Make sure free variable degrees are accommodated.
  72. then (mksp(mvar q,
  73. if numberp x then -x else {'minus,x})
  74. .* quotof(p,lcx q) .+ nil) where x = ldeg q
  75. else (lambda (x,y);
  76. if car x eq car y
  77. then (lambda (n,w,z);
  78. if n=0 then raddf(w,z)
  79. else ((car y .** n) .* w) .+ z)
  80. (cdr x-cdr y,quotof(lc p,lcx q),quotof(red p,q))
  81. else if ordop(car x,car y)
  82. then (x .* quotof(lc p,q)) .+ quotof(red p,q)
  83. else mksp(car y,- cdr y) .* quotof(p,lcx q) .+ nil)
  84. (lpow p,lpow q);
  85. symbolic procedure quotofd(p,q);
  86. % P is a form, Q a domain element. Value is quotient of P and Q
  87. % for output purposes.
  88. if null p then nil
  89. else if domainp p then quotodd(p,q)
  90. else (lpow p .* quotofd(lc p,q)) .+ quotofd(red p,q);
  91. symbolic procedure quotodd(p,q);
  92. % P and Q are domain elements. Value is domain element for P/Q.
  93. if atom p and atom q then int!-equiv!-chk mkrn(p,q)
  94. else lowest!-terms(p,q);
  95. symbolic procedure lowest!-terms(u,v);
  96. % Reduces compatible domain elements U and V to a ratio in lowest
  97. % terms. Value as a rational may contain domain arguments rather
  98. % just integers. Modified to use dcombine for field division.
  99. if u=v then 1
  100. else if flagp(dmode!*,'field) or not atom u and flagp(car u,'field)
  101. or not atom v and flagp(car v,'field)
  102. % then multdm(u,!:recip v)
  103. then dcombine!*(u,v,'quotient)
  104. else begin scalar x;
  105. if atom(x := dcombine!*(u,v,'gcd)) and x neq 1 then
  106. <<u := dcombine!*(u,x,'quotient);
  107. v := dcombine!*(v,x,'quotient)>>;
  108. return if v=1 then u else '!:rn!: . (u . v)
  109. end;
  110. symbolic procedure dcombine!*(u,v,w);
  111. if atom u and atom v then apply2(w,u,v) else dcombine(u,v,w);
  112. symbolic procedure ckrn u;
  113. % Factors out the leading numerical coefficient from field domains.
  114. if flagp(dmode!*,'field) and not(dmode!* memq '(!:rd!: !:cr!:))
  115. then begin scalar x;
  116. x := lnc u;
  117. x := multf(x,ckrn1 quotfd(u,x));
  118. if null x then x := 1;
  119. % NULL could be caused by floating point underflow.
  120. return x
  121. end
  122. else ckrn1 u;
  123. symbolic procedure ckrn1 u;
  124. begin scalar x;
  125. if domainp u then return u;
  126. a: x := gck2(ckrn1 cdar u,x);
  127. if null cdr u
  128. then return if noncomp mvar u then x else list(caar u . x)
  129. else if domainp cdr u or not(caaar u eq caaadr u)
  130. then return gck2(ckrn1 cdr u,x);
  131. u := cdr u;
  132. go to a
  133. end;
  134. symbolic procedure gck2(u,v);
  135. % U and V are domain elements or forms with a zero reductum.
  136. % Value is the gcd of U and V.
  137. if null v then u
  138. else if u=v then u
  139. else if domainp u
  140. then if domainp v then
  141. if flagp(dmode!*,'field)
  142. or pairp u and flagp(car u,'field)
  143. or pairp v and flagp(car v,'field) then 1
  144. else if dmode!* eq '!:gi!: then intgcdd(u,v) else gcddd(u,v)
  145. else gck2(u,cdarx v)
  146. else if domainp v then gck2(cdarx u,v)
  147. else (lambda (x,y);
  148. if car x eq car y
  149. then list((if cdr x>cdr y then y else x) .
  150. gck2(cdarx u,cdarx v))
  151. else if ordop(car x,car y) then gck2(cdarx u,v)
  152. else gck2(u,cdarx v))
  153. (caar u,caar v);
  154. symbolic procedure cdarx u;
  155. cdr carx(u,'cdar);
  156. symbolic procedure negf!* u; negf u where !*noequiv = t;
  157. symbolic procedure prepsq!* u;
  158. begin scalar x,y,!*combinelogs;
  159. if null numr u then return 0;
  160. % The following leads to some ugly output.
  161. % else if minusf numr u
  162. % then return list('minus,prepsq!*(negf!* numr u ./ denr u));
  163. x := setkorder ordl!*;
  164. setkorder
  165. append(sort(for each j in factors!*
  166. join if not idp j then nil
  167. else if y := get(j,'prepsq!*fn)
  168. then apply2(y,u,j)
  169. else for each k in get(j,'klist)
  170. collect car k,'ordop),
  171. append(sort(factors!*,'ordop),ordl!*));
  172. if kord!* neq x or wtl!*
  173. then u := formop numr u . formop denr u;
  174. % u := if !*rat or (not flagp(dmode!*,'field) and !*div)
  175. u := if !*rat or !*div
  176. or upl!* or dnl!*
  177. then replus prepsq!*1(numr u,denr u,nil)
  178. else sqform(u,function prepsq!*2);
  179. setkorder x;
  180. return u
  181. end;
  182. symbolic procedure prepsq!*0(u,v);
  183. % U is a standard quotient, but not necessarily in lowest terms.
  184. % V a list of factored powers.
  185. % Value is equivalent list of prefix expressions (an implicit sum).
  186. begin scalar x;
  187. return if null numr u then nil
  188. else if (x := gcdf(numr u,denr u)) neq 1
  189. then prepsq!*1(quotf(numr u,x),quotf(denr u,x),v)
  190. else prepsq!*1(numr u,denr u,v)
  191. end;
  192. symbolic procedure prepsq!*1(u,v,w);
  193. % U and V are the numerator and denominator expression resp,
  194. % in lowest terms.
  195. % W is a list of powers to be factored from U.
  196. begin scalar x,y,z;
  197. % Look for "factors" in the numerator.
  198. if not domainp u and (mvar u member factors!* or (not
  199. atom mvar u and car mvar u member factors!*))
  200. then return nconc!*(
  201. if v=1 then prepsq!*0(lc u ./ v,lpow u . w)
  202. else (begin scalar n,v1,z1;
  203. % See if the same "factor" appears in denominator.
  204. n := ldeg u;
  205. v1 := v;
  206. z1 := !*k2f mvar u;
  207. while (z := quotfm(v1,z1)) do <<v1 := z; n := n-1>>;
  208. return
  209. prepsq!*0(lc u ./ v1,
  210. if n>0 then (mvar u .** n) . w
  211. else if n<0
  212. then mksp(list('expt,mvar u,n),1) . w
  213. else w)
  214. end),
  215. prepsq!*0(red u ./ v,w));
  216. % Now see if there are any remaining "factors" in denominator.
  217. % (KORD!* contains all potential kernel factors.)
  218. if not domainp v
  219. then for each j in kord!* do
  220. begin integer n; scalar z1;
  221. n := 0;
  222. z1 := !*k2f j;
  223. while z := quotfm(v,z1) do <<n := n-1; v := z>>;
  224. if n<0 then w := mksp(list('expt,j,n),1) . w
  225. end;
  226. % Now all "factors" have been removed.
  227. if kernlp u then <<u := mkkl(w,u); w := nil>>;
  228. if dnl!*
  229. then <<x := if null !*allfac then 1 else ckrn u;
  230. z := ckrn!*(x,dnl!*);
  231. x := quotof(x,z);
  232. u := quotof(u,z);
  233. v := quotof(v,z)>>;
  234. if upl!*
  235. then <<y := ckrn v;
  236. z := ckrn!*(y,upl!*);
  237. y := quotof(y,z);
  238. u := quotof(u,z);
  239. v := quotof(v,z)>>
  240. else if !*div then y := ckrn v
  241. else y := 1;
  242. u := canonsq (u . quotof(v,y));
  243. % if !*gcd then u := cancel u;
  244. u := quotof(numr u,y) ./ denr u;
  245. if !*allfac
  246. then <<x := ckrn numr u; y := ckrn denr u;
  247. if (x neq 1 or y neq 1)
  248. and (x neq numr u or y neq denr u)
  249. then <<v := quotof(denr u,y);
  250. u := quotof(numr u,x);
  251. w := prepf mkkl(w,x);
  252. x := prepf y;
  253. u := addfactors(w,u);
  254. v := addfactors(x,v);
  255. return if v=1 then rmplus u
  256. else list if eqcar(u,'minus)
  257. then list('minus,
  258. list('quotient,cadr u,v))
  259. else list('quotient,u,v)>>>>;
  260. return if w then list retimes aconc!*(exchk w,prepsq u)
  261. else rmplus prepsq u
  262. end;
  263. symbolic procedure addfactors(u,v);
  264. % U is a (possible) product of factors, v a standard form.
  265. % Result is a folded prefix expression.
  266. if u = 1 then prepf v
  267. else if v = 1 then u
  268. else if eqcar(u,'times) then 'times . aconc!*(cdr u,prepf v)
  269. else retimes list(u,prepf v);
  270. symbolic procedure rmplus u; if eqcar(u,'plus) then cdr u else list u;
  271. symbolic procedure prepsq!*2 u; replus prepsq!*1(u,1,nil);
  272. symbolic procedure ckrn!*(u,v);
  273. if null u then errach 'ckrn!*
  274. else if domainp u then 1
  275. else if caaar u member v
  276. then list (caar u . ckrn!*(cdr carx(u,'ckrn),v))
  277. else ckrn!*(cdr carx(u,'ckrn),v);
  278. symbolic procedure mkkl(u,v);
  279. if null u then v else mkkl(cdr u,list (car u . v));
  280. symbolic procedure quotfm(u,v);
  281. begin scalar !*mcd; !*mcd := t; return quotf(u,v) end;
  282. endmodule;
  283. end;