facform.red 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. module facform; % Factored form representation for standard form polys.
  2. % Author: Anthony C. Hearn.
  3. % Modifications by: Francis J. Wright.
  4. % Copyright (c) 1990 The RAND Corporation. All rights reserved.
  5. % INTEGER FACTORS?
  6. % SHOULDN'T SYMMETRIC TESTS ETC BE RUN RECURSIVELY?
  7. fluid '(!*exp !*ezgcd !*factor !*force!-prime !*gcd !*ifactor !*nopowers
  8. !*kernreverse !*limitedfactors !*sqfree !*trfac current!-modulus
  9. dmode!* m!-image!-variable ncmp!*);
  10. switch limitedfactors,nopowers;
  11. % switch sqfree;
  12. put('sqfree,'simpfg,'((t (rmsubs) (setq !*exp nil))
  13. (nil (rmsubs) (setq !*exp t))));
  14. comment In this module, we consider the manipulation of factored forms.
  15. These have the structure
  16. <monomial> . <form-power-list>
  17. where the monomial is a standard form (with numerator and
  18. denominator satisfying the KERNLP test) and a form-power is a
  19. dotted pair whose car is a standard form and cdr an integer>0.
  20. We have thus represented the form as a product of a monomial
  21. quotient and powers of non-monomial factors;
  22. symbolic procedure fac!-merge(u,v);
  23. % Returns the merge of the factored forms U and V.
  24. multf(car u,car v) . append(cdr u,cdr v);
  25. symbolic procedure factorize u;
  26. % Factorize the polynomial u, returning the factors found.
  27. (begin scalar x,y;
  28. x := simp!* u;
  29. y := denr x;
  30. if not domainp y then typerr(u,"polynomial");
  31. u := numr x;
  32. if u = 1 then return
  33. {'list, if !*nopowers then 1 else {'list,1,1}} % FJW
  34. else if fixp u then !*ifactor := t; % Factor an integer.
  35. if !*force!-prime and not primep !*force!-prime
  36. then typerr(!*force!-prime,"prime");
  37. u := if dmode!*
  38. then if get(dmode!*,'factorfn)
  39. then begin scalar !*factor;
  40. !*factor := t;
  41. return fctrf u
  42. end
  43. else rerror(poly,14,
  44. list("Factorization not supported over domain",
  45. get(dmode!*,'dname)))
  46. else fctrf u;
  47. return facform2list(u,y)
  48. end) where !*ifactor = !*ifactor;
  49. symbolic procedure facform2list(x,y);
  50. % x is a factored form.
  51. % y is a possible numerical (domain) denominator.
  52. begin scalar factor!-count,z;
  53. if null car x and null cdr x then return list 'list
  54. % car x is now expected to be a number.
  55. else if null !*nopowers then z := facform2list2 x
  56. else <<
  57. z:= (0 . car x) . nil;
  58. x := reversip!* cdr x; % This puts factors in better order.
  59. factor!-count:=0;
  60. for each fff in x do
  61. for i:=1:cdr fff do
  62. z := ((factor!-count:=factor!-count+1) .
  63. mk!*sq(car fff ./ 1)) . z;
  64. z := multiple!-result(z,nil);
  65. if atom z then typerr(z,"factor form") % old style input.
  66. else if numberp cadr z and cadr z<0 and cddr z
  67. then z := car z .
  68. (- cadr z) . mk!*sq negsq simp caddr z
  69. . cdddr z;
  70. % make numerical coefficient positive.
  71. z := cdr z;
  72. if car z = 1 then z := cdr z
  73. else if not fixp car z then z := prepd car z . cdr z
  74. else if !*ifactor
  75. then z := append(pairlist2list reversip zfactor car z,
  76. cdr z)>>;
  77. if y neq 1 then z := list('recip,prepd y) . z;
  78. return 'list . z
  79. end;
  80. symbolic procedure facform2list2 u;
  81. begin scalar bool,x;
  82. if !:minusp(x := car u) then <<bool := t; x := !:minus x>>;
  83. u := cdr u;
  84. if x neq 1
  85. then if !*ifactor and fixp x
  86. then u := append(reversip zfactor x,u)
  87. else u := (x . 1) . u;
  88. % Adjust for negative sign.
  89. x := nil;
  90. for each j in u do
  91. if bool and not evenp cdr j
  92. then <<bool := nil; x := (negf car j . cdr j) . x>>
  93. else x := j . x;
  94. % Convert terms to list form.
  95. u := nil;
  96. for each j in x do
  97. if fixp car j then u := {'list,car j,cdr j} . u
  98. else u := {'list,mk!*sq(car j ./ 1),cdr j} . u;
  99. return if bool then '(list -1 1) . u else u
  100. end;
  101. symbolic procedure old_factorize u; factorize u where !*nopowers=t;
  102. flag('(factorize old_factorize),'opfn);
  103. symbolic procedure pairlist2list u;
  104. for each x in u conc nlist(car x,cdr x);
  105. symbolic procedure fctrf u;
  106. % U is a standard form. Value is a factored form.
  107. % The function FACTORF is an assumed entry point to a more complete
  108. % factorization module. It returns a form power list.
  109. (begin scalar !*ezgcd,!*gcd,denom,x,y;
  110. if domainp u then return list u
  111. else if ncmp!* and not noncomfp u then ncmp!* := nil;
  112. !*gcd := t;
  113. if null !*limitedfactors and null dmode!* then !*ezgcd := t;
  114. if null !*mcd
  115. then rerror(poly,15,"Factorization invalid with MCD off")
  116. else if null !*exp
  117. then <<!*exp := t; u := !*q2f resimp !*f2q u>>;
  118. % Convert rationals to integers for factorization.
  119. if dmode!* eq '!:rn!:
  120. then <<dmode!* := nil; alglist!* := nil . nil;
  121. u := simp prepf u;
  122. denom := denr u; u := numr u>>;
  123. % Check for homogeneous polynomials. This can't be done with
  124. % current code though if non-commuting objects occur.
  125. if null ncmp!*
  126. then <<x := sf2ss u;
  127. if homogp x
  128. then <<if !*trfac
  129. then prin2t
  130. "This polynomial is homogeneous - variables scaled";
  131. y := caaar x . listsum caaadr x;
  132. x := fctrf1 ss2sf(car(x)
  133. . (reverse subs0 cadr x . 1));
  134. x := rconst(y,x);
  135. return car x . sort!-factors cdr x>>>>;
  136. u := fctrf1 u;
  137. if denom
  138. then <<alglist!* := nil . nil;
  139. dmode!* := '!:rn!:; car u := quotf(car u,denom)>>;
  140. return car u . sort!-factors cdr u
  141. end) where !*exp = !*exp, ncmp!* = ncmp!*;
  142. symbolic procedure fctrf1 u;
  143. begin scalar x,y,z;
  144. if domainp u then return list u; % Do this again just in case.
  145. if flagp(dmode!*,'field) and ((z := lnc u) neq 1)
  146. then u := multd(!:recip z,u)
  147. else if dmode!* and (y := get(dmode!*,'unitsfn))
  148. then <<x := apply2(y,1 . u,lnc u);
  149. u := cdr x;
  150. z := !:recip car x>>;
  151. x := comfac u;
  152. u := quotf(u,comfac!-to!-poly x);
  153. y := fctrf1 cdr x; % factor the content.
  154. if car x then y := car y . (!*k2f caar x . cdar x) . cdr y;
  155. if z and (z neq 1) then y := multd(z,car y) . cdr y;
  156. if domainp u then return multf(u,car y) . cdr y
  157. else if minusf u
  158. then <<u := negf u; y := negf car y . cdr y>>;
  159. return fac!-merge(factor!-prim!-f u,y)
  160. end;
  161. symbolic procedure factorize!-form!-recursion u;
  162. fctrf1 u;
  163. symbolic procedure factor!-prim!-f u;
  164. % U is a non-trivial form which is primitive in all its variables
  165. % and has a positive leading numerical coefficient. Result is a
  166. % form power list.
  167. begin scalar v,w,x,y;
  168. if ncmp!* then return list(1,u . 1);
  169. if dmode!* and (x := get(dmode!*,'sqfrfactorfn))
  170. then if !*factor then v := apply1(x,u) else v := list(1,u . 1)
  171. else if flagp(dmode!*,'field) and ((w := lnc u) neq 1)
  172. then v := w . sqfrf multd(!:recip w,u)
  173. else if (w := get(dmode!*,'units)) and (w := assoc(y := lnc u,w))
  174. then v := y . sqfrf multd(cdr w,u)
  175. else v := 1 . sqfrf u;
  176. if x and (x eq get(dmode!*,'factorfn))
  177. then return v; % No point in re-factorizing.
  178. w := list car v;
  179. for each x in cdr v
  180. do w := fac!-merge(factor!-prim!-sqfree!-f x,w);
  181. return w
  182. end;
  183. symbolic procedure factor!-prim!-sqfree!-f u;
  184. % U is of the form <square free poly> . <power>. Result is a factored
  185. % form.
  186. % Modified to work properly in rounded (real or complex),
  187. % rational and complex modes. SLK.
  188. begin scalar x,y,!*msg,r;
  189. r := !*rounded;
  190. if r or !*complex or !*rational then
  191. <<if r then on rational;
  192. u := numr resimp !*f2q car u . cdr u>>;
  193. if null !*limitedfactors
  194. then <<if null dmode!* then y := 'factorf
  195. else <<x := get(dmode!*,'sqfrfactorfn);
  196. y := get(dmode!*,'factorfn);
  197. if x and not(x eq y) then y := 'factorf>>;
  198. if y
  199. then <<y := apply1(y,car u);
  200. u := (car y . for each j in cdr y
  201. collect(car j . cdr u));
  202. go to ret>>>>;
  203. u := factor!-prim!-sqfree!-f!-1(car u,cdr u);
  204. ret: if r then
  205. <<on rounded;
  206. u := car u . for each j in cdr u collect
  207. (numr resimp !*f2q car j . cdr j)>>;
  208. return u
  209. end;
  210. symbolic procedure distribute!.multiplicity(factorlist,n);
  211. % Factorlist is a simple list of factors of a square free primitive
  212. % multivariate poly and n is their multiplicity in a square free
  213. % decomposition of another polynomial. result is a list of form:
  214. % ((f1 . n),(f2 . n),...) where fi are the factors.
  215. for each w in factorlist collect (w . n);
  216. symbolic procedure factorf u;
  217. % NOTE: This is not an entry point to be used by novice programmers.
  218. % Please used FCTRF instead.
  219. % There is an inefficiency in this procedure relating to ordering.
  220. % There is a final reordering done at every recursive level in order
  221. % to make sure final result has the right order. However, this only
  222. % need be done once at the top level, probably in fctrf. Since some
  223. % programmers still use this function however, it's safer for it to
  224. % return results in the correct order.
  225. (begin scalar m!-image!-variable,new!-korder,old!-korder,sign,v,w;
  226. if domainp u then return list u;
  227. new!-korder:=kernord(u,nil);
  228. if !*kernreverse then new!-korder:=reverse new!-korder;
  229. old!-korder:=setkorder new!-korder;
  230. u := reorder u; % Make var of lowest degree the main one.
  231. if minusf u then <<sign := not sign; u := negf u>>;
  232. v := comfac u; % Since new order may reveal more factors.
  233. u := quotf1(u,cdr v);
  234. if domainp u then errach list("Improper factors in factorf");
  235. % The example on rounded; solve(df(e^x/(e^(2*x)+1)^1.5,x),{x});
  236. % shows car v can be non-zero.
  237. w := car v;
  238. v := fctrf1 cdr v;
  239. if w then v := car v . (!*k2f car w . cdr w) . cdr v;
  240. m!-image!-variable := mvar u;
  241. u :=
  242. distribute!.multiplicity(factorize!-primitive!-polynomial u,1);
  243. setkorder old!-korder;
  244. if sign then u := (negf caar u . cdar u) . cdr u;
  245. u := fac!-merge(v,1 . u);
  246. return car u . for each w in cdr u collect (reorder car w . cdr w)
  247. end) where current!-modulus = current!-modulus;
  248. symbolic procedure factor!-prim!-sqfree!-f!-1(u,n);
  249. (exptf(car x,n) . for each j in cdr x collect (j . n))
  250. where x = prsqfrfacf u;
  251. symbolic procedure sqfrf u;
  252. % U is a non-trivial form which is primitive in all its variables
  253. % and has an overall numerical coefficient which should be a unit.
  254. % SQFRF performs square free factorization on U and returns a
  255. % form power list.
  256. % Modified to work properly in rounded (real or complex) modes. SLK.
  257. begin integer n; scalar !*gcd,units,v,w,x,y,z,!*msg,r;
  258. !*gcd := t;
  259. if (r := !*rounded) then
  260. <<on rational; u := numr resimp !*f2q u>>;
  261. n := 1;
  262. x := mvar u;
  263. v := gcdf(u,diff(u,x));
  264. u := quotf(u,v);
  265. % If domain is a field, or has non-trivial units, v can have a
  266. % spurious numerical factor.
  267. if flagp(dmode!*,'field) and ((y := lnc u) neq 1)
  268. then <<u := multd(!:recip y,u); v := multd(y,v)>>
  269. else if (units := get(dmode!*,'units))
  270. and (w := assoc(y:= lnc u,units))
  271. then <<u := multd(cdr w,u); v := multd(y,v)>>;
  272. while degr(v,x)>0 do
  273. <<w := gcdf(v,u);
  274. if u neq w then z := (quotf(u,w) . n) . z;
  275. % Don't add units to z.
  276. v := quotf(v,w);
  277. u := w;
  278. n := n + 1>>;
  279. if r then
  280. <<on rounded;
  281. u := numr resimp !*f2q u;
  282. z := for each j in z
  283. collect numr resimp !*f2q car j . cdr j>>;
  284. if v neq 1 and assoc(v,units) then v := 1;
  285. if v neq 1 then if n=1 then u := multf(v,u)
  286. else if (w := rassoc(1,z)) then rplaca(w,multf(v,car w))
  287. else if null z and not domainp v then z := {v . 1}
  288. else if null z and ((w := rootxf(v,n)) neq 'failed)
  289. then u := multf(w,u)
  290. else errach {"sqfrf failure",u,n,z};
  291. return (u . n) . z
  292. end;
  293. symbolic procedure sqfrf!* u; caar sqfrf u;
  294. symbolic procedure square_free u;
  295. 'list . for each v in sqfrf !*q2f simp!* u
  296. collect {'list,mk!*sq(car v . 1),cdr v};
  297. flag('(square_free),'opfn);
  298. symbolic procedure diff(u,v);
  299. % A polynomial differentation routine which does not check
  300. % indeterminate dependencies.
  301. if domainp u then nil
  302. else addf(addf(multpf(lpow u,diff(lc u,v)),
  303. multf(lc u,diffp1(lpow u,v))),
  304. diff(red u,v));
  305. symbolic procedure diffp1(u,v);
  306. if not( car u eq v) then nil
  307. else if cdr u=1 then 1
  308. else multd(cdr u,!*p2f(car u .** (cdr u-1)));
  309. endmodule;
  310. end;