specfac.red 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. module specfac; % Splitting of low degree polynomials.
  2. % Author: Anthony C. Hearn.
  3. % Copyright (c) 1991 RAND. All rights reserved.
  4. fluid '(!*keepsqrts !*sub2 !*surds knowndiscrimsign kord!* zlist);
  5. % switch surds;
  6. exports cubicf,quadraticf,quarticf;
  7. symbolic procedure coeffs pol;
  8. % Extract coefficients of polynomial wrt its main variable and leading
  9. % degree. Result is a list of coefficients.
  10. begin integer degree,deg1; scalar cofs,mv;
  11. mv := mvar pol;
  12. degree := ldeg pol;
  13. while not domainp pol and mvar pol eq mv do
  14. <<deg1 := ldeg pol;
  15. for i:= 1:(degree-deg1-1) do cofs := nil . cofs;
  16. cofs := lc pol . cofs;
  17. pol := red pol;
  18. degree := deg1>>;
  19. for i:=1:degree-1 do cofs := nil . cofs;
  20. return reversip(pol . cofs)
  21. end;
  22. symbolic procedure shift!-pol pol;
  23. % Shifts main variable, mv, of square free nth degree polynomial pol so
  24. % that coefficient of mv**(n-1) is zero.
  25. % Does not assume pol is univariate.
  26. begin scalar lc1,ld,mv,pol1,redp,shift,x;
  27. mv := mvar pol;
  28. ld := ldeg pol;
  29. redp := red pol;
  30. if domainp redp or not(mvar redp eq mv) or ldeg redp<(ld-1)
  31. then return list(pol,1,nil ./ 1);
  32. lc1 := lc pol;
  33. x := lc redp;
  34. shift := quotsq(!*f2q x,!*f2q multd(ld,lc1));
  35. pol1 := subf1(pol,list(mv . mk!*sq addsq(!*k2q mv,negsq shift)));
  36. return list(numr pol1,denr pol1,shift)
  37. end;
  38. symbolic procedure quadraticf!*(pol,var);
  39. if domainp pol then errach "invalid quadratic to factr"
  40. else if mvar pol = var then quadraticf pol
  41. else begin scalar kord,w;
  42. kord := kord!*;
  43. kord!* := list var;
  44. w := coeffs !*q2f resimp(pol ./ 1);
  45. kord!* := kord;
  46. w := quadraticf1(car w,cadr w,caddr w);
  47. if w eq 'failed then return list(1,pol);
  48. var := !*k2f var;
  49. return list(if car w neq 1 then mkrn(1,car w) else 1,
  50. addf(multf(var,cadr w),caddr w),
  51. addf(multf(var,cadddr w),car cddddr w))
  52. end;
  53. symbolic procedure quadraticf pol;
  54. % Finds factors of square free quadratic polynomial pol (if they
  55. % exist). Does not assume pol is univariate.
  56. (if x eq 'failed then list(1,pol)
  57. else if not domainp car x then list(1,pol)
  58. % Answer would be rational.
  59. else list(if car x neq 1 then mkrn(1,car x) else 1,
  60. y .* cadr x .+ caddr x,y .* cadddr x .+ car cddddr x)
  61. where y = (mvar pol .** 1))
  62. where x = quadraticf1(car w,cadr w,caddr w) where w = coeffs pol;
  63. symbolic procedure quadraticf1(a,b,c);
  64. begin scalar a1,denom,discrim,w;
  65. if null b and minusf c and not minusf a
  66. then <<a := rootxf(a,2);
  67. c := rootxf(negf c,2);
  68. return if a eq 'failed or c eq 'failed then 'failed
  69. else list(1,a,c,a,negf c)>>;
  70. discrim := powsubsf addf(exptf(b,2),multd(-4,multf(a,c)));
  71. % A null discriminator can arise from a polynomial such as
  72. % 16x^2+(32i-8)*x-8i-15;
  73. if null discrim then nil
  74. else <<if knowndiscrimsign
  75. then <<if knowndiscrimsign eq 'negative
  76. then return 'failed>>
  77. % else if not clogflag and minusf discrim
  78. % then return 'failed;
  79. else if minusf discrim then return 'failed;
  80. discrim:=rootxf(discrim,2);
  81. if discrim='failed then return discrim>>;
  82. denom := multd(4,a);
  83. a := a1 := multd(2,a);
  84. w := addf(b,discrim);
  85. c := addf(b,negf discrim);
  86. b := w;
  87. if (w := gcdf(a,b)) neq 1
  88. then <<a1 := quotf(a,w); b := quotf(b,w);
  89. denom := quotf(denom,w)>>;
  90. if (w := gcdf(a,denom)) neq 1 and (w := gcdf(c,denom))
  91. then <<a := quotf(a,w);
  92. c := quotf(c,w);
  93. denom := quotf(denom,w)>>;
  94. return list(denom,a1,b,a,c)
  95. end;
  96. symbolic procedure rootxf(u,n);
  97. % Return either polynomial nth root of u or "failed".
  98. begin scalar x,y,z,w;
  99. if domainp u
  100. then return if minusf u then 'failed
  101. else if atom u and (y := irootn(u,n))**n=u then y
  102. else if not atom u and (x := get(car u,'rootfn))
  103. then apply2(x,u,n)
  104. else if !*surds and not(u member zlist)
  105. then nrootn!*(u,n)
  106. else 'failed;
  107. x := comfac u;
  108. u := quotf(u,comfac!-to!-poly x);
  109. z := 1;
  110. if car x then if cdr(y := divide(cdar x,n)) = 0
  111. then z := multpf(caar x .** car y,z)
  112. else if !*surds
  113. then <<z := multf(mkrootf(caar x,n,cdr y),z);
  114. if car y neq 0
  115. then z := multpf(caar x .** car y,z)>>
  116. else return 'failed;
  117. x := cdr x;
  118. if domainp x
  119. then if minusf x then return 'failed
  120. else if fixp x and (y := irootn(x,n))**n=x
  121. then z := multd(y,z)
  122. else if !*surds and fixp x
  123. then z := multf(nrootn!*(x,n),z)
  124. else if not atom x and (w := get(car x,'rootfn))
  125. then apply2(w,x,n)
  126. else return 'failed
  127. else if (y := rootxf(x,n)) eq 'failed then return y
  128. else z := multf(y,z);
  129. if u=1 then return z;
  130. x := sqfrf u;
  131. c: if null x then return z
  132. else if cdr(y := divide(cdar x,n)) = 0
  133. then <<z := multf(exptf(caar x,car y),z); x := cdr x>>
  134. else if !*surds
  135. then <<z := multf(mkrootf(prepf caar x,n,cdr y),
  136. multf(exptf(caar x,car y),z));
  137. x := cdr x>>
  138. else return 'failed;
  139. go to c
  140. end;
  141. symbolic procedure mkrootf(u,m,n);
  142. if m neq 2 or null !*keepsqrts
  143. then !*p2f mksp(list('expt,u,list('quotient,1,m)),n)
  144. else if n neq 1 then errach 'mkrootf
  145. else !*q2f simpsqrt list u;
  146. symbolic procedure nrootn!*(u,n);
  147. % Returns a standard form representation of the nth root of u.
  148. begin scalar x;
  149. if null u then return nil;
  150. u := nrootn(u,n);
  151. x := cdr u; % surd part.
  152. u := car u; % rational part.
  153. if x=1 then return x;
  154. x := mkrootf(prepf x,n,1);
  155. return powsubsf multf(u,x)
  156. end;
  157. symbolic procedure cubicf pol;
  158. % Split the cubic pol if a change of origin puts it in the form
  159. % (x-a)**3-b=0.
  160. begin scalar a,a0,a1,b,neg,p;
  161. p := shift!-pol pol;
  162. a := coeffs car p;
  163. if cadr a then return list(1,pol)
  164. % Cadr a non nil probably means there are some surds in the
  165. % coefficients that don't reduce to 0.
  166. else if caddr a then return list(1,pol);
  167. % Factorization not possible by this method.
  168. a0 := cadddr a;
  169. a := car a;
  170. if minusf a0 then <<neg := t; a0 := negf a0>>;
  171. if (a := rootxf(a,3)) eq 'failed
  172. or (a0 := rootxf(a0,3)) eq 'failed
  173. then return list(1,pol);
  174. if neg then a0 := negf a0;
  175. a := !*f2q a;
  176. a0 := !*f2q a0;
  177. p := addsq(!*k2q mvar pol,caddr p);
  178. % Now numr (a*(mv+shift)+a0) is a factor of pol.
  179. a1 := numr addsq(multsq(a,p),a0);
  180. % quotf(pol,a) is quadratic factor. However, the surd division may
  181. % not work properly, so we calculate factor directly.
  182. b := multsq(a0,a0);
  183. b := addsq(b,multsq(negsq multsq(a,a0),p));
  184. b := numr addsq(b,multsq(multsq(a,a),exptsq(p,2)));
  185. return aconc!*(quadraticf b,a1)
  186. end;
  187. symbolic procedure powsubsf u;
  188. % We believe that the result of this operation must be a polynomial.
  189. % If subs2q returns a rational, it must be because there are
  190. % unsimplified surds. Hopefully rationalizesq can fix those.
  191. begin scalar !*sub2;
  192. u := subs2q !*f2q u;
  193. if denr u neq 1
  194. then <<u := rationalizesq u;
  195. if denr u neq 1 then errach list('powsubsf,u)>>;
  196. return numr u
  197. end;
  198. symbolic procedure quarticf pol;
  199. % Splits quartics that can be written in the form
  200. % (x-a)**4+b*(x-a)**2+c.
  201. % Note that any call of rootxf can lead to a result "failed."
  202. begin scalar !*sub2,a,a2,a0,b,dsc,p,p1,p2,q,shift,var;
  203. var := mvar pol;
  204. p := shift!-pol pol;
  205. a := coeffs car p;
  206. shift := caddr p;
  207. if cadr a % pol not correctly shifted, possibly due to sqrt.
  208. % e.g., 729para^4*be^4 - 81para^3*sqrt(27*be^2*para^2 - 8cte1^3)*
  209. % sqrt(3)*be^3 - 216para^2*be^2*cte1^3 + 12para*sqrt(27be^2*para^2
  210. % - 8*cte1^3)*sqrt(3) *be*cte1^3 + 8*cte1^6.
  211. or cadddr a then return list(1,pol);
  212. % Factorization not possible by this method.
  213. a2 := cddr a;
  214. a0 := caddr a2;
  215. a2 := car a2;
  216. a := car a;
  217. q := quadraticf1(a,a2,a0);
  218. if not(q eq 'failed)
  219. then <<a2 := car q; q := cdr q;
  220. a := exptsq(addsq(!*k2q mvar pol,shift),2);
  221. b := numr subs2q quotsq(addsq(multsq(!*f2q car q,a),
  222. !*f2q cadr q),
  223. !*f2q cadr p);
  224. a := numr subs2q quotsq(addsq(multsq(!*f2q caddr q,a),
  225. !*f2q cadddr q),
  226. !*f2q cadr p);
  227. a := quadraticf!*(a,var);
  228. b := quadraticf!*(b,var);
  229. return multf(a2,multf(car a,car b))
  230. . nconc!*(cdr a,cdr b)>>
  231. else if null !*surds or denr shift neq 1
  232. then return list(1,pol);
  233. % Factorization not possible by this method.
  234. shift := numr shift;
  235. if knowndiscrimsign eq 'negative then go to complex;
  236. dsc := powsubsf addf(exptf(a2,2),multd(-4,multf(a,a0)));
  237. p2 := minusf a0;
  238. if not p2 and minusf dsc then go to complex;
  239. p1 := not a2 or minusf a2;
  240. if not p1 then if p2 then p1 := t else p2 := t;
  241. p1 := if p1 then 'positive else 'negative;
  242. p2 := if p2 then 'negative else 'positive;
  243. a := rootxf(a,2);
  244. if a eq 'failed then return list(1,pol);
  245. dsc := rootxf(dsc,2);
  246. if dsc eq 'failed then return list(1,pol);
  247. p := invsq !*f2q addf(a,a);
  248. q := multsq(!*f2q addf(a2,negf dsc),p);
  249. p := multsq(!*f2q addf(a2,dsc),p);
  250. b := multf(a,exptf(addf(!*k2f mvar pol,shift),2));
  251. a := powsubsf addf(b,q);
  252. b := powsubsf addf(b,p);
  253. knowndiscrimsign := p1;
  254. a := quadraticf!*(a,var);
  255. knowndiscrimsign := p2;
  256. b := quadraticf!*(b,var);
  257. knowndiscrimsign := nil;
  258. return multf(car a,car b) . nconc!*(cdr a,cdr b);
  259. % Complex case.
  260. complex:
  261. a := rootxf(a,2);
  262. if a eq 'failed then return list(1,pol);
  263. a0 := rootxf(a0,2);
  264. if a0 eq 'failed then return list(1,pol);
  265. a2 := powsubsf addf(multf(2,multf(a,a0)),negf a2);
  266. a2 := rootxf(a2,2);
  267. if a2 eq 'failed then return list(1,pol);
  268. % Now a*(x+shift)**2 (+/-) b*(x+shift) + c is a factor.
  269. p := addf(!*k2f mvar pol,shift);
  270. q := addf(multf(a,exptf(p,2)),a0);
  271. p := multf(a2,p);
  272. a := powsubsf addf(q,p);
  273. b := powsubsf addf(q,negf p);
  274. knowndiscrimsign := 'negative;
  275. a := quadraticf!*(a,var);
  276. b := quadraticf!*(b,var);
  277. knowndiscrimsign := nil;
  278. return multf(car a,car b) . nconc!*(cdr a,cdr b)
  279. end;
  280. endmodule;
  281. end;