unihens.red 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052
  1. module unihens; % Univariate case of Hensel code with quadratic growth.
  2. % Author: P. M. A. Moore, 1979.
  3. % Modifications by J.H. Davenport 1988 following a 1985 draft by Abbott,
  4. % Bradford and Davenport.
  5. fluid '(!*linear
  6. !*overshoot
  7. !*overview
  8. !*trfac
  9. alphalist
  10. alphavec
  11. coefftbd
  12. current!-factor!-product
  13. current!-modulus
  14. delfvec
  15. deltam
  16. factor!-level
  17. factor!-trace!-list
  18. factors!-done
  19. factorvec
  20. facvec
  21. fhatvec
  22. hensel!-growth!-size
  23. hensel!-poly
  24. irreducible
  25. m!-image!-variable
  26. modfvec
  27. multivariate!-input!-poly
  28. non!-monic
  29. number!-of!-factors
  30. polyzero
  31. prime!-base
  32. reconstructing!-gcd);
  33. global '(largest!-small!-modulus);
  34. symbolic procedure uhensel!.extend(poly,best!-flist,lclist,p);
  35. % Extend poly=product(factors in best!-flist) mod p even if poly is
  36. % non-monic. Return a list (ok. list of factors) if factors can be
  37. % extended to be correct over the integers, otherwise return a list
  38. % (failed <reason> <reason>).
  39. begin scalar w,k,old!-modulus,alphavec,modular!-flist,factorvec,
  40. modfvec,coefftbd,fcount,fhatvec,deltam,mod!-symm!-flist,
  41. current!-factor!-product,facvec,factors!-done,hensel!-poly;
  42. prime!-base:=p;
  43. old!-modulus:=set!-modulus p;
  44. % timer:=readtime();
  45. number!-of!-factors:=length best!-flist;
  46. w:=expt(lc poly,number!-of!-factors -1);
  47. if lc poly < 0 then errorf list("LC SHOULD NOT BE -VE",poly);
  48. coefftbd:=max(110,p+1,lc poly*get!-coefft!-bound(poly,ldeg poly));
  49. poly:=multf(poly,w);
  50. modular!-flist:=for each ff in best!-flist collect
  51. reduce!-mod!-p ff;
  52. % Modular factors have been multiplied by a constant to
  53. % fix the l.c.'s, so they may be out of range - this
  54. % fixes that.
  55. if not(w=1) then factor!-trace <<
  56. prin2!* "Altered univariate polynomial: "; printsf poly >>;
  57. % Make sure the leading coefft will not cause trouble
  58. % in the hensel construction.
  59. mod!-symm!-flist:=for each ff in modular!-flist collect
  60. make!-modular!-symmetric ff;
  61. if not !*overview then factor!-trace <<
  62. prin2!* "The factors mod "; prin2!* p;
  63. printstr " to start from are:";
  64. fcount:=1;
  65. for each ff in mod!-symm!-flist do <<
  66. prin2!* " f("; prin2!* fcount; prin2!* ")=";
  67. printsf ff; fcount:=iadd1 fcount >>;
  68. terpri!*(nil) >>;
  69. alphalist:=alphas(number!-of!-factors,modular!-flist,1);
  70. % 'magic' polynomials associated with the image factors.
  71. if not !*overview then factor!-trace <<
  72. printstr
  73. "The following modular polynomials are chosen such that:";
  74. terpri();
  75. prin2!* " a(1)*h(1) + ... + a(";
  76. prin2!* number!-of!-factors;
  77. prin2!* ")*h("; prin2!* number!-of!-factors;
  78. prin2!* ") = 1 mod "; printstr p;
  79. terpri();
  80. printstr " where h(i)=(product of all f(j) [see below])/f(i)";
  81. printstr " and degree of a(i) < degree of f(i).";
  82. fcount:=1;
  83. for each a in modular!-flist do <<
  84. prin2!* " a("; prin2!* fcount; prin2!* ")=";
  85. printsf cdr get!-alpha a;
  86. prin2!* " f("; prin2!* fcount; prin2!* ")=";
  87. printsf a;
  88. fcount:=iadd1 fcount >>
  89. >>;
  90. k:=0;
  91. factorvec:=mkvect number!-of!-factors;
  92. modfvec:=mkvect number!-of!-factors;
  93. alphavec:=mkvect number!-of!-factors;
  94. for each modsymmf in mod!-symm!-flist do
  95. << putv(factorvec,k:=k+1,force!-lc(modsymmf,car lclist));
  96. lclist:=cdr lclist
  97. >>;
  98. k:=0;
  99. for each modfactor in modular!-flist do
  100. << putv(modfvec,k:=k+1,modfactor);
  101. putv(alphavec,k,cdr get!-alpha modfactor);
  102. >>;
  103. % best!-fvec is now a vector of factors of poly correct
  104. % mod p with true l.c.s forced in.
  105. fhatvec:=mkvect number!-of!-factors;
  106. w:=hensel!-mod!-p(poly,modfvec,factorvec,coefftbd,nil,p);
  107. if car w='overshot then w := uhensel!.extend1(poly,w)
  108. else w := uhensel!.extend2 w;
  109. set!-modulus old!-modulus;
  110. if irreducible then <<
  111. factor!-trace
  112. printstr "Two factors and overshooting means irreducible";
  113. return t >>;
  114. factor!-trace begin scalar k;
  115. k:=0;
  116. printstr "Univariate factors, possibly with adjusted leading";
  117. printstr "coefficients, are:";
  118. for each ww in cdr w do <<
  119. prin2!* " f("; prin2!* (k:=k #+ 1);
  120. prin2!* ")="; printsf ww >>
  121. end;
  122. return if non!-monic then
  123. (car w . primitive!.parts(cdr w,m!-image!-variable,t))
  124. else w
  125. end;
  126. symbolic procedure uhensel!.extend1(poly,w);
  127. begin scalar oklist,badlist,m,r,ff,om,pol;
  128. m:=cadr w; % the modulus.
  129. r:=getv(factorvec,0); % the number of factors.
  130. if r=2 then return (irreducible:=t);
  131. if factors!-done then <<
  132. poly:=hensel!-poly;
  133. for each ww in factors!-done do
  134. poly:=multf(poly,ww) >>;
  135. pol:=poly;
  136. om:=set!-modulus hensel!-growth!-size;
  137. alphalist:=nil;
  138. for i:=r step -1 until 1 do
  139. alphalist:=
  140. (reduce!-mod!-p getv(factorvec,i) . getv(alphavec,i))
  141. . alphalist;
  142. set!-modulus om;
  143. % bring alphalist up to date.
  144. for i:=1:r do <<
  145. ff:=getv(factorvec,i);
  146. if not didntgo(w:=quotf(pol,ff)) then
  147. << oklist:=ff . oklist; pol:=w>>
  148. else badlist:=(i . ff) . badlist >>;
  149. if null badlist then w:='ok . oklist
  150. else <<
  151. if not !*overview then factor!-trace <<
  152. printstr "Overshot factors are:";
  153. for each f in badlist do <<
  154. prin2!* " f("; prin2!* car f; prin2!* ")=";
  155. printsf cdr f >>
  156. >>;
  157. w:=try!.combining(badlist,pol,m,nil);
  158. if car w='one! bad! factor then begin scalar x;
  159. w:=append(oklist,cdr w);
  160. x:=1;
  161. for each v in w do x:=multf(x,v);
  162. w:='ok . (quotfail(pol,x) . w)
  163. end
  164. else w:='ok . append(oklist,w) >>;
  165. if (not !*linear) and multivariate!-input!-poly then <<
  166. poly:=1;
  167. number!-of!-factors:=0;
  168. for each facc in cdr w do <<
  169. poly:=multf(poly,facc);
  170. number!-of!-factors:=1 #+ number!-of!-factors >>;
  171. % make sure poly is the product of the factors we have,
  172. % we recalculate it this way because we may have the wrong
  173. % lc in old value of poly.
  174. reset!-quadratic!-step!-fluids(poly,cdr w,
  175. number!-of!-factors);
  176. if m=deltam then errorf list("Coefft bound < prime ?",
  177. coefftbd,m);
  178. m:=deltam*deltam;
  179. while m<largest!-small!-modulus do <<
  180. quadratic!-step(m,number!-of!-factors);
  181. m:=m*deltam >>;
  182. hensel!-growth!-size:=deltam;
  183. om:=set!-modulus hensel!-growth!-size;
  184. alphalist:=nil;
  185. for i:=number!-of!-factors step -1 until 1 do
  186. alphalist:=
  187. (reduce!-mod!-p getv(factorvec,i) . getv(alphavec,i))
  188. . alphalist;
  189. set!-modulus om >>;
  190. return w
  191. end;
  192. symbolic procedure uhensel!.extend2 w;
  193. begin scalar r,faclist,om;
  194. r:=getv(factorvec,0); % no of factors.
  195. om:=set!-modulus hensel!-growth!-size;
  196. alphalist:=nil;
  197. for i:=r step -1 until 1 do
  198. alphalist:=(reduce!-mod!-p getv(factorvec,i) . getv(alphavec,i))
  199. . alphalist;
  200. set!-modulus om;
  201. % bring alphalist up to date.
  202. for i:=r step -1 until 1 do
  203. faclist:=getv(factorvec,i) . faclist;
  204. return (car w . faclist)
  205. end;
  206. symbolic procedure get!-coefft!-bound(poly,ddeg);
  207. % This uses Mignotte's bound which is minimal I believe.
  208. % NB. poly had better be univariate as bound only valid for this.
  209. binomial!-coefft(ddeg/2,ddeg/4) * root!-squares(poly,0);
  210. symbolic procedure binomial!-coefft(n,r);
  211. if n<r then nil
  212. else if n=r then 1
  213. else if r=1 then n
  214. else begin scalar n!-c!-r,b;
  215. n!-c!-r:=1;
  216. b:=min(r,n-r);
  217. for i:=1:b do
  218. n!-c!-r:=(n!-c!-r * (n - i + 1)) / i;
  219. return n!-c!-r
  220. end;
  221. symbolic procedure find!-alphas!-in!-a!-ring(n,mflist,fhatlist,gamma);
  222. % Find the alphas (as below) given that the modulus may not be prime
  223. % but is a prime power.
  224. begin scalar gg,m,ppow,i,gg!-mod!-p,modflist,wvec,alpha,alphazeros,w;
  225. if null prime!-base then errorf
  226. list("Prime base not set for finding alphas",
  227. current!-modulus,n,mflist);
  228. m:=set!-modulus prime!-base;
  229. modflist:= if m=prime!-base then mflist
  230. else for each fthing in mflist collect
  231. reduce!-mod!-p !*mod2f fthing;
  232. alphalist:=alphas(n,modflist,gamma);
  233. if m=prime!-base then <<
  234. set!-modulus m;
  235. return alphalist >>;
  236. i:=0;
  237. alphazeros:=mkvect n;
  238. wvec:=mkvect n;
  239. for each modfthing in modflist do <<
  240. putv(modfvec,i:=iadd1 i,modfthing);
  241. putv(alphavec,i,!*f2mod(alpha:=cdr get!-alpha modfthing));
  242. putv(alphazeros,i,alpha);
  243. putv(wvec,i,alpha);
  244. putv(fhatvec,i,car fhatlist);
  245. fhatlist:=cdr fhatlist >>;
  246. gg:=gamma;
  247. ppow:=prime!-base;
  248. while ppow<m do <<
  249. set!-modulus m;
  250. gg:=!*f2mod quotfail(!*mod2f difference!-mod!-p(gg,
  251. form!-sum!-and!-product!-mod!-m(wvec,fhatvec,n)),prime!-base);
  252. set!-modulus prime!-base;
  253. gg!-mod!-p:=reduce!-mod!-p !*mod2f gg;
  254. for k:=1:n do <<
  255. putv(wvec,k,w:=remainder!-mod!-p(
  256. times!-mod!-p(getv(alphazeros,k),gg!-mod!-p),
  257. getv(modfvec,k)));
  258. putv(alphavec,k,addf(getv(alphavec,k),multf(!*mod2f w,ppow)))>>;
  259. ppow:=ppow*prime!-base >>;
  260. set!-modulus m;
  261. i:=0;
  262. return (for each fthing in mflist collect
  263. (fthing . !*f2mod getv(alphavec,i:=iadd1 i)))
  264. end;
  265. symbolic procedure alphas(n,flist,gamma);
  266. % Finds alpha,beta,delta,... wrt factors f(i) in flist s.t.
  267. % alpha*g(1) + beta*g(2) + delta*g(3) + ... = gamma mod p,
  268. % where g(i)=product(all the f(j) except f(i) itself).
  269. % (cf. xgcd!-mod!-p below). n is number of factors in flist.
  270. if n=1 then list(car flist . gamma)
  271. else begin scalar k,w,f1,f2,i,gamma1,gamma2;
  272. k:=n/2;
  273. f1:=1; f2:=1;
  274. i:=1;
  275. for each f in flist do
  276. << if i>k then f2:=times!-mod!-p(f,f2)
  277. else f1:=times!-mod!-p(f,f1);
  278. i:=i+1 >>;
  279. w:=xgcd!-mod!-p(f1,f2,1,polyzero,polyzero,1);
  280. if atom w then
  281. return 'factors! not! coprime;
  282. gamma1:=remainder!-mod!-p(times!-mod!-p(cdr w,gamma),f1);
  283. gamma2:=remainder!-mod!-p(times!-mod!-p(car w,gamma),f2);
  284. i:=1; f1:=nil; f2:=nil;
  285. for each f in flist do
  286. << if i>k then f2:=f . f2
  287. else f1:=f . f1;
  288. i:=i+1 >>;
  289. return append(
  290. alphas(k,f1,gamma1),
  291. alphas(n-k,f2,gamma2))
  292. end;
  293. symbolic procedure xgcd!-mod!-p(a,b,x1,y1,x2,y2);
  294. % Finds alpha and beta s.t. alpha*a+beta*b=1.
  295. % Returns alpha . beta or nil if a and b are not coprime.
  296. if null b then nil
  297. else if domainp b then begin
  298. b:=modular!-reciprocal b;
  299. x2:=multiply!-by!-constant!-mod!-p(x2,b);
  300. y2:=multiply!-by!-constant!-mod!-p(y2,b);
  301. return x2 . y2 end
  302. else begin scalar q;
  303. q:=quotient!-mod!-p(a,b); % Truncated quotient here.
  304. return xgcd!-mod!-p(b,difference!-mod!-p(a,times!-mod!-p(b,q)),
  305. x2,y2,
  306. difference!-mod!-p(x1,times!-mod!-p(x2,q)),
  307. difference!-mod!-p(y1,times!-mod!-p(y2,q)))
  308. end;
  309. symbolic procedure hensel!-mod!-p(poly,mvec,fvec,cbd,vset,p);
  310. % Hensel construction building up in powers of p.
  311. % Given that poly=product(factors in factorvec) mod p, find the full
  312. % factors over the integers. Mvec contains the univariate factors mod p
  313. % while fvec contains our best knowledge of the factors to date.
  314. % Fvec includes leading coeffts (and in multivariate case possibly other
  315. % coeffts) of the factors. return a list whose first element is a flag
  316. % with one of the following values:
  317. % ok construction worked, the cdr of the result is a list of
  318. % the correct factors.
  319. % failed inputs must have been incorrect
  320. % overshot factors are correct mod some power of p (say p**m),
  321. % but are not correct over the integers.
  322. % result is (overshot,p**m,list of factors so far).
  323. begin scalar w,u0,delfvec,old!.mod,res,m;
  324. u0:=initialize!-hensel(number!-of!-factors,p,poly,mvec,fvec,cbd);
  325. % u0 contains the product (over integers) of factors mod p.
  326. m := p;
  327. old!.mod := set!-modulus nil;
  328. if number!-of!-factors=1
  329. then <<putv(fvec,1,current!-factor!-product:=poly);
  330. % Added JHD 28.9.87
  331. return hensel!-exit(m,old!.mod,p,vset,w)>>;
  332. % only one factor to grow! but need to go this deep to
  333. % construct the alphas and set things up for the
  334. % multivariate growth which may follow.
  335. hensel!-msg1(p,u0);
  336. old!.mod:=set!-modulus p;
  337. res:=addf(hensel!-poly,negf u0);
  338. % calculate the residue. from now on this is always
  339. % kept in res.
  340. m:=p;
  341. % measure of how far we have built up factors - at this
  342. % stage we know the constant terms mod p in the factors.
  343. a: if polyzerop res then return hensel!-exit(m,old!.mod,p,vset,w);
  344. if (m/2)>coefftbd then
  345. <<
  346. % we started with a false split of the image so some
  347. % of the factors we have built up must amalgamate in
  348. % the complete factorization.
  349. if !*overshoot then <<
  350. prin2 if null vset then "Univariate " else "Multivariate ";
  351. prin2t "coefft bound overshoot" >>;
  352. if not !*overview then
  353. factor!-trace printstr "We have overshot the coefficient bound";
  354. return hensel!-exit(m,old!.mod,p,vset,'overshot)>>;
  355. res:=quotfail(res,deltam);
  356. % next term in residue.
  357. if not !*overview then factor!-trace <<
  358. prin2!* "Residue divided by "; prin2!* m; prin2!* " is ";
  359. printsf res >>;
  360. if (not !*linear) and null vset
  361. and m<=largest!-small!-modulus and m>p then
  362. quadratic!-step(m,number!-of!-factors);
  363. w:=reduce!-mod!-p res;
  364. if not !*overview then factor!-trace <<
  365. prin2!* "Next term in residue to kill is:";
  366. prinsf w; prin2!* " which is of size ";
  367. printsf (deltam*m);
  368. >>;
  369. solve!-for!-corrections(w,fhatvec,modfvec,delfvec,vset);
  370. % delfvec is vector of next correction terms to factors.
  371. make!-vec!-modular!-symmetric(delfvec,number!-of!-factors);
  372. if not !*overview then factor!-trace <<
  373. printstr "Correction terms are:";
  374. w:=1;
  375. for i:=1:number!-of!-factors do <<
  376. prin2!* " To f("; prin2!* w; prin2!* "): ";
  377. printsf multf(m,getv(delfvec,i));
  378. w:=iadd1 w >>;
  379. >>;
  380. w:=terms!-done(factorvec,delfvec,m);
  381. res:=addf(res,negf w);
  382. % subtract out the terms generated by these corrections
  383. % from the residue.
  384. current!-factor!-product:=
  385. addf(current!-factor!-product,multf(m,w));
  386. % add in the correction terms to give new factor product.
  387. for i:=1:number!-of!-factors do
  388. putv(factorvec,i,
  389. addf(getv(factorvec,i),multf(getv(delfvec,i),m)));
  390. % add the corrections into the factors.
  391. if not !*overview then factor!-trace <<
  392. printstr " giving new factors as:";
  393. w:=1;
  394. for i:=1:number!-of!-factors do <<
  395. prin2!* " f("; prin2!* w; prin2!* ")=";
  396. printsf getv(factorvec,i); w:=iadd1 w >>
  397. >>;
  398. m:=m*deltam;
  399. if not polyzerop res and null vset and
  400. not reconstructing!-gcd then
  401. begin scalar j,u,fac;
  402. j:=0;
  403. while (j:=j #+ 1)<=number!-of!-factors do
  404. % IF NULL GETV(DELFVEC,J) AND
  405. % - Try dividing out every time for now.
  406. if not didntgo
  407. (u:=quotf(hensel!-poly,fac:=getv(factorvec,j))) then <<
  408. hensel!-poly:=u;
  409. res:=adjust!-growth(fac,j,m);
  410. j:=number!-of!-factors >>
  411. end;
  412. go to a
  413. end;
  414. symbolic procedure hensel!-exit(m,old!.mod,p,vset,w);
  415. begin
  416. if factors!-done then <<
  417. if not(w='overshot) then m:=p*p;
  418. set!-hensel!-fluids!-back p >>;
  419. if (not (w='overshot)) and null vset
  420. and (not !*linear) and multivariate!-input!-poly then
  421. while m<largest!-small!-modulus do <<
  422. if not(m=deltam) then quadratic!-step(m,number!-of!-factors);
  423. m:=m*deltam >>;
  424. % set up the alphas etc so that multivariate growth can
  425. % use a Hensel growth size of about word size.
  426. set!-modulus old!.mod;
  427. % reset the old modulus.
  428. hensel!-growth!-size:=deltam;
  429. putv(factorvec,0,number!-of!-factors);
  430. return
  431. if w='overshot then list('overshot,m,factorvec)
  432. else 'ok . factorvec
  433. end;
  434. symbolic procedure hensel!-msg1(p,u0);
  435. begin scalar w;
  436. factor!-trace <<
  437. printstr
  438. "We are now ready to use the Hensel construction to grow";
  439. prin2!* "in powers of "; printstr current!-modulus;
  440. if not !*overview then <<prin2!* "Polynomial to factor (=U): ";
  441. printsf hensel!-poly>>;
  442. prin2!* "Initial factors mod "; prin2!* p;
  443. printstr " with some correct coefficients:";
  444. w:=1;
  445. for i:=1:number!-of!-factors do <<
  446. prin2!* " f("; prin2!* w; prin2!* ")=";
  447. printsf getv(factorvec,i); w:=iadd1 w >>;
  448. if not !*overview then << prin2!* "Coefficient bound = ";
  449. prin2!* coefftbd;
  450. terpri!*(nil);
  451. prin2!* "The product of factors over the integers is ";
  452. printsf u0;
  453. printstr "In each step below, the residue is U - (product of the";
  454. printstr
  455. "factors as far as we know them). The correction to each";
  456. printstr "factor, f(i), is (a(i)*v) mod f0(i) where f0(i) is";
  457. prin2!* "f(i) mod "; prin2!* p;
  458. printstr "(ie. the f(i) used in calculating the a(i))"
  459. >>>>
  460. end;
  461. symbolic procedure initialize!-hensel(r,p,poly,mvec,fvec,cbd);
  462. % Set up the vectors and initialize the fluids.
  463. begin scalar u0;
  464. delfvec:=mkvect r;
  465. facvec:=mkvect r;
  466. hensel!-poly:=poly;
  467. modfvec:=mvec;
  468. factorvec:=fvec;
  469. coefftbd:=cbd;
  470. factors!-done:=nil;
  471. deltam:=p;
  472. u0:=1;
  473. for i:=1:r do u0:=multf(getv(factorvec,i),u0);
  474. current!-factor!-product:=u0;
  475. return u0
  476. end;
  477. % symbolic procedure reset!-quadratic!-step!-fluids(poly,faclist,n);
  478. % begin scalar i,om,modf;
  479. % current!-factor!-product:=poly;
  480. % om:=set!-modulus hensel!-growth!-size;
  481. % i:=0;
  482. % for each fac in faclist do <<
  483. % putv(factorvec,i:=iadd1 i,fac);
  484. % putv(modfvec,i,modf:=reduce!-mod!-p fac);
  485. % putv(alphavec,i,cdr get!-alpha modf) >>;
  486. % for i:=1:n do <<
  487. % prin2 "F("; % prin2 i; % prin2 ") = ";
  488. % printsf getv(factorvec,i);
  489. % prin2 "F("; % prin2 i; % prin2 ") MOD P = ";
  490. % printsf getv(modfvec,i);
  491. % prin2 "A("; % prin2 i; % prin2 ") = ";
  492. % printsf getv(alphavec,i) >>;
  493. % set!-modulus om
  494. % end;
  495. symbolic procedure reset!-quadratic!-step!-fluids(poly,faclist,n);
  496. begin scalar i,om,facpairlist,cfp!-mod!-p,fhatlist;
  497. current!-factor!-product:=poly;
  498. om:=set!-modulus hensel!-growth!-size;
  499. cfp!-mod!-p:=reduce!-mod!-p current!-factor!-product;
  500. i:=0;
  501. facpairlist:=for each fac in faclist collect <<
  502. i:= i #+ 1;
  503. (fac . reduce!-mod!-p fac) >>;
  504. fhatlist:=for each facc in facpairlist collect
  505. quotfail!-mod!-p(cfp!-mod!-p,cdr facc);
  506. if factors!-done then alphalist:=
  507. find!-alphas!-in!-a!-ring(i,
  508. for each facpr in facpairlist collect cdr facpr,
  509. fhatlist,1);
  510. % a bug has surfaced such that the alphas get out of step.
  511. % In this case so recalculate them to stop the error for now.
  512. i:=0;
  513. for each facpair in facpairlist do <<
  514. putv(factorvec,i:=iadd1 i,car facpair);
  515. putv(modfvec,i,cdr facpair);
  516. putv(alphavec,i,cdr get!-alpha cdr facpair) >>;
  517. % for i:=1:n do <<
  518. % prin2 "f("; % prin2 i; % prin2 ") = ";
  519. % printsf getv(factorvec,i);
  520. % prin2 "f("; % prin2 i; % prin2 ") mod p = ";
  521. % printsf getv(modfvec,i);
  522. % prin2 "a("; % prin2 i; % prin2 ") = ";
  523. % printsf getv(alphavec,i) >>;
  524. set!-modulus om
  525. end;
  526. symbolic procedure quadratic!-step(m,r);
  527. % Code for adjusting the hensel variables to take quadratic steps in
  528. % the growing process.
  529. begin scalar w,s,cfp!-mod!-p;
  530. set!-modulus m;
  531. cfp!-mod!-p:=reduce!-mod!-p current!-factor!-product;
  532. for i:=1:r do putv(facvec,i,reduce!-mod!-p getv(factorvec,i));
  533. for i:=1:r do putv(fhatvec,i,
  534. quotfail!-mod!-p(cfp!-mod!-p,getv(facvec,i)));
  535. w:=form!-sum!-and!-product!-mod!-m(alphavec,fhatvec,r);
  536. w:=!*mod2f plus!-mod!-p(1,minus!-mod!-p w);
  537. s:=quotfail(w,deltam);
  538. set!-modulus deltam;
  539. s:=!*f2mod s;
  540. % Boxes S up to look like a poly mod deltam.
  541. for i:=1:r do <<
  542. w:=remainder!-mod!-p(times!-mod!-p(s,getv(alphavec,i)),
  543. getv(modfvec,i));
  544. putv(alphavec,i,
  545. addf(!*mod2f getv(alphavec,i),multf(!*mod2f w,deltam))) >>;
  546. s:=modfvec;
  547. modfvec:=facvec;
  548. facvec:=s;
  549. deltam:=m;
  550. % this is our new growth rate.
  551. set!-modulus deltam;
  552. for i:=1:r do <<
  553. putv(facvec,i,"RUBBISH");
  554. % we will want to overwrite facvec next time so we
  555. % had better point it to the old (no longer needed)
  556. % modvec. Also mark it as containing rubbish for safety.
  557. putv(alphavec,i,!*f2mod getv(alphavec,i)) >>;
  558. % Make sure the alphas are boxed up as being mod new deltam.
  559. if not !*overview then factor!-trace <<
  560. printstr "The new modular polynomials are chosen such that:";
  561. terpri();
  562. prin2!* " a(1)*h(1) + ... + a(";
  563. prin2!* r;
  564. prin2!* ")*h("; prin2!* r;
  565. prin2!* ") = 1 mod "; printstr m;
  566. terpri();
  567. printstr " where h(i)=(product of all f(j) [see below])/f(i)";
  568. printstr " and degree of a(i) < degree of f(i).";
  569. for i:=1:r do <<
  570. prin2!* " a("; prin2!* i; prin2!* ")=";
  571. printsf getv(alphavec,i);
  572. prin2!* " f("; prin2!* i; prin2!* ")=";
  573. printsf getv(modfvec,i) >>
  574. >>
  575. end;
  576. symbolic procedure terms!-done(fvec,delfvec,m);
  577. begin scalar flist,delflist;
  578. for i:=1:number!-of!-factors do <<
  579. flist:=getv(fvec,i) . flist;
  580. delflist:=getv(delfvec,i) . delflist >>;
  581. return terms!.done(number!-of!-factors,flist,delflist,
  582. number!-of!-factors,m)
  583. end;
  584. symbolic procedure terms!.done(n,flist,delflist,r,m);
  585. if n=1 then (car flist) . (car delflist)
  586. else begin scalar k,i,f1,f2,delf1,delf2;
  587. k:=n/2; i:=1;
  588. for each f in flist do
  589. << if i>k then f2:=(f . f2)
  590. else f1:=(f . f1);
  591. i:=i+1 >>;
  592. i:=1;
  593. for each delf in delflist do
  594. << if i>k then delf2:=(delf . delf2)
  595. else delf1:=(delf . delf1);
  596. i:=i+1 >>;
  597. f1:=terms!.done(k,f1,delf1,r,m);
  598. delf1:=cdr f1; f1:=car f1;
  599. f2:=terms!.done(n-k,f2,delf2,r,m);
  600. delf2:=cdr f2; f2:=car f2;
  601. delf1:=
  602. addf(addf(
  603. multf(f1,delf2),
  604. multf(f2,delf1)),
  605. multf(multf(delf1,m),delf2));
  606. if n=r then return delf1;
  607. return (multf(f1,f2) . delf1)
  608. end;
  609. symbolic procedure try!.combining(l,poly,m,sofar);
  610. try!.combining1(l,poly,m,sofar,2);
  611. % The following code is not optimal. If we find a combination of k
  612. % factors, we will re-rty all the previous combinations of k factors
  613. % already tried.
  614. % This is not frightfully serious, since in practice most such
  615. % combinations will have had something in common with the set found, and
  616. % so won't re-appear. This is definitely better than the previous
  617. % version, which re-tried all combinations. JHD 14.1.88.
  618. symbolic procedure try!.combining1(l,poly,m,sofar,k);
  619. % l is a list of factors, f(i), s.t. (product of the f(i) mod m) = poly
  620. % but no f(i) divides poly over the integers. We find the combinations
  621. % of the f(i) that yield the true factors of poly over the integers.
  622. % Sofar is a list of these factors found so far.
  623. % start combining them K at a time
  624. if poly=1 then
  625. if null l then sofar
  626. else errorf(list("TOO MANY BAD FACTORS:",l))
  627. else begin scalar n,res,ff,v,w,w1,combined!.factors,ll,lcfinv,oldmod;
  628. n:=length l;
  629. if n=1 then
  630. if ldeg car l > (ldeg poly)/2 then
  631. return ('one! bad! factor . sofar)
  632. else errorf(list("ONE BAD FACTOR DOES NOT FIT:",l));
  633. if n=2 or n=3 then <<
  634. w:=lc cdar l; % The LC of all the factors is the same.
  635. while not (w=lc poly) do poly:=quotfail(poly,w);
  636. % poly's LC may be a higher power of w than we want
  637. % and we must return a result with the same
  638. % LC as each of the combined factors.
  639. if not !*overview then factor!-trace <<
  640. printstr "We combine:";
  641. for each lf in l do printsf cdr lf;
  642. prin2!* " mod "; prin2!* m;
  643. printstr " to give correct factor:";
  644. printsf poly >>;
  645. combine!.alphas(l,t);
  646. return (poly . sofar) >>;
  647. ll:=for each ff in l collect (cdr ff . car ff);
  648. % K := 2; % K is now an argument
  649. oldmod := set!-general!-modulus m;
  650. lcfinv := general!-modular!-reciprocal lc cdar l;
  651. set!-general!-modulus oldmod;
  652. loop1:
  653. if k > n/2 then go to exit;
  654. w:=koutof(k,if 2*k=n then cdr l else l,nil);
  655. % We needn't try a combination and its complement
  656. while w and
  657. (v:=factor!-trialdiv(poly,car w,m,ll,lcfinv))='didntgo do
  658. << w:=cdr w;
  659. while w and
  660. ((car w = '!*lazyadjoin) or (car w = '!*lazykoutof)) do
  661. if car w= '!*lazyadjoin then
  662. w:=lazy!-adjoin(cadr w,caddr w,cadr cddr w)
  663. else w:=koutof(cadr w,caddr w,cadr cddr w)
  664. >>;
  665. if not(v='didntgo) then <<
  666. ff:=car v; v:=cdr v;
  667. if not !*overview then factor!-trace <<
  668. printstr "We combine:";
  669. for each a in car w do printsf a;
  670. prin2!* " mod "; prin2!* m;
  671. printstr " to give correct factor:";
  672. printsf ff >>;
  673. for each a in car w do <<
  674. w1:=l;
  675. while not (a = cdar w1) do w1:=cdr w1;
  676. combined!.factors:=car w1 . combined!.factors;
  677. l:=delete(car w1,l) >>;
  678. combine!.alphas(combined!.factors,t);
  679. % Now combine the rest, starting with k-tuples
  680. res:=try!.combining1(l,v,m,ff . sofar,k);
  681. go to exit>>;
  682. k := k + 1;
  683. go to loop1;
  684. exit:
  685. if res then return res
  686. else <<
  687. w:=lc cdar l; % The LC of all the factors is the same.
  688. while not (w=lc poly) do poly:=quotfail(poly,w);
  689. % poly's LC may be a higher power of w than we want
  690. % and we must return a result with the same
  691. % LC as each of the combined factors.
  692. if not !*overview then factor!-trace <<
  693. printstr "We combine:";
  694. for each ff in l do printsf cdr ff;
  695. prin2!* " mod "; prin2!* m;
  696. printstr " to give correct factor:";
  697. printsf poly >>;
  698. combine!.alphas(l,t);
  699. return (poly . sofar) >>
  700. end;
  701. symbolic procedure koutof(k,l,sofar);
  702. % Produces all permutations of length k from list l accumulating them
  703. % in sofar as we go. We use lazy evaluation in that this results in
  704. % a permutation dotted with:
  705. % ( '!*lazy . (argument for eval) )
  706. % except when k=1 when the permutations are explicitly given.
  707. if k=1 then append(
  708. for each f in l collect list cdr f,sofar)
  709. else if k>length l then sofar
  710. else <<
  711. while eqcar(l,'!*lazyadjoin) or eqcar(l,'!*lazykoutof) do
  712. if car l='!*lazyadjoin then
  713. l := lazy!-adjoin(cadr l,caddr l,cadr cddr l)
  714. else l := koutof(cadr l,caddr l,cadr cddr l);
  715. if k=length l then
  716. (for each ll in l collect cdr ll ) . sofar
  717. else koutof(k,cdr l,
  718. list('!*lazyadjoin,cdar l,
  719. list('!*lazykoutof,(k-1),cdr l,nil),
  720. sofar)) >>;
  721. symbolic procedure lazy!-adjoin(item,l,tail);
  722. % Dots item with each element in l using lazy evaluation on l.
  723. % If l is null tail results.
  724. << while eqcar(l,'!*lazyadjoin) or eqcar(l,'!*lazykoutof) do
  725. if car l ='!*lazyadjoin then
  726. l:=lazy!-adjoin(cadr l,caddr l,cadr cddr l)
  727. else l:=koutof(cadr l,caddr l,cadr cddr l);
  728. if null l then tail
  729. else (item . car l) .
  730. if null cdr l then tail
  731. else list('!*lazyadjoin,item,cdr l,tail) >>;
  732. symbolic procedure factor!-trialdiv(poly,flist,m,llist,lcfinv);
  733. % Combines the factors in FLIST mod M and test divides the result
  734. % into POLY (over integers) to see if it goes. If it doesn't
  735. % then DIDNTGO is returned, else the pair (D . Q) is
  736. % returned where Q is the quotient obtained and D is the product
  737. % of the factors mod M;
  738. % Abbott,J.A., Bradford,R.J. & Davenport,J.H.,
  739. % A Remark on Factorisation.
  740. % SIGSAM Bulletin 19(1985) 2, pp. 31-33, 37.
  741. if polyzerop poly then errorf "Test dividing into zero?"
  742. else begin scalar d,q,tcpoly,tcoeff,x,oldmod,w,poly1,try1;
  743. factor!-trace <<
  744. prin2!* "We combine factors ";
  745. for each ff in flist do <<
  746. w:=assoc(ff,llist);
  747. prin2!* "f(";
  748. prin2!* cdr w;
  749. prin2!* "), " >> ;
  750. prin2!* "and try dividing : " >>;
  751. x := mvar poly;
  752. tcpoly :=trailing!.coefft(poly,x);
  753. tcoeff := trailing!.coefft(car flist,x);
  754. oldmod := set!-general!-modulus m;
  755. for each fac in cdr flist do
  756. tcoeff := general!-modular!-times(
  757. general!-modular!-times(tcoeff,lcfinv),
  758. trailing!.coefft(fac,x));
  759. if not zerop remainder(tcpoly,
  760. w:=general!-make!-modular!-symmetric tcoeff) then <<
  761. factor!-trace printstr " it didn't go (tc test)";
  762. set!-general!-modulus oldmod;
  763. % if not(w = trailing!.coefft(car COMBINE(FLIST,M,LLIST,lcfinv),x))
  764. % then <<
  765. % printstr "incompatibility: we have";
  766. % prin2!* w;
  767. % printstr "which should be the trailing coefficient of:";
  768. % prin2!* car combine(flist,m,llist,lcfinv) >>;
  769. return 'didntgo >>;
  770. % it has passed the tc test - now try evaluating at 1;
  771. poly1 := eval!-at!-1 poly;
  772. try1 := eval!-at!-1 car flist;
  773. for each fac in cdr flist do
  774. try1 := general!-modular!-times(
  775. general!-modular!-times(try1,lcfinv),eval!-at!-1 fac);
  776. if (zerop try1 and not zerop poly1) or
  777. not zerop remainder(poly1,general!-make!-modular!-symmetric try1)
  778. then <<
  779. factor!-trace printstr " it didn't go (test at 1)";
  780. set!-general!-modulus oldmod;
  781. return 'didntgo >>;
  782. % it has passed both tests - work out longhand;
  783. set!-general!-modulus oldmod;
  784. d:=combine(flist,m,llist,lcfinv);
  785. if didntgo(q:=quotf(poly,car d)) then <<
  786. factor!-trace printstr " it didn't go (division fail)";
  787. return 'didntgo >>
  788. else <<
  789. factor!-trace printstr " it worked !";
  790. return (car d . quotf(q,cdr d)) >>
  791. end;
  792. symbolic procedure eval!-at!-1 f;
  793. % f a univariate standard form over Z with f(0) neq 0;
  794. % return the integer f(1);
  795. if atom f then f else (lc f) + eval!-at!-1(red f);
  796. symbolic procedure combine(flist,m,l,lcfinv);
  797. % Multiply factors in flist mod m.
  798. % L is a list of the factors for use in FACTOR!-TRACE.
  799. begin scalar om,res,lcf,lcfprod;
  800. lcf := lc car flist; % all leading coeffts should be the same.
  801. lcfprod := 1;
  802. % This is one of only two places in the entire factorizer where
  803. % it is ever necessary to use a modulus larger than word-size.
  804. if m>largest!-small!-modulus then <<
  805. om:=set!-general!-modulus m;
  806. % lcfinv := general!-modular!-reciprocal lcf; Done once and for all
  807. res:=general!-reduce!-mod!-p car flist;
  808. for each ff in cdr flist do <<
  809. if not(lcf=lc ff) then errorf "BAD LC IN FLIST";
  810. res:=general!-times!-mod!-p(
  811. general!-times!-mod!-p(lcfinv,
  812. general!-reduce!-mod!-p ff),res);
  813. lcfprod := lcfprod*lcf >>;
  814. res:=general!-make!-modular!-symmetric res;
  815. set!-modulus om;
  816. return (res . lcfprod) >>
  817. else <<
  818. om:=set!-modulus m;
  819. lcfinv := modular!-reciprocal lcf;
  820. res:=reduce!-mod!-p car flist;
  821. for each ff in cdr flist do <<
  822. if not(lcf=lc ff) then errorf "BAD LC IN FLIST";
  823. res:=times!-mod!-p(times!-mod!-p(lcfinv,reduce!-mod!-p ff),res);
  824. lcfprod := lcfprod*lcf >>;
  825. res:=make!-modular!-symmetric res;
  826. set!-modulus om;
  827. return (res . lcfprod) >>
  828. end;
  829. symbolic procedure combine!.alphas(flist,fixlcs);
  830. % Combine the alphas associated with each of these factors to
  831. % give the one alpha for their combination.
  832. begin scalar f1,a1,ff,aa,oldm,lcfac,lcfinv,saveflist;
  833. oldm:=set!-modulus hensel!-growth!-size;
  834. flist:=for each fac in flist collect <<
  835. saveflist:= (reduce!-mod!-p cdr fac) . saveflist;
  836. (car fac) . car saveflist >>;
  837. if fixlcs then <<
  838. lcfinv:=modular!-reciprocal lc cdar flist;
  839. lcfac:=modular!-expt(lc cdar flist,sub1 length flist)
  840. >>
  841. else << lcfinv:=1; lcfac:=1 >>;
  842. % If FIXLCS is set then we have combined n factors
  843. % (each with the same l.c.) to give one and we only need one
  844. % l.c. in the result, we have divided the combination by
  845. % lc**(n-1) and we must be sure to do the same for the
  846. % alphas.
  847. ff:=cdar flist;
  848. aa:=cdr get!-alpha ff;
  849. flist:=cdr flist;
  850. while flist do <<
  851. f1:=cdar flist;
  852. a1:=cdr get!-alpha f1;
  853. flist:=cdr flist;
  854. aa:=plus!-mod!-p(times!-mod!-p(aa,f1),times!-mod!-p(a1,ff));
  855. ff:=times!-mod!-p(ff,f1)
  856. >>;
  857. for each a in alphalist do
  858. if not member(car a,saveflist) then
  859. flist:=(car a . times!-mod!-p(cdr a,lcfac)) . flist;
  860. alphalist:=(quotient!-mod!-p(ff, lcfac) . aa) . flist;
  861. set!-modulus oldm
  862. end;
  863. % The following code is for dividing out factors in the middle
  864. % of the Hensel construction and adjusting all the associated
  865. % variables that go with it.
  866. symbolic procedure adjust!-growth(facdone,k,m);
  867. % One factor (at least) divides out so we can reconfigure the
  868. % problem for Hensel constrn giving a smaller growth and hopefully
  869. % reducing the coefficient bound considerably.
  870. begin scalar w,u,bound!-scale,modflist,factorlist,fhatlist,
  871. modfdone,b;
  872. factorlist:=vec2list!-without!-k(factorvec,k);
  873. modflist:=vec2list!-without!-k(modfvec,k);
  874. fhatlist:=vec2list!-without!-k(fhatvec,k);
  875. w:=number!-of!-factors;
  876. modfdone:=getv(modfvec,k);
  877. top:
  878. factors!-done:=facdone . factors!-done;
  879. if (number!-of!-factors:=number!-of!-factors #- 1)=1 then <<
  880. factors!-done:=hensel!-poly . factors!-done;
  881. number!-of!-factors:=0;
  882. hensel!-poly:=1;
  883. if not !*overview then factor!-trace <<
  884. printstr " All factors found:";
  885. for each fd in factors!-done do printsf fd >>;
  886. return polyzero >>;
  887. fhatlist:=for each fhat in fhatlist collect
  888. quotfail!-mod!-p(if null fhat then polyzero else fhat,modfdone);
  889. u:=comfac facdone; % Take contents and prim. parts.
  890. if car u then
  891. errorf(list("Factor divisible by main variable: ",facdone,car u));
  892. facdone:=quotfail(facdone,cdr u);
  893. bound!-scale:=cdr u;
  894. if not((b:=lc facdone)=1) then begin scalar b!-inv,old!-m;
  895. hensel!-poly:=quotfail(hensel!-poly,b**number!-of!-factors);
  896. b!-inv:=modular!-reciprocal modular!-number b;
  897. modflist:=for each modf in modflist collect
  898. times!-mod!-p(b!-inv,modf);
  899. % This is one of only two places in the entire factorizer where
  900. % it is ever necessary to use a modulus larger than word-size.
  901. if m>largest!-small!-modulus then <<
  902. old!-m:=set!-general!-modulus m;
  903. factorlist:=for each facc in factorlist collect
  904. adjoin!-term(lpow facc,quotfail(lc facc,b),
  905. general!-make!-modular!-symmetric(
  906. general!-times!-mod!-p(
  907. general!-modular!-reciprocal general!-modular!-number b,
  908. general!-reduce!-mod!-p red facc))) >>
  909. else <<
  910. old!-m:=set!-modulus m;
  911. factorlist:=for each facc in factorlist collect
  912. adjoin!-term(lpow facc,quotfail(lc facc,b),
  913. make!-modular!-symmetric(
  914. times!-mod!-p(modular!-reciprocal modular!-number b,
  915. reduce!-mod!-p red facc))) >>;
  916. % We must be careful not to destroy the information
  917. % that we have about the leading coefft.
  918. set!-modulus old!-m;
  919. fhatlist:=for each fhat in fhatlist collect
  920. times!-mod!-p(
  921. modular!-expt(b!-inv,number!-of!-factors #- 1),fhat)
  922. end;
  923. try!-another!-factor:
  924. if (w:=w #- 1)>0 then
  925. if not didntgo
  926. (u:=quotf(hensel!-poly,facdone:=car factorlist)) then <<
  927. hensel!-poly:=u;
  928. factorlist:=cdr factorlist;
  929. modfdone:=car modflist;
  930. modflist:=cdr modflist;
  931. fhatlist:=cdr fhatlist;
  932. goto top >>
  933. else <<
  934. factorlist:=append(cdr factorlist,list car factorlist);
  935. modflist:=append(cdr modflist,list car modflist);
  936. fhatlist:=append(cdr fhatlist,list car fhatlist);
  937. goto try!-another!-factor >>;
  938. set!-fluids!-for!-newhensel(factorlist,fhatlist,modflist);
  939. bound!-scale:=
  940. bound!-scale * get!-coefft!-bound(
  941. quotfail(hensel!-poly,bound!-scale**(number!-of!-factors #- 1)),
  942. ldeg hensel!-poly);
  943. % We expect the new coefficient bound to be smaller, but on
  944. % dividing out a factor our polynomial's height may have grown
  945. % more than enough to compensate in the bound formula for
  946. % the drop in degree. Anyway, the bound we computed last time
  947. % will still be valid, so let's stick with the smaller.
  948. if bound!-scale < coefftbd then coefftbd := bound!-scale;
  949. w:=quotfail(addf(hensel!-poly,negf current!-factor!-product),
  950. m/deltam);
  951. if not !*overview then factor!-trace <<
  952. printstr " Factors found to be correct:";
  953. for each fd in factors!-done do
  954. printsf fd;
  955. printstr "Remaining factors are:";
  956. printvec(" f(",number!-of!-factors,") = ",factorvec);
  957. prin2!* "New coefficient bound is "; printstr coefftbd;
  958. prin2!* " and the residue is now "; printsf w >>;
  959. return w
  960. end;
  961. symbolic procedure vec2list!-without!-k(v,k);
  962. % Turn a vector into a list leaving out Kth element.
  963. begin scalar w;
  964. for i:=1:number!-of!-factors do
  965. if not(i=k) then w:=getv(v,i) . w;
  966. return w
  967. end;
  968. symbolic procedure set!-fluids!-for!-newhensel(flist,fhatlist,modflist);
  969. << current!-factor!-product:=1;
  970. alphalist:=
  971. find!-alphas!-in!-a!-ring(number!-of!-factors,modflist,fhatlist,1);
  972. for i:=number!-of!-factors step -1 until 1 do <<
  973. putv(factorvec,i,car flist);
  974. putv(modfvec,i,car modflist);
  975. putv(fhatvec,i,car fhatlist);
  976. putv(alphavec,i,cdr get!-alpha car modflist);
  977. current!-factor!-product:=multf(car flist,current!-factor!-product);
  978. flist:=cdr flist;
  979. modflist:=cdr modflist;
  980. fhatlist:=cdr fhatlist >>
  981. >>;
  982. symbolic procedure set!-hensel!-fluids!-back p;
  983. % After the Hensel growth we must be careful to set back any fluids
  984. % that have been changed when we divided out a factor in the middle
  985. % of growing. Since calculating the alphas involves modular division
  986. % we cannot do it mod DELTAM which is generally a non-trivial power of
  987. % P (prime). So we calculate them mod P and if necessary we can do a
  988. % few quadratic growth steps later.
  989. begin scalar n,fd,modflist,fullf,modf;
  990. set!-modulus p;
  991. deltam:=p;
  992. n:=number!-of!-factors #+ length (fd:=factors!-done);
  993. current!-factor!-product:=hensel!-poly;
  994. for i:=(number!-of!-factors #+ 1):n do <<
  995. putv(factorvec,i,fullf:=car fd);
  996. putv(modfvec,i,modf:=reduce!-mod!-p fullf);
  997. current!-factor!-product:=multf(fullf,current!-factor!-product);
  998. modflist:=modf . modflist;
  999. fd:=cdr fd >>;
  1000. for i:=1:number!-of!-factors do <<
  1001. modf:=reduce!-mod!-p !*mod2f getv(modfvec,i);
  1002. % need to 'unbox' a modpoly before reducing it mod p as we
  1003. % know that the input modpoly is wrt a larger modulus
  1004. % (otherwise this would be a stupid thing to do anyway!)
  1005. % and so we are just pretending it is a full poly.
  1006. modflist:=modf . modflist;
  1007. putv(modfvec,i,modf) >>;
  1008. alphalist:=alphas(n,modflist,1);
  1009. for i:=1:n do putv(alphavec,i,cdr get!-alpha getv(modfvec,i));
  1010. number!-of!-factors:=n
  1011. end;
  1012. endmodule;
  1013. end;