facuni.red 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. module facuni;
  2. % Authors: A. C. Norman and P. M. A. Moore, 1979;
  3. fluid '(!*force!-prime
  4. !*trfac
  5. alphalist
  6. bad!-case
  7. best!-factor!-count
  8. best!-known!-factors
  9. best!-modulus
  10. best!-set!-pointer
  11. chosen!-prime
  12. factor!-level
  13. factor!-trace!-list
  14. forbidden!-primes
  15. hensel!-growth!-size
  16. input!-leading!-coefficient
  17. input!-polynomial
  18. irreducible
  19. known!-factors
  20. m!-image!-variable
  21. modular!-info
  22. no!-of!-best!-primes
  23. no!-of!-random!-primes
  24. non!-monic
  25. null!-space!-basis
  26. number!-of!-factors
  27. one!-complete!-deg!-analysis!-done
  28. poly!-mod!-p
  29. previous!-degree!-map
  30. reduction!-count
  31. split!-list
  32. target!-factor!-count
  33. univariate!-factors
  34. univariate!-input!-poly
  35. valid!-primes);
  36. symbolic procedure univariate!-factorize poly;
  37. % input poly a primitive square-free univariate polynomial at least
  38. % quadratic and with +ve lc. output is a list of the factors of poly
  39. % over the integers ;
  40. if testx!*!*n!+1 poly then
  41. factorizex!*!*n!+1(m!-image!-variable,ldeg poly,1)
  42. else if testx!*!*n!-1 poly then
  43. factorizex!*!*n!-1(m!-image!-variable,ldeg poly,1)
  44. else univariate!-factorize1 poly;
  45. symbolic procedure univariate!-factorize1 poly;
  46. begin scalar
  47. valid!-primes,univariate!-input!-poly,best!-set!-pointer,
  48. number!-of!-factors,irreducible,forbidden!-primes,
  49. no!-of!-best!-primes,no!-of!-random!-primes,bad!-case,
  50. target!-factor!-count,modular!-info,univariate!-factors,
  51. hensel!-growth!-size,alphalist,previous!-degree!-map,
  52. one!-complete!-deg!-analysis!-done,reduction!-count,
  53. multivariate!-input!-poly;
  54. %note that this code works by using a local database of
  55. %fluid variables that are updated by the subroutines directly
  56. %called here. this allows for the relativly complicated
  57. %interaction between flow of data and control that occurs in
  58. %the factorization algorithm;
  59. factor!-trace <<
  60. prin2!* "Univariate polynomial="; printsf poly;
  61. printstr
  62. "The polynomial is univariate, primitive and square-free";
  63. printstr "so we can treat it slightly more specifically. We";
  64. printstr "factorise mod several primes,then pick the best one";
  65. printstr "to use in the Hensel construction." >>;
  66. initialize!-univariate!-fluids poly;
  67. % set up the fluids to start things off;
  68. tryagain:
  69. get!-some!-random!-primes();
  70. choose!-the!-best!-prime();
  71. if irreducible then <<
  72. univariate!-factors:=list univariate!-input!-poly;
  73. goto exit >>
  74. else if bad!-case then <<
  75. bad!-case:=nil; goto tryagain >>;
  76. reconstruct!-factors!-over!-integers();
  77. if irreducible then <<
  78. univariate!-factors:=list univariate!-input!-poly;
  79. goto exit >>;
  80. exit:
  81. factor!-trace <<
  82. printstr "The univariate factors are:";
  83. for each ff in univariate!-factors do printsf ff >>;
  84. return univariate!-factors
  85. end;
  86. %**********************************************************************
  87. % univariate factorization part 1. initialization and setting fluids;
  88. symbolic procedure initialize!-univariate!-fluids u;
  89. % Set up the fluids to be used in factoring primitive poly;
  90. begin
  91. if !*force!-prime then <<
  92. no!-of!-random!-primes:=1;
  93. no!-of!-best!-primes:=1 >>
  94. else <<
  95. no!-of!-random!-primes:=5;
  96. % we generate this many modular images and calculate
  97. % their factor counts;
  98. no!-of!-best!-primes:=3;
  99. % we find the modular factors of this many;
  100. >>;
  101. univariate!-input!-poly:=u;
  102. target!-factor!-count:=ldeg u
  103. end;
  104. %**********************************************************************;
  105. % univariate factorization part 2. creating modular images and picking
  106. % the best one;
  107. symbolic procedure get!-some!-random!-primes();
  108. % here we create a number of random primes to reduce the input mod p;
  109. begin scalar chosen!-prime,poly!-mod!-p,i;
  110. valid!-primes:=mkvect no!-of!-random!-primes;
  111. i:=0;
  112. while i < no!-of!-random!-primes do <<
  113. poly!-mod!-p:=
  114. find!-a!-valid!-prime(lc univariate!-input!-poly,
  115. univariate!-input!-poly,nil);
  116. if not(poly!-mod!-p='not!-square!-free) then <<
  117. i:=iadd1 i;
  118. putv(valid!-primes,i,chosen!-prime . poly!-mod!-p);
  119. forbidden!-primes:=chosen!-prime . forbidden!-primes
  120. >>
  121. >>
  122. end;
  123. symbolic procedure choose!-the!-best!-prime();
  124. % given several random primes we now choose the best by factoring
  125. % the poly mod its chosen prime and taking one with the
  126. % lowest factor count as the best for hensel growth;
  127. begin scalar split!-list,poly!-mod!-p,null!-space!-basis,
  128. known!-factors,w,n;
  129. modular!-info:=mkvect no!-of!-random!-primes;
  130. for i:=1:no!-of!-random!-primes do <<
  131. w:=getv(valid!-primes,i);
  132. get!-factor!-count!-mod!-p(i,cdr w,car w,nil) >>;
  133. split!-list:=sort(split!-list,function lessppair);
  134. % this now contains a list of pairs (m . n) where
  135. % m is the no: of factors in set no: n. the list
  136. % is sorted with best split (smallest m) first;
  137. if caar split!-list = 1 then <<
  138. irreducible:=t; return nil >>;
  139. w:=split!-list;
  140. for i:=1:no!-of!-best!-primes do <<
  141. n:=cdar w;
  142. get!-factors!-mod!-p(n,car getv(valid!-primes,n));
  143. w:=cdr w >>;
  144. % pick the best few of these and find out their
  145. % factors mod p;
  146. split!-list:=delete(w,split!-list);
  147. % throw away the other sets;
  148. check!-degree!-sets(no!-of!-best!-primes,nil);
  149. % the best set is pointed at by best!-set!-pointer;
  150. one!-complete!-deg!-analysis!-done:=t;
  151. factor!-trace <<
  152. w:=getv(valid!-primes,best!-set!-pointer);
  153. prin2!* "The chosen prime is "; printstr car w;
  154. prin2!* "The polynomial mod "; prin2!* car w;
  155. printstr ", made monic, is:";
  156. printsf cdr w;
  157. printstr "and the factors of this modular polynomial are:";
  158. for each x in getv(modular!-info,best!-set!-pointer)
  159. do printsf x;
  160. >>
  161. end;
  162. %**********************************************************************;
  163. % univariate factorization part 3. reconstruction of the
  164. % chosen image over the integers;
  165. symbolic procedure reconstruct!-factors!-over!-integers();
  166. % the hensel construction from modular case to univariate
  167. % over the integers;
  168. begin scalar best!-modulus,best!-factor!-count,input!-polynomial,
  169. input!-leading!-coefficient,best!-known!-factors,s;
  170. s:=getv(valid!-primes,best!-set!-pointer);
  171. best!-known!-factors:=getv(modular!-info,best!-set!-pointer);
  172. input!-leading!-coefficient:=lc univariate!-input!-poly;
  173. best!-modulus:=car s;
  174. best!-factor!-count:=length best!-known!-factors;
  175. input!-polynomial:=univariate!-input!-poly;
  176. univariate!-factors:=reconstruct!.over!.integers();
  177. if irreducible then return t;
  178. number!-of!-factors:=length univariate!-factors;
  179. if number!-of!-factors=1 then return irreducible:=t
  180. end;
  181. symbolic procedure reconstruct!.over!.integers();
  182. begin scalar w,lclist,non!-monic;
  183. set!-modulus best!-modulus;
  184. for i:=1:best!-factor!-count do
  185. lclist:=input!-leading!-coefficient . lclist;
  186. if not (input!-leading!-coefficient=1) then <<
  187. best!-known!-factors:=
  188. for each ff in best!-known!-factors collect
  189. multf(input!-leading!-coefficient,!*mod2f ff);
  190. non!-monic:=t;
  191. factor!-trace <<
  192. printstr
  193. "(a) Now the polynomial is not monic so we multiply each";
  194. printstr
  195. "of the modular factors, f(i), by the absolute value of";
  196. prin2!* "the leading coefficient: ";
  197. prin2!* input!-leading!-coefficient; printstr '!.;
  198. printstr "To bring the polynomial into agreement with this, we";
  199. prin2!* "multiply it by ";
  200. if best!-factor!-count > 2 then
  201. << prin2!* input!-leading!-coefficient; prin2!* "**";
  202. printstr isub1 best!-factor!-count >>
  203. else printstr input!-leading!-coefficient >> >>;
  204. w:=uhensel!.extend(input!-polynomial,
  205. best!-known!-factors,lclist,best!-modulus);
  206. if irreducible then return t;
  207. if car w ='ok then return cdr w
  208. else errorf w
  209. end;
  210. % Now some special treatment for cyclotomic polynomials;
  211. symbolic procedure testx!*!*n!+1 u;
  212. not domainp u and (
  213. lc u=1 and
  214. red u = 1);
  215. symbolic procedure testx!*!*n!-1 u;
  216. not domainp u and (
  217. lc u=1 and
  218. red u = -1);
  219. symbolic procedure factorizex!*!*n!+1(var,degree,vorder);
  220. % Deliver factors of (VAR**VORDER)**DEGREE+1 given that it is
  221. % appropriate to treat VAR**VORDER as a kernel;
  222. if evenp degree then factorizex!*!*n!+1(var,degree/2,2*vorder)
  223. else begin
  224. scalar w;
  225. w := factorizex!*!*n!-1(var,degree,vorder);
  226. w := negf car w . cdr w;
  227. return for each p in w collect negate!-variable(var,2*vorder,p)
  228. end;
  229. symbolic procedure negate!-variable(var,vorder,p);
  230. % VAR**(VORDER/2) -> -VAR**(VORDER/2) in the polynomial P;
  231. if domainp p then p
  232. else if mvar p=var then
  233. if remainder(ldeg p,vorder)=0 then
  234. lt p .+ negate!-variable(var,vorder,red p)
  235. else (lpow p .* negf lc p) .+ negate!-variable(var,vorder,red p)
  236. else (lpow p .* negate!-variable(var,vorder,lc p)) .+
  237. negate!-variable(var,vorder,red p);
  238. symbolic procedure integer!-factors n;
  239. % Return integer factors of N, with attached multiplicities. Assumes
  240. % that N is fairly small;
  241. begin
  242. scalar l,q,m,w;
  243. % L is list of results generated so far, Q is current test divisor,
  244. % and M is associated multiplicity;
  245. if n=1 then return '((1 . 1));
  246. q := 2; m := 0;
  247. % Test divide by 2,3,5,7,9,11,13,...
  248. top:
  249. w := divide(n,q);
  250. while cdr w=0 do << n := car w; w := divide(n,q); m := m+1 >>;
  251. if not(m=0) then l := (q . m) . l;
  252. if q>car w then <<
  253. if not(n=1) then l := (n . 1) . l;
  254. return reversip l >>;
  255. % q := ilogor(1,iadd1 q);
  256. q := iadd1 q;
  257. if q #> 3 then q := iadd1 q;
  258. m := 0;
  259. go to top
  260. end;
  261. symbolic procedure factored!-divisors fl;
  262. % FL is an association list of primes and exponents. Return a list
  263. % of all subsets of this list, i.e. of numbers dividing the
  264. % original integer. Exclude '1' from the list;
  265. if null fl then nil
  266. else begin
  267. scalar l,w;
  268. w := factored!-divisors cdr fl;
  269. l := w;
  270. for i := 1:cdar fl do <<
  271. l := list (caar fl . i) . l;
  272. for each p in w do
  273. l := ((caar fl . i) . p) . l >>;
  274. return l
  275. end;
  276. symbolic procedure factorizex!*!*n!-1(var,degree,vorder);
  277. if evenp degree then append(factorizex!*!*n!+1(var,degree/2,vorder),
  278. factorizex!*!*n!-1(var,degree/2,vorder))
  279. else if degree=1 then list((mksp(var,vorder) .* 1) .+ (-1))
  280. else begin
  281. scalar facdeg;
  282. facdeg := '((1 . 1)) . factored!-divisors integer!-factors degree;
  283. return for each fl in facdeg
  284. collect cyclotomic!-polynomial(var,fl,vorder)
  285. end;
  286. symbolic procedure cyclotomic!-polynomial(var,fl,vorder);
  287. % Create Psi<degree>(var**order)
  288. % where degree is given by the association list of primes and
  289. % multiplicities FL;
  290. if not(cdar fl=1) then
  291. cyclotomic!-polynomial(var,(caar fl . sub1 cdar fl) . cdr fl,
  292. vorder*caar fl)
  293. else if cdr fl=nil then
  294. if caar fl=1 then (mksp(var,vorder) .* 1) .+ (-1)
  295. else quotfail((mksp(var,vorder*caar fl) .* 1) .+ (-1),
  296. (mksp(var,vorder) .* 1) .+ (-1))
  297. else quotfail(cyclotomic!-polynomial(var,cdr fl,vorder*caar fl),
  298. cyclotomic!-polynomial(var,cdr fl,vorder));
  299. endmodule;
  300. end;