facprim.red 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. module facprim; % Factorize a primitive multivariate polynomial.
  2. % Author: P. M. A. Moore, 1979.
  3. % Modifications by: Arthur C. Norman, Anthony C. Hearn.
  4. fluid '(!*force!-zero!-set
  5. !*overshoot
  6. !*overview
  7. !*trfac
  8. alphalist
  9. alphavec
  10. bad!-case
  11. best!-factor!-count
  12. best!-known!-factors
  13. best!-modulus
  14. best!-set!-pointer
  15. chosen!-prime
  16. current!-factor!-product
  17. deltam
  18. f!-numvec
  19. factor!-level
  20. factor!-trace!-list
  21. factored!-lc
  22. factorvec
  23. facvec
  24. fhatvec
  25. forbidden!-primes
  26. forbidden!-sets
  27. full!-gcd
  28. hensel!-growth!-size
  29. image!-content
  30. image!-factors
  31. image!-lc
  32. image!-mod!-p
  33. image!-poly
  34. image!-set
  35. image!-set!-modulus
  36. input!-leading!-coefficient
  37. input!-polynomial
  38. inverted
  39. inverted!-sign
  40. irreducible
  41. known!-factors
  42. kord!*
  43. m!-image!-variable
  44. modfvec
  45. modular!-info
  46. multivariate!-factors
  47. multivariate!-input!-poly
  48. no!-of!-best!-sets
  49. no!-of!-primes!-to!-try
  50. no!-of!-random!-sets
  51. non!-monic
  52. null!-space!-basis
  53. number!-of!-factors
  54. one!-complete!-deg!-analysis!-done
  55. othervars
  56. poly!-mod!-p
  57. polynomial!-to!-factor
  58. previous!-degree!-map
  59. prime!-base
  60. reconstructing!-gcd
  61. reduction!-count
  62. save!-zset
  63. split!-list
  64. target!-factor!-count
  65. true!-leading!-coeffts
  66. usable!-set!-found
  67. valid!-image!-sets
  68. vars!-to!-kill
  69. zero!-set!-tried
  70. zerovarset
  71. zset);
  72. global '(largest!-small!-modulus);
  73. %***********************************************************************
  74. %
  75. % Primitive multivariate polynomial factorization more or less as
  76. % described by Paul Wang in: Math. Comp. vol.32 no.144 oct 1978 pp.
  77. % 1215-1231 'An Improved Multivariate Polynomial Factoring Algorithm'
  78. %
  79. %***********************************************************************
  80. %-----------------------------------------------------------------------
  81. % This code works by using a local database of fluid variables
  82. % whose meaning is (hopefully) obvious.
  83. % they are used as follows:
  84. %
  85. % global name: set in: comments:
  86. %
  87. % m!-factored!-leading! create!.images only set if non-numeric
  88. % -coefft
  89. % m!-factored!-images factorize!.images vector
  90. % m!-input!-polynomial factorize!-primitive!
  91. % -polynomial
  92. % m!-best!-image!-pointer choose!.best!.image
  93. % m!-image!-factors choose!.best!.image vector
  94. % m!-true!-leading! choose!.best!.image vector
  95. % -coeffts
  96. % m!-prime choose!.best!.image
  97. % irreducible factorize!.images predicate
  98. % inverted create!.images predicate
  99. % m!-inverted!-sign create!-images +1 or -1
  100. % non!-monic determine!-leading! predicate
  101. % -coeffts
  102. % (also reconstruct!-over!
  103. % -integers)
  104. % m!-number!-of!-factors choose!.best!.image
  105. % m!-image!-variable square!.free!.factorize
  106. % or factorize!-form
  107. % m!-image!-sets create!.images vector
  108. % this last contains the images of m!-input!-polynomial and the
  109. % numbers associated with the factors of lc m!-input!-polynomial (to be
  110. % used later) the latter existing only when the lc m!-input!-polynomial
  111. % is non-integral. ie.:
  112. % m!-image!-sets=< ... , (( d . u ), a, d) , ... > ( a vector)
  113. % where: a = an image set (=association list);
  114. % d = cont(m!-input!-polynomial image wrt a);
  115. % u = prim.part.(same) which is non-trivial square-free
  116. % by choice of image set.;
  117. % d = vector of numbers associated with factors in lc
  118. % m!-input!-polynomial (these depend on a as well);
  119. % the number of entries in m!-image!-sets is defined by the fluid
  120. % variable, no.of.random.sets.
  121. %***********************************************************************
  122. % Multivariate factorization part 1. entry point for this code:
  123. % (** NB ** the polynomial is assumed to be non-trivial, primitive and
  124. % square free.)
  125. %***********************************************************************
  126. symbolic procedure factorize!-primitive!-polynomial u;
  127. % U is primitive square free and at least linear in
  128. % m!-image!-variable. M!-image!-variable is the variable preserved in
  129. % the univariate images. This function determines a random set of
  130. % integers and a prime to create a univariate modular image of u,
  131. % factorize it and determine the leading coeffts of the factors in the
  132. % full factorization of u. Finally the modular image factors are grown
  133. % up to the full multivariates ones using the hensel construction.
  134. % Result is simple list of irreducible factors.
  135. if not(m!-image!-variable eq mvar u) then errach "factorize variable"
  136. else if degree!-in!-variable(u,m!-image!-variable) = 1 then list u
  137. else if degree!-in!-variable(u,m!-image!-variable) = 2
  138. then factorize!-quadratic u
  139. else if fac!-univariatep u then univariate!-factorize u
  140. else begin scalar
  141. valid!-image!-sets,factored!-lc,image!-factors,prime!-base,
  142. one!-complete!-deg!-analysis!-done,zset,zerovarset,othervars,
  143. multivariate!-input!-poly,best!-set!-pointer,reduction!-count,
  144. true!-leading!-coeffts,number!-of!-factors,
  145. inverted!-sign,irreducible,inverted,vars!-to!-kill,
  146. forbidden!-sets,zero!-set!-tried,non!-monic,
  147. no!-of!-best!-sets,no!-of!-random!-sets,bad!-case,
  148. target!-factor!-count,modular!-info,multivariate!-factors,
  149. hensel!-growth!-size,alphalist,
  150. previous!-degree!-map,image!-set!-modulus,
  151. best!-known!-factors,reconstructing!-gcd,full!-gcd;
  152. % base!-timer:=time();
  153. % trace!-time display!-time(
  154. % " Entered multivariate primitive polynomial code after ",
  155. % base!-timer - base!-time);
  156. % Note that this code works by using a local database of fluid
  157. % variables that are updated by the subroutines directly called
  158. % here. This allows for the relatively complicated interaction
  159. % between flow of data and control that occurs in the factorization
  160. % algorithm.
  161. factor!-trace <<
  162. printstr "From now on we shall refer to this polynomial as U.";
  163. printstr
  164. "We now create an image of U by picking suitable values ";
  165. printstr "for all but one of the variables in U.";
  166. prin2!* "The variable preserved in the image is ";
  167. prinvar m!-image!-variable; terpri!*(nil) >>;
  168. initialize!-fluids u;
  169. % set up the fluids to start things off.
  170. % w!-time:=time();
  171. tryagain:
  172. get!-some!-random!-sets();
  173. choose!-the!-best!-set();
  174. % trace!-time <<
  175. % display!-time("Modular factoring and best set chosen in ",
  176. % time()-w!-time);
  177. % w!-time:=time() >>;
  178. if irreducible then return list u
  179. else if bad!-case then <<
  180. if !*overshoot then prin2t "Bad image sets - loop";
  181. bad!-case:=nil; goto tryagain >>;
  182. reconstruct!-image!-factors!-over!-integers();
  183. % trace!-time <<
  184. % display!-time("Image factors reconstructed in ",time()-w!-time);
  185. % w!-time:=time() >>;
  186. if irreducible then return list u
  187. else if bad!-case then <<
  188. if !*overshoot then prin2t "Bad image factors - loop";
  189. bad!-case:=nil; goto tryagain >>;
  190. determine!.leading!.coeffts();
  191. % trace!-time <<
  192. % display!-time("Leading coefficients distributed in ",
  193. % time()-w!-time);
  194. % w!-time:=time() >>;
  195. if irreducible then
  196. return list u
  197. else if bad!-case then <<
  198. if !*overshoot then prin2t "Bad split shown by LC distribution";
  199. bad!-case:=nil; goto tryagain >>;
  200. if determine!-more!-coeffts()='done then <<
  201. % trace!-time <<
  202. % display!-time("All the coefficients distributed in ",
  203. % time()-w!-time);
  204. % w!-time:=time() >>;
  205. return check!-inverted multivariate!-factors >>;
  206. % trace!-time <<
  207. % display!-time("More coefficients distributed in ",
  208. % time()-w!-time);
  209. % w!-time:=time() >>;
  210. reconstruct!-multivariate!-factors(nil);
  211. if bad!-case and not irreducible then <<
  212. if !*overshoot then prin2t "Multivariate overshoot - restart";
  213. bad!-case:=nil; goto tryagain >>;
  214. % trace!-time
  215. % display!-time("Multivariate factors reconstructed in ",
  216. % time()-w!-time);
  217. if irreducible then return list u;
  218. return check!-inverted multivariate!-factors
  219. end;
  220. symbolic procedure check!-inverted multi!-faclist;
  221. begin scalar inv!.sign,l;
  222. if inverted then <<
  223. inv!.sign:=1;
  224. multi!-faclist:=
  225. for each x in multi!-faclist collect <<
  226. l:=invert!.poly(x,m!-image!-variable);
  227. inv!.sign:=(car l) * inv!.sign;
  228. cdr l >>;
  229. if not(inv!.sign=inverted!-sign) then
  230. errorf list("INVERSION HAS LOST A SIGN",inv!.sign) >>;
  231. return multivariate!-factors:=multi!-faclist end;
  232. symbolic procedure getcof(p, v, n);
  233. % Get coeff of v^n in p.
  234. % I bet this exists somewhere under a different name....
  235. if domainp p then if n=0 then p else nil
  236. else if mvar p = v then
  237. if ldeg p=n then lc p
  238. else getcof(red p, v, n)
  239. else addf(multf((lpow p .* 1) .+ nil, getcof(lc p, v, n)),
  240. getcof(red p, v, n));
  241. symbolic procedure factorize!-quadratic u;
  242. % U is a primitive square-free quadratic. It factors if and only if
  243. % its discriminant is a perfect square.
  244. begin scalar a, b, c, discr, f1, f2, x;
  245. % I am unreasonably cautious here - I THINK that the image variable
  246. % should be the main var here, but in case things have got themselves
  247. % reordered & to make myself bomb proof against future changes I will
  248. % not assume same.
  249. a := getcof(u, m!-image!-variable, 2);
  250. b := getcof(u, m!-image!-variable, 1);
  251. c := getcof(u, m!-image!-variable, 0);
  252. if dmode!* = '!:mod!: and current!-modulus = 2 then % problems
  253. if b=1 and c=1 then return list u; % Irreducible.
  254. discr := addf(multf(b, b), multf(a, multf(-4, c)));
  255. discr := sqrtf2 discr;
  256. if discr=-1 then return list u; % Irreducible.
  257. x := addf(multf(a, multf(2, !*k2f m!-image!-variable)), b);
  258. f1 := addf(x, discr);
  259. f2 := addf(x, negf discr);
  260. f1 := quotf(f1,
  261. cdr contents!-with!-respect!-to(f1, m!-image!-variable));
  262. f2 := quotf(f2,
  263. cdr contents!-with!-respect!-to(f2, m!-image!-variable));
  264. return list(f1, f2)
  265. end;
  266. symbolic procedure sqrtd2 d;
  267. % Square root of domain element or -1 if it does not have an exact one.
  268. % Possibly needs upgrades to deal with non-integer domains, e.g. in
  269. % modular arithmetic just half of all values have square roots (= are
  270. % quadratic residues), but finding the roots is (I think) HARD. In
  271. % floating point it could be taken that all positive values have square
  272. % roots. Anyway somebody can adjust this as necessary and I think that
  273. % SQRTF2 will then behave properly...
  274. if d=nil then nil
  275. else if not fixp d or d<0 then -1
  276. else begin
  277. scalar q, r, rold;
  278. q := pmam!-sqrt d; % Works even if D is really huge.
  279. r := q*q-d;
  280. repeat <<
  281. rold := abs r;
  282. q := q - (r+q)/(2*q); % / truncates, so this rounds to nearest
  283. r := q*q-d >> until abs r >= rold;
  284. if r=0 then return q
  285. else return -1
  286. end;
  287. symbolic procedure pmam!-sqrt n;
  288. % Find the square root of n and return integer part + 1. N is fixed
  289. % pt on input. As it may be very large, i.e. > largest allowed
  290. % floating pt number, it is scaled appropriately.
  291. begin scalar s,ten!*!*6,ten!*!*12,ten!*!*14;
  292. s:=0;
  293. ten!*!*6:=10**6;
  294. ten!*!*12:=ten!*!*6**2;
  295. ten!*!*14:=100*ten!*!*12;
  296. while n>ten!*!*14 do << s:=iadd1 s; n:=1+n/ten!*!*12 >>;
  297. return (fix sqrt float n + 1)*10**(6*s)
  298. end;
  299. symbolic procedure sqrtf2 p;
  300. % Return square root of the polynomial P if there is an exact one,
  301. % else returns -1 to indicate failure.
  302. if domainp p then sqrtd2 p
  303. else begin
  304. scalar v, d, qlc, q, r, w;
  305. if not evenp (d := ldeg p) or
  306. (qlc := sqrtf2 lc p) = -1 then return -1;
  307. d := d/2;
  308. v := mvar p;
  309. q := (mksp(v, d) .* qlc) .+ nil; % First approx to sqrt(P)
  310. r := multf(2, q);
  311. p := red p; % Residue
  312. while not domainp p and
  313. mvar p = v and
  314. ldeg p >= d and
  315. (w := quotf(lt p .+ nil, r)) neq nil do
  316. << p := addf(p, multf(negf w, addf(multf(2, q), w)));
  317. q := addf(q, w) >>;
  318. if null p then return q else return -1
  319. end;
  320. symbolic procedure initialize!-fluids u;
  321. % Set up the fluids to be used in factoring primitive poly.
  322. begin scalar w,w1;
  323. if !*force!-zero!-set then <<
  324. no!-of!-random!-sets:=1;
  325. no!-of!-best!-sets:=1 >>
  326. else <<
  327. no!-of!-random!-sets:=9;
  328. % we generate this many and calculate their factor counts.
  329. no!-of!-best!-sets:=5;
  330. % we find the modular factors of this many.
  331. >>;
  332. image!-set!-modulus:=5;
  333. vars!-to!-kill:=variables!-to!-kill lc u;
  334. multivariate!-input!-poly:=u;
  335. no!-of!-primes!-to!-try := 5;
  336. target!-factor!-count:=degree!-in!-variable(u,m!-image!-variable);
  337. if not domainp lc multivariate!-input!-poly then
  338. if domainp (w:=
  339. trailing!.coefft(multivariate!-input!-poly,
  340. m!-image!-variable)) then
  341. << inverted:=t;
  342. % note that we are 'inverting' the poly m!-input!-polynomial.
  343. w1:=invert!.poly(multivariate!-input!-poly,m!-image!-variable);
  344. multivariate!-input!-poly:=cdr w1;
  345. inverted!-sign:=car w1;
  346. % to ease the lc problem, m!-input!-polynomial <- poly
  347. % produced by taking numerator of (m!-input!-polynomial
  348. % with 1/m!-image!-variable substituted for
  349. % m!-image!-variable).
  350. % m!-inverted!-sign is -1 if we have inverted the sign of
  351. % the resulting poly to keep it +ve, else +1.
  352. factor!-trace <<
  353. prin2!* "The trailing coefficient of U wrt ";
  354. prinvar m!-image!-variable; prin2!* "(="; prin2!* w;
  355. printstr ") is purely numeric so we 'invert' U to give: ";
  356. prin2!* " U <- "; printsf multivariate!-input!-poly;
  357. printstr "This simplifies any problems with the leading ";
  358. printstr "coefficient of U." >>
  359. >>
  360. else <<
  361. % trace!-time prin2t "Factoring the leading coefficient:";
  362. % wtime:=time();
  363. factored!-lc:=
  364. factorize!-form!-recursion lc multivariate!-input!-poly;
  365. % trace!-time display!-time("Leading coefficient factored in ",
  366. % time()-wtime);
  367. % factorize the lc of m!-input!-polynomial completely.
  368. factor!-trace <<
  369. printstr
  370. "The leading coefficient of U is non-trivial so we must ";
  371. printstr "factor it before we can decide how it is distributed";
  372. printstr "over the leading coefficients of the factors of U.";
  373. printstr "So the factors of this leading coefficient are:";
  374. fac!-printfactors factored!-lc >>
  375. >>;
  376. make!-zerovarset vars!-to!-kill;
  377. % Sets ZEROVARSET and OTHERVARS.
  378. if null zerovarset then zero!-set!-tried:=t
  379. else <<
  380. zset:=make!-zeroset!-list length zerovarset;
  381. save!-zset:=zset >>
  382. end;
  383. symbolic procedure variables!-to!-kill lc!-u;
  384. % Picks out all the variables in u except var. Also checks to see if
  385. % any of these divide lc u: if they do they are dotted with t otherwise
  386. % dotted with nil. result is list of these dotted pairs.
  387. for each w in cdr kord!* collect
  388. if (domainp lc!-u) or didntgo quotf(lc!-u,!*k2f w) then
  389. (w . nil) else (w . t);
  390. %***********************************************************************
  391. % Multivariate factorization part 2. Creating image sets and picking
  392. % the best one.
  393. fluid '(usable!-set!-found);
  394. symbolic procedure get!-some!-random!-sets();
  395. % here we create a number of random sets to make the input
  396. % poly univariate by killing all but 1 of the variables. at
  397. % the same time we pick a random prime to reduce this image
  398. % poly mod p.
  399. begin scalar image!-set,chosen!-prime,image!-lc,image!-mod!-p,
  400. image!-content,image!-poly,f!-numvec,forbidden!-primes,i,j,
  401. usable!-set!-found;
  402. valid!-image!-sets:=mkvect no!-of!-random!-sets;
  403. i:=0;
  404. while i < no!-of!-random!-sets do <<
  405. % wtime:=time();
  406. generate!-an!-image!-set!-with!-prime(
  407. if i<idifference(no!-of!-random!-sets,3) then nil else t);
  408. % trace!-time
  409. % display!-time(" Image set generated in ",time()-wtime);
  410. i:=iadd1 i;
  411. putv(valid!-image!-sets,i,list(
  412. image!-set,chosen!-prime,image!-lc,image!-mod!-p,image!-content,
  413. image!-poly,f!-numvec));
  414. forbidden!-sets:=image!-set . forbidden!-sets;
  415. forbidden!-primes:=list chosen!-prime;
  416. j:=1;
  417. while (j<3) and (i<no!-of!-random!-sets) do <<
  418. % wtime:=time();
  419. image!-mod!-p:=find!-a!-valid!-prime(image!-lc,image!-poly,
  420. not numberp image!-content);
  421. if not(image!-mod!-p='not!-square!-free) then <<
  422. % trace!-time
  423. % display!-time(" Prime and image mod p found in ",
  424. % time()-wtime);
  425. i:=iadd1 i;
  426. putv(valid!-image!-sets,i,list(
  427. image!-set,chosen!-prime,image!-lc,image!-mod!-p,
  428. image!-content,image!-poly,f!-numvec));
  429. forbidden!-primes:=chosen!-prime . forbidden!-primes >>;
  430. j:=iadd1 j
  431. >>
  432. >>
  433. end;
  434. symbolic procedure choose!-the!-best!-set();
  435. % Given several random sets we now choose the best by factoring
  436. % each image mod its chosen prime and taking one with the
  437. % lowest factor count as the best for hensel growth.
  438. begin scalar split!-list,poly!-mod!-p,null!-space!-basis,
  439. known!-factors,w,n,fnum,remaining!-split!-list;
  440. modular!-info:=mkvect no!-of!-random!-sets;
  441. % wtime:=time();
  442. for i:=1:no!-of!-random!-sets do <<
  443. w:=getv(valid!-image!-sets,i);
  444. get!-factor!-count!-mod!-p(i,get!-image!-mod!-p w,
  445. get!-chosen!-prime w,not numberp get!-image!-content w) >>;
  446. split!-list:=sort(split!-list,function lessppair);
  447. % this now contains a list of pairs (m . n) where
  448. % m is the no: of factors in image no: n. the list
  449. % is sorted with best split (smallest m) first.
  450. % trace!-time
  451. % display!-time(" Factor counts found in ",time()-wtime);
  452. if caar split!-list = 1 then <<
  453. irreducible:=t; return nil >>;
  454. w:=nil;
  455. % wtime:=time();
  456. for i:=1:no!-of!-best!-sets do <<
  457. n:=cdar split!-list;
  458. get!-factors!-mod!-p(n,
  459. get!-chosen!-prime getv(valid!-image!-sets,n));
  460. w:=(car split!-list) . w;
  461. split!-list:=cdr split!-list >>;
  462. % pick the best few of these and find out their
  463. % factors mod p.
  464. % trace!-time
  465. % display!-time(" Best factors mod p found in ",time()-wtime);
  466. remaining!-split!-list:=split!-list;
  467. split!-list:=reversip w;
  468. % keep only those images that are fully factored mod p.
  469. % wtime:=time();
  470. check!-degree!-sets(no!-of!-best!-sets,t);
  471. % the best image is pointed at by best!-set!-pointer.
  472. % trace!-time
  473. % display!-time(" Degree sets analysed in ",time()-wtime);
  474. % now if these didn't help try the rest to see
  475. % if we can avoid finding new image sets altogether:
  476. if bad!-case then <<
  477. bad!-case:=nil;
  478. % wtime:=time();
  479. while remaining!-split!-list do <<
  480. n:=cdar remaining!-split!-list;
  481. get!-factors!-mod!-p(n,
  482. get!-chosen!-prime getv(valid!-image!-sets,n));
  483. w:=(car remaining!-split!-list) . w;
  484. remaining!-split!-list:=cdr remaining!-split!-list >>;
  485. % trace!-time
  486. % display!-time(" More sets factored mod p in ",time()-wtime);
  487. split!-list:=reversip w;
  488. % wtime:=time();
  489. check!-degree!-sets(no!-of!-random!-sets - no!-of!-best!-sets,t);
  490. % best!-set!-pointer hopefully points at the best image.
  491. % trace!-time
  492. % display!-time(" More degree sets analysed in ",time()-wtime)
  493. >>;
  494. one!-complete!-deg!-analysis!-done:=t;
  495. factor!-trace <<
  496. w:=getv(valid!-image!-sets,best!-set!-pointer);
  497. prin2!* "The chosen image set is: ";
  498. for each x in get!-image!-set w do <<
  499. prinvar car x; prin2!* "="; prin2!* cdr x; prin2!* "; " >>;
  500. terpri!*(nil);
  501. prin2!* "and chosen prime is "; printstr get!-chosen!-prime w;
  502. printstr "Image polynomial (made primitive) = ";
  503. printsf get!-image!-poly w;
  504. if not(get!-image!-content w=1) then <<
  505. prin2!* " with (extracted) content of ";
  506. printsf get!-image!-content w >>;
  507. prin2!* "The image polynomial mod "; prin2!* get!-chosen!-prime w;
  508. printstr ", made monic, is:";
  509. printsf get!-image!-mod!-p w;
  510. printstr "and factors of the primitive image mod this prime are:";
  511. for each x in getv(modular!-info,best!-set!-pointer)
  512. do printsf x;
  513. if (fnum:=get!-f!-numvec w) and not !*overview then <<
  514. printstr "The numeric images of each (square-free) factor of";
  515. printstr "the leading coefficient of the polynomial are as";
  516. prin2!* "follows (in order):";
  517. prin2!* " ";
  518. for i:=1:length cdr factored!-lc do <<
  519. prin2!* getv(fnum,i); prin2!* "; " >>;
  520. terpri!*(nil) >>
  521. >>
  522. end;
  523. %***********************************************************************
  524. % Multivariate factorization part 3. Reconstruction of the
  525. % chosen image over the integers.
  526. symbolic procedure reconstruct!-image!-factors!-over!-integers();
  527. % The Hensel construction from modular case to univariate
  528. % over the integers.
  529. begin scalar best!-modulus,best!-factor!-count,input!-polynomial,
  530. input!-leading!-coefficient,best!-known!-factors,s,w,i,
  531. x!-is!-factor,x!-factor;
  532. s:=getv(valid!-image!-sets,best!-set!-pointer);
  533. best!-known!-factors:=getv(modular!-info,best!-set!-pointer);
  534. best!-modulus:=get!-chosen!-prime s;
  535. best!-factor!-count:=length best!-known!-factors;
  536. input!-polynomial:=get!-image!-poly s;
  537. if ldeg input!-polynomial=1 then
  538. if not(x!-is!-factor:=not numberp get!-image!-content s) then
  539. errorf list("Trying to factor a linear image poly: ",
  540. input!-polynomial)
  541. else begin scalar brecip,ww,om,x!-mod!-p;
  542. number!-of!-factors:=2;
  543. prime!-base:=best!-modulus;
  544. x!-factor:=!*k2f m!-image!-variable;
  545. putv(valid!-image!-sets,best!-set!-pointer,
  546. put!-image!-poly!-and!-content(s,lc get!-image!-content s,
  547. multf(x!-factor,get!-image!-poly s)));
  548. om:=set!-modulus best!-modulus;
  549. brecip:=modular!-reciprocal
  550. red (ww:=reduce!-mod!-p input!-polynomial);
  551. x!-mod!-p:=!*f2mod x!-factor;
  552. alphalist:=list(
  553. (x!-mod!-p . brecip),
  554. (ww . modular!-minus modular!-times(brecip,lc ww)));
  555. do!-quadratic!-growth(list(x!-factor,input!-polynomial),
  556. list(x!-mod!-p,ww),best!-modulus);
  557. w:=list input!-polynomial; % All factors apart from X-FACTOR.
  558. set!-modulus om
  559. end
  560. else <<
  561. input!-leading!-coefficient:=lc input!-polynomial;
  562. factor!-trace <<
  563. printstr
  564. "Next we use the Hensel Construction to grow these modular";
  565. printstr "factors into factors over the integers." >>;
  566. w:=reconstruct!.over!.integers();
  567. if irreducible then return t;
  568. if (x!-is!-factor:=not numberp get!-image!-content s) then <<
  569. number!-of!-factors:=length w + 1;
  570. x!-factor:=!*k2f m!-image!-variable;
  571. putv(valid!-image!-sets,best!-set!-pointer,
  572. put!-image!-poly!-and!-content(s,lc get!-image!-content s,
  573. multf(x!-factor,get!-image!-poly s)));
  574. fix!-alphas() >>
  575. else number!-of!-factors:=length w;
  576. if number!-of!-factors=1 then return irreducible:=t >>;
  577. if number!-of!-factors>target!-factor!-count then
  578. return bad!-case:=list get!-image!-set s;
  579. image!-factors:=mkvect number!-of!-factors;
  580. i:=1;
  581. factor!-trace
  582. printstr "The full factors of the image polynomial are:";
  583. for each im!-factor in w do <<
  584. putv(image!-factors,i,im!-factor);
  585. factor!-trace printsf im!-factor;
  586. i:=iadd1 i >>;
  587. if x!-is!-factor then <<
  588. putv(image!-factors,i,x!-factor);
  589. factor!-trace <<
  590. printsf x!-factor;
  591. printsf get!-image!-content
  592. getv(valid!-image!-sets,best!-set!-pointer) >> >>
  593. end;
  594. symbolic procedure do!-quadratic!-growth(flist,modflist,p);
  595. begin scalar fhatvec,alphavec,factorvec,modfvec,facvec,
  596. current!-factor!-product,i,deltam,m;
  597. fhatvec:=mkvect number!-of!-factors;
  598. alphavec:=mkvect number!-of!-factors;
  599. factorvec:=mkvect number!-of!-factors;
  600. modfvec:=mkvect number!-of!-factors;
  601. facvec:=mkvect number!-of!-factors;
  602. current!-factor!-product:=1;
  603. i:=0;
  604. for each ff in flist do <<
  605. putv(factorvec,i:=iadd1 i,ff);
  606. current!-factor!-product:=multf(ff,current!-factor!-product) >>;
  607. i:=0;
  608. for each modff in modflist do <<
  609. putv(modfvec,i:=iadd1 i,modff);
  610. putv(alphavec,i,cdr get!-alpha modff) >>;
  611. deltam:=p;
  612. m:=deltam*deltam;
  613. while m<largest!-small!-modulus do <<
  614. quadratic!-step(m,number!-of!-factors);
  615. m:=m*deltam >>;
  616. hensel!-growth!-size:=deltam;
  617. alphalist:=nil;
  618. for j:=1:number!-of!-factors do
  619. alphalist:=(reduce!-mod!-p getv(factorvec,j) . getv(alphavec,j))
  620. . alphalist
  621. end;
  622. symbolic procedure fix!-alphas();
  623. % We extracted a factor x (where x is the image variable)
  624. % before any alphas were calculated, we now need to put
  625. % back this factor and its coresponding alpha which incidently
  626. % will change the other alphas.
  627. begin scalar om,f1,x!-factor,a,arecip,b;
  628. om:=set!-modulus hensel!-growth!-size;
  629. f1:=reduce!-mod!-p input!-polynomial;
  630. x!-factor:=!*f2mod !*k2f m!-image!-variable;
  631. arecip:=modular!-reciprocal
  632. (a:=evaluate!-mod!-p(f1,m!-image!-variable,0));
  633. b:=times!-mod!-p(modular!-minus arecip,
  634. quotfail!-mod!-p(difference!-mod!-p(f1,a),x!-factor));
  635. alphalist:=(x!-factor . arecip) .
  636. (for each aa in alphalist collect
  637. ((car aa) . remainder!-mod!-p(times!-mod!-p(b,cdr aa),car aa)));
  638. set!-modulus om
  639. end;
  640. %***********************************************************************
  641. % Multivariate factorization part 4. Determining the leading
  642. % coefficients.
  643. symbolic procedure determine!.leading!.coeffts();
  644. % This function determines the leading coeffts to all but a constant
  645. % factor which is spread over all of the factors before reconstruction.
  646. begin scalar delta,c,s;
  647. s:=getv(valid!-image!-sets,best!-set!-pointer);
  648. delta:=get!-image!-content s;
  649. % cont(the m!-input!-polynomial image).
  650. if not domainp lc multivariate!-input!-poly then
  651. << true!-leading!-coeffts:=
  652. distribute!.lc(number!-of!-factors,image!-factors,s,
  653. factored!-lc);
  654. if bad!-case then <<
  655. bad!-case:=list get!-image!-set s;
  656. target!-factor!-count:=number!-of!-factors - 1;
  657. if target!-factor!-count=1 then irreducible:=t;
  658. return bad!-case >>;
  659. delta:=car true!-leading!-coeffts;
  660. true!-leading!-coeffts:=cdr true!-leading!-coeffts;
  661. % if the lc problem exists then use Wang's algorithm to
  662. % distribute it over the factors.
  663. if not !*overview then factor!-trace <<
  664. printstr "We now determine the leading coefficients of the ";
  665. printstr "factors of U by using the factors of the leading";
  666. printstr "coefficient of U and their (square-free) images";
  667. printstr "referred to earlier:";
  668. for i:=1:number!-of!-factors do <<
  669. prinsf getv(image!-factors,i);
  670. prin2!* " with l.c.: ";
  671. printsf getv(true!-leading!-coeffts,i)
  672. >> >>;
  673. if not onep delta then factor!-trace <<
  674. if !*overview then
  675. << printstr
  676. "In determining the leading coefficients of the factors";
  677. prin2!* "of U, " >>;
  678. prin2!* "We have an integer factor, ";
  679. prin2!* delta;
  680. printstr ", left over that we ";
  681. printstr "cannot yet distribute correctly." >>
  682. >>
  683. else <<
  684. true!-leading!-coeffts:=mkvect number!-of!-factors;
  685. for i:=1:number!-of!-factors do
  686. putv(true!-leading!-coeffts,i,lc getv(image!-factors,i));
  687. if not onep delta then
  688. factor!-trace <<
  689. prin2!* "U has a leading coefficient = ";
  690. prin2!* delta;
  691. printstr " which we cannot ";
  692. printstr "yet distribute correctly over the image factors." >>
  693. >>;
  694. if not onep delta then
  695. << for i:=1:number!-of!-factors do
  696. << putv(image!-factors,i,multf(delta,getv(image!-factors,i)));
  697. putv(true!-leading!-coeffts,i,
  698. multf(delta,getv(true!-leading!-coeffts,i)))
  699. >>;
  700. divide!-all!-alphas delta;
  701. c:=expt(delta,isub1 number!-of!-factors);
  702. multivariate!-input!-poly:=multf(c,multivariate!-input!-poly);
  703. non!-monic:=t;
  704. factor!-trace <<
  705. printstr "(a) We multiply each of the image factors by the ";
  706. printstr "absolute value of this constant and multiply";
  707. prin2!* "U by ";
  708. if not(number!-of!-factors=2) then
  709. << prin2!* delta; prin2!* "**";
  710. prin2!* isub1 number!-of!-factors >>
  711. else prin2!* delta;
  712. printstr " giving new image factors";
  713. printstr "as follows: ";
  714. for i:=1:number!-of!-factors do
  715. printsf getv(image!-factors,i)
  716. >>
  717. >>;
  718. % If necessary, fiddle the remaining integer part of the
  719. % lc of m!-input!-polynomial.
  720. end;
  721. endmodule;
  722. end;