gcd.red 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. module gcd; % Greatest common divisor routines.
  2. % Author: Anthony C. Hearn.
  3. % Copyright (c) 1987 The RAND Corporation. All rights reserved.
  4. fluid '(!*exp !*ezgcd !*gcd !*heugcd !*mcd asymplis!* dmode!*);
  5. switch ezgcd,heugcd;
  6. % Note: The handling of non-commuting quantities in the following is
  7. % dubious. The problem is that to do things properly, a left- and
  8. % right-hand gcd and quotient would be necessary. For now, the code
  9. % returns 1 if the quotient tests fail in gcdf1 for non-commuting
  10. % arguments.
  11. symbolic procedure comfac p;
  12. % P is a non-atomic standard form.
  13. % CAR of result is lowest common power of leading kernel in
  14. % every term in P (or NIL). CDR is gcd of all coefficients of
  15. % powers of leading kernel.
  16. % If field elements are involved, lnc is normalized to 1.
  17. % We need GCDF here since the same function is used by EZGCD.
  18. begin scalar x,y;
  19. if flagp(dmode!*,'field) and ((x := lnc p) neq 1)
  20. then p := multd(!:recip x,p);
  21. if null red p then return lt p;
  22. x := lc p;
  23. y := mvar p;
  24. a: p := red p;
  25. if degr(p,y)=0
  26. then return nil
  27. . if domainp p or not(noncomp y and noncomp mvar p)
  28. then gcdf(x,p)
  29. else 1
  30. else if null red p then return lpow p . gcdf(x,lc p)
  31. else x := gcdf(lc p,x);
  32. go to a
  33. end;
  34. symbolic procedure degr(u,var);
  35. if domainp u or not(mvar u eq var) then 0 else ldeg u;
  36. put('gcd,'polyfn,'gcdf!*);
  37. put('gcd,'number!-of!-args,2);
  38. symbolic procedure gcdf!*(u,v);
  39. begin scalar !*gcd; !*gcd := t; return gcdf(u,v) end;
  40. symbolic procedure gcdf(u,v);
  41. % U and V are standard forms.
  42. % Value is the gcd of U and V, complete only if *GCD is true.
  43. begin scalar !*exp,!*rounded;
  44. % The next line was to prevent numerators moving to denominators
  45. % as in weight x=1,y=2$ wtlevel 4$ wtest:=(z^4-z^3*y-z^3*x+z^2*y^2
  46. % +2*z^2*x*y+z^2*x^2-3*z*x^2*y-z*x^3+x^4)/z^5; wtest where z=>a;
  47. % However, the results are formally correct without it, and it
  48. % causes other problems.
  49. % if wtl!* then return 1;
  50. !*exp := t;
  51. u := if domainp u or domainp v or not !*ezgcd
  52. % or dmode!* memq '(!:rn!: !:rd!:) % Should be generalized.
  53. or dmode!* % I don't know what to do in this case.
  54. or free!-powerp u or free!-powerp v
  55. then gcdf1(u,v)
  56. else ezgcdf(u,v);
  57. return if minusf u then negf u else u
  58. end;
  59. symbolic procedure free!-powerp u;
  60. not domainp u
  61. and (not fixp ldeg u or free!-powerp lc u or free!-powerp red u);
  62. symbolic procedure gcdf1(u,v);
  63. begin scalar w;
  64. if null u then return v
  65. else if null v then return u
  66. else if u=1 or v=1 then return 1
  67. else if domainp u then return gcdfd(u,v)
  68. else if domainp v then return gcdfd(v,u)
  69. else if not num!-exponents u or not num!-exponents v then 1
  70. else if quotf1(u,v) then return v
  71. else if quotf1(v,u) then return u;
  72. w := gcdf2(u,v);
  73. if !*gcd and not(dmode!* memq '(!:rd!: !:cr!:))
  74. and (null quotf1(u,w) or null quotf1(v,w))
  75. then if noncomfp u or noncomfp v then return 1
  76. else errach list("gcdf failed",prepf u,prepf v);
  77. % This probably implies that integer overflow occurred.
  78. return w
  79. end;
  80. symbolic procedure gcdf2(u,v);
  81. % U and V are both non-trivial forms. Value is their GCD.
  82. % We need to rebind asymplis!* to avoid setting higher powers to 0.
  83. begin scalar asymplis!*,w,z;
  84. if not num!-exponents u or not num!-exponents v then return 1;
  85. if !*gcd and length(w := kernord(u,v))>1
  86. then <<w := list setkorder w; % List used to make sure non-NIL
  87. u := reorder u;
  88. v := reorder v>>
  89. else w := nil;
  90. % Things can go wrong with noncom oprs. However, empirically we
  91. % only need to make sure that both u and v do not have a leading
  92. % noncom opr.
  93. if mvar u eq mvar v
  94. then begin scalar x,y;
  95. x := comfac u;
  96. y := comfac v;
  97. z := gcdf1(cdr x,cdr y);
  98. u := quotf1(u,comfac!-to!-poly x);
  99. v := quotf1(v,comfac!-to!-poly y);
  100. if !*gcd then z := multf(gcdk(u,v),z)
  101. else if v and quotf1(u,v) then z := multf(v,z)
  102. else if u and quotf1(v,u) then z := multf(u,z);
  103. if car x and car y
  104. then if pdeg car x>pdeg car y
  105. then z := multpf(car y,z)
  106. else z := multpf(car x,z)
  107. end
  108. else if noncomp mvar u and noncomp mvar v
  109. then z := gcdfnc(u,v,mvar v)
  110. else if ordop(mvar u,mvar v) then z := gcdf1(cdr comfac u,v)
  111. else z := gcdf1(cdr comfac v,u);
  112. if w then <<setkorder car w; z := reorder z>>;
  113. return z
  114. end;
  115. symbolic procedure gcdfnc(x,p,y);
  116. if domainp x or not noncomp mvar x then gcdf1(x,p)
  117. else if null red x then gcdfnc(lc x,p,y)
  118. else gcdf1(gcdfnc(lc x,p,y),gcdfnc(red x,p,y));
  119. symbolic procedure num!-exponents u;
  120. % check that all exponents are integers (this may not be true in
  121. % rules).
  122. domainp u or
  123. fixp ldeg u and num!-exponents lc u and num!-exponents red u;
  124. symbolic procedure gcdfd(u,v);
  125. % U is a domain element, V a form.
  126. % Value is gcd of U and V.
  127. % if not atom u and flagp(car u,'field) then 1 else gcdfd1(u,v);
  128. if flagp(dmode!*,'field) then 1 else gcdfd1(u,v);
  129. symbolic procedure gcdfd1(u,v);
  130. if null v then u
  131. else if domainp v then gcddd(u,v)
  132. else gcdfd1(gcdfd1(u,lc v),red v);
  133. symbolic procedure gcddd(u,v);
  134. %U and V are domain elements. If they are invertable, value is 1
  135. %otherwise the gcd of U and V as a domain element;
  136. if u=1 or v=1 then 1
  137. % else if atom u and atom v then gcdn(u,v)
  138. else if atom u then if atom v then gcdn(u,v)
  139. else if fieldp v then 1
  140. else dcombine(u,v,'gcd)
  141. else if atom v
  142. then if flagp(car u,'field) then 1 else dcombine(u,v,'gcd)
  143. else if flagp(car u,'field) or flagp(car v,'field) then 1
  144. else dcombine(u,v,'gcd);
  145. symbolic procedure gcdk(u,v);
  146. % U and V are primitive polynomials in the main variable VAR.
  147. % Result is gcd of U and V.
  148. begin scalar lclst,var,w,x;
  149. if u=v then return u
  150. else if domainp u or degr(v,(var := mvar u))=0 then return 1
  151. else if ldeg u<ldeg v then <<w := u; u := v; v := w>>;
  152. if quotf1(u,v) then return v
  153. else if !*heugcd and (x := heu!-gcd(u,v)) then return x
  154. % else if flagp(dmode!*,'field) then return 1
  155. % otherwise problems arise.
  156. else if ldeg v=1
  157. or getd 'modular!-multicheck and modular!-multicheck(u,v,var)
  158. or not !*mcd
  159. then return 1;
  160. a: w := remk(u,v);
  161. if null w then return v
  162. else if degr(w,var)=0 then return 1;
  163. lclst := addlc(v,lclst);
  164. if x := quotf1(w,lc w) then w := x
  165. else for each y in lclst do
  166. if atom y or not % prevent endless loop in !:gi!: dmode.
  167. (domainp y and (x := get(car y,'units))
  168. and y member (for each z in x collect car z))
  169. then while (x := quotf1(w,y)) do w := x;
  170. u := v; v := prim!-part w;
  171. if degr(v,var)=0 then return 1 else go to a
  172. end;
  173. symbolic procedure addlc(u,v);
  174. if u=1 then v
  175. else (lambda x;
  176. if x=1 or x=-1 or not atom x and flagp(car x,'field) then v
  177. else x . v)
  178. lc u;
  179. symbolic procedure delallasc(u,v);
  180. if null v then nil
  181. else if u eq caar v then delallasc(u,cdr v)
  182. else car v . delallasc(u,cdr v);
  183. symbolic procedure kernord(u,v);
  184. <<u := kernord!-split(u,v);
  185. append(kernord!-sort car u,kernord!-sort cdr u)>>;
  186. symbolic procedure kernord!-split(u,v);
  187. % splits U and V into a set of powers of those kernels occurring in
  188. % one form and not the other, and those occurring in both;
  189. begin scalar x,y;
  190. u := powers u;
  191. v := powers v;
  192. for each j in u do
  193. if assoc(car j,v) then y := j . y else x := j . x;
  194. for each j in v do
  195. if assoc(car j,u) then y := j . y else x := j . x;
  196. return reversip x . reversip y
  197. end;
  198. symbolic procedure kernord!-sort u;
  199. % returns list of kernels ordered so that kernel with lowest maximum
  200. % power in U (a list of powers) is first, and so on;
  201. begin scalar x,y;
  202. while u do
  203. <<x := maxdeg(cdr u,car u);
  204. u := delallasc(car x,u);
  205. y := car x . y>>;
  206. return y
  207. end;
  208. symbolic procedure maxdeg(u,v);
  209. if null u then v
  210. else if cdar u>cdr v then maxdeg(cdr u,car u)
  211. else maxdeg(cdr u,v);
  212. symbolic procedure powers form;
  213. % returns a list of the maximum powers of each kernel in FORM.
  214. % order tends to be opposite to original order.
  215. powers0(form,nil);
  216. symbolic procedure powers0(form,powlst);
  217. if null form or domainp form then powlst
  218. else begin scalar x;
  219. if (x := atsoc(mvar form,powlst))
  220. % then ldeg form>cdr x and rplacd(x,ldeg form)
  221. then (if ldeg form>cdr x
  222. then powlst := repasc(mvar form,ldeg form,powlst))
  223. else powlst := (mvar form . ldeg form) . powlst;
  224. return powers0(red form,powers0(lc form,powlst))
  225. end;
  226. put('lcm,'polyfn,'lcm!*);
  227. put('lcm,'number!-of!-args,2);
  228. symbolic procedure lcm!*(u,v);
  229. begin scalar !*gcd; !*gcd := t; return lcm(u,v) end;
  230. symbolic procedure lcm(u,v);
  231. %U and V are standard forms. Value is lcm of U and V;
  232. if null u or null v then nil
  233. else if u=1 then v % ONEP
  234. else if v=1 then u % ONEP
  235. else multf(u,quotf(v,gcdf(u,v)));
  236. symbolic procedure remk(u,v);
  237. %modified pseudo-remainder algorithm
  238. %U and V are polynomials, value is modified prem of U and V;
  239. begin scalar f1,var,x; integer k,n;
  240. f1 := lc v;
  241. var := mvar v;
  242. n := ldeg v;
  243. while (k := degr(u,var)-n)>=0 do
  244. <<x := negf multf(lc u,red v);
  245. if k>0 then x := multpf(var .** k,x);
  246. u := addf(multf(f1,red u),x)>>;
  247. return u
  248. end;
  249. symbolic procedure prim!-part u;
  250. %returns the primitive part of the polynomial U wrt leading var;
  251. quotf1(u,comfac!-to!-poly comfac u);
  252. symbolic procedure comfac!-to!-poly u;
  253. if null car u then cdr u else list u;
  254. endmodule;
  255. end;