imageset.red 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. module imageset;
  2. % Authors: A. C. Norman and P. M. A. Moore, 1979;
  3. fluid '(!*force!-prime
  4. !*force!-zero!-set
  5. !*trfac
  6. bad!-case
  7. chosen!-prime
  8. current!-modulus
  9. f!-numvec
  10. factor!-level
  11. factor!-trace!-list
  12. factor!-x
  13. factored!-lc
  14. forbidden!-primes
  15. forbidden!-sets
  16. image!-content
  17. image!-lc
  18. image!-mod!-p
  19. image!-poly
  20. image!-set
  21. image!-set!-modulus
  22. kord!*
  23. m!-image!-variable
  24. modulus!/2
  25. multivariate!-input!-poly
  26. no!-of!-primes!-to!-try
  27. othervars
  28. polyzero
  29. save!-zset
  30. usable!-set!-found
  31. vars!-to!-kill
  32. zero!-set!-tried
  33. zerovarset
  34. zset);
  35. %*******************************************************************;
  36. %
  37. % this section deals with the image sets used in
  38. % factorising multivariate polynomials according
  39. % to wang's theories.
  40. % ref: math. comp. vol.32 no.144 oct 1978 pp 1217-1220
  41. % 'an improved multivariate polynomial factoring algorithm'
  42. %
  43. %*******************************************************************;
  44. %*******************************************************************;
  45. % first we have routines for generating the sets
  46. %*******************************************************************;
  47. symbolic procedure generate!-an!-image!-set!-with!-prime
  48. good!-set!-needed;
  49. % given a multivariate poly (in a fluid) we generate an image set
  50. % to make it univariate and also a random prime to use in the
  51. % modular factorization. these numbers are random except that
  52. % we will not allow anything in forbidden!-sets or forbidden!-primes;
  53. begin scalar currently!-forbidden!-sets,u;
  54. u:=multivariate!-input!-poly;
  55. % a bit of a handful to type otherwise!!!! ;
  56. image!-set:=nil;
  57. currently!-forbidden!-sets:=forbidden!-sets;
  58. tryanotherset:
  59. if image!-set then
  60. currently!-forbidden!-sets:=image!-set .
  61. currently!-forbidden!-sets;
  62. % wtime:=time();
  63. image!-set:=get!-new!-set currently!-forbidden!-sets;
  64. % princ "Trying imageset= ";
  65. % prin2t image!-set;
  66. % trace!-time <<
  67. % display!-time(" New image set found in ",time()-wtime);
  68. % wtime:=time() >>;
  69. image!-lc:=make!-image!-lc!-list(lc u,image!-set);
  70. % list of image lc's wrt different variables in IMAGE-SET;
  71. % princ "Image set to try is:";% prin2t image!-set;
  72. % prin2!* "L.C. of poly is:";% printsf lc u;
  73. % prin2t "Image l.c.s with variables substituted on order:";
  74. % for each imlc in image!-lc do printsf imlc;
  75. % trace!-time
  76. % display!-time(" Image of lc made in ",time()-wtime);
  77. if (caar image!-lc)=0 then goto tryanotherset;
  78. % wtime:=time();
  79. image!-poly:=make!-image(u,image!-set);
  80. % trace!-time <<
  81. % display!-time(" Image poly made in ",time()-wtime);
  82. % wtime:=time() >>;
  83. image!-content:=get!.content image!-poly;
  84. % note: the content contains the image variable if it
  85. % is a factor of the image poly;
  86. % trace!-time
  87. % display!-time(" Content found in ",time()-wtime);
  88. image!-poly:=quotfail(image!-poly,image!-content);
  89. % make sure the image polynomial is primitive which includes
  90. % making the leading coefft positive (-ve content if
  91. % necessary).
  92. % If the image polynomial was of the form k*v^2 where v is
  93. % the image variable then GET.CONTENT will have taken out
  94. % one v and the k leaving the polynomial v here.
  95. % Divisibility by v here thus indicates that the image was
  96. % not square free, and so we will not be able to find a
  97. % sensible prime to use.
  98. if not didntgo quotf(image!-poly,!*k2f m!-image!-variable) then
  99. go to tryanotherset;
  100. % wtime:=time();
  101. image!-mod!-p:=find!-a!-valid!-prime(image!-lc,image!-poly,
  102. not numberp image!-content);
  103. if image!-mod!-p='not!-square!-free then goto tryanotherset;
  104. % trace!-time <<
  105. % display!-time(" Prime and image mod p found in ",time()-wtime);
  106. % wtime:=time() >>;
  107. if factored!-lc then
  108. if f!-numvec:=unique!-f!-nos(factored!-lc,image!-content,
  109. image!-set) then usable!-set!-found:=t
  110. % trace!-time
  111. % display!-time(" Nos for lc found in ",time()-wtime) >>
  112. else <<
  113. % trace!-time display!-time(" Nos for lc failed in ",
  114. % time()-wtime);
  115. if (not usable!-set!-found) and good!-set!-needed then
  116. goto tryanotherset >>
  117. end;
  118. symbolic procedure get!-new!-set forbidden!-s;
  119. % associate each variable in vars-to-kill with a random no. mod
  120. % image-set-modulus. If the boolean tagged with a variable is true then
  121. % a value of 1 or 0 is no good and so rejected, however all other
  122. % variables can take these values so they are tried exhaustively before
  123. % using truly random values. sets in forbidden!-s not allowed;
  124. begin scalar old!.m,alist,n,nextzset,w;
  125. if zero!-set!-tried then <<
  126. if !*force!-zero!-set then
  127. errorf "Zero set tried - possibly it was invalid";
  128. image!-set!-modulus:=iadd1 image!-set!-modulus;
  129. old!.m:=set!-modulus image!-set!-modulus;
  130. alist:=for each v in vars!-to!-kill collect
  131. << n:=modular!-number next!-random!-number();
  132. if n>modulus!/2 then n:=n-current!-modulus;
  133. if cdr v then <<
  134. while n=0
  135. or n=1
  136. or (n = (isub1 current!-modulus)) do
  137. n:=modular!-number next!-random!-number();
  138. if n>modulus!/2 then n:=n-current!-modulus >>;
  139. car v . n >> >>
  140. else <<
  141. old!.m:=set!-modulus image!-set!-modulus;
  142. nextzset:=car zset;
  143. alist:=for each zv in zerovarset collect <<
  144. w:=zv . car nextzset;
  145. nextzset:=cdr nextzset;
  146. w >>;
  147. if othervars then alist:=
  148. append(alist,for each v in othervars collect <<
  149. n:=modular!-number next!-random!-number();
  150. while n=0
  151. or n=1
  152. or (n = (isub1 current!-modulus)) do
  153. n:=modular!-number next!-random!-number();
  154. if n>modulus!/2 then n:=n-current!-modulus;
  155. v . n >>);
  156. if null(zset:=cdr zset) then
  157. if null save!-zset then zero!-set!-tried:=t
  158. else zset:=make!-next!-zset save!-zset;
  159. alist:=for each v in cdr kord!* collect atsoc(v,alist);
  160. % Puts the variables in alist in the right order;
  161. >>;
  162. set!-modulus old!.m;
  163. return if member(alist,forbidden!-s) then
  164. get!-new!-set forbidden!-s
  165. else alist
  166. end;
  167. %**********************************************************************
  168. % now given an image/univariate polynomial find a suitable random prime;
  169. symbolic procedure find!-a!-valid!-prime(lc!-u,u,factor!-x);
  170. % finds a suitable random prime for reducing a poly mod p.
  171. % u is the image/univariate poly. we are not allowed to use
  172. % any of the primes in forbidden!-primes (fluid).
  173. % lc!-u is either numeric or (in the multivariate case) a list of
  174. % images of the lc;
  175. begin scalar currently!-forbidden!-primes,res,prime!-count,v,w;
  176. if factor!-x then u:=multf(u,v:=!*k2f m!-image!-variable);
  177. chosen!-prime:=nil;
  178. currently!-forbidden!-primes:=forbidden!-primes;
  179. prime!-count:=1;
  180. tryanotherprime:
  181. if chosen!-prime then
  182. currently!-forbidden!-primes:=chosen!-prime .
  183. currently!-forbidden!-primes;
  184. chosen!-prime:=get!-new!-prime currently!-forbidden!-primes;
  185. set!-modulus chosen!-prime;
  186. if not atom lc!-u then <<
  187. w:=lc!-u;
  188. while w and
  189. ((domainp caar w and not(modular!-number caar w = 0))
  190. or not (domainp caar w or modular!-number lnc caar w=0))
  191. do w:=cdr w;
  192. if w then goto tryanotherprime >>
  193. else if modular!-number lc!-u=0 then goto tryanotherprime;
  194. res:=monic!-mod!-p reduce!-mod!-p u;
  195. if not square!-free!-mod!-p res then
  196. if multivariate!-input!-poly
  197. and (prime!-count:=prime!-count+1)>no!-of!-primes!-to!-try
  198. then <<no!-of!-primes!-to!-try := no!-of!-primes!-to!-try+1;
  199. res:='not!-square!-free>>
  200. else goto tryanotherprime;
  201. if factor!-x and not(res='not!-square!-free) then
  202. res:=quotfail!-mod!-p(res,!*f2mod v);
  203. return res
  204. end;
  205. symbolic procedure get!-new!-prime forbidden!-p;
  206. % get a small prime that is not in the list forbidden!-p;
  207. % we pick one of the first 10 primes if we can;
  208. if !*force!-prime then !*force!-prime
  209. else begin scalar p,primes!-done;
  210. for each pp in forbidden!-p do
  211. if pp<32 then primes!-done:=pp.primes!-done;
  212. tryagain:
  213. if null(p:=random!-teeny!-prime primes!-done) then <<
  214. p:=random!-small!-prime();
  215. primes!-done:='all >>
  216. else primes!-done:=p . primes!-done;
  217. if member(p,forbidden!-p) then goto tryagain;
  218. return p
  219. end;
  220. %***********************************************************************
  221. % find the numbers associated with each factor of the leading
  222. % coefficient of our multivariate polynomial. this will help
  223. % to distribute the leading coefficient later.;
  224. symbolic procedure unique!-f!-nos(v,cont!.u0,im!.set);
  225. % given an image set (im!.set), this finds the numbers associated with
  226. % each factor in v subject to wang's condition (2) on the image set.
  227. % this is an implementation of his algorithm n. if the condition
  228. % is met the result is a vector containing the images of each factor
  229. % in v, otherwise the result is nil;
  230. begin scalar d,k,q,r,lc!.image!.vec;
  231. % v's integer factor is at the front: ;
  232. k:=length cdr v;
  233. % no. of non-trivial factors of v;
  234. if not numberp cont!.u0 then cont!.u0:=lc cont!.u0;
  235. putv(d:=mkvect k,0,abs(cont!.u0 * car v));
  236. % d will contain the special numbers to be used in the
  237. % loop below;
  238. putv(lc!.image!.vec:=mkvect k,0,abs(cont!.u0 * car v));
  239. % vector for result with 0th entry filled in;
  240. v:=cdr v;
  241. % throw away integer factor of v;
  242. % k is no. of non-trivial factors (say f(i)) in v;
  243. % d will contain the nos. associated with each f(i);
  244. % v is now a list of the f(i) (and their multiplicities);
  245. for i:=1:k do
  246. << q:=abs make!-image(caar v,im!.set);
  247. putv(lc!.image!.vec,i,q);
  248. v:=cdr v;
  249. for j:=isub1 i step -1 until 0 do
  250. << r:=getv(d,j);
  251. while not onep r do
  252. << r:=gcdn(r,q); q:=q/r >>;
  253. if onep q then <<lc!.image!.vec:=nil; j := -1>>
  254. % if q=1 here then we have failed the condition so exit;
  255. >>;
  256. if null lc!.image!.vec then i := k+1 else putv(d,i,q);
  257. % else q is the ith number we want;
  258. >>;
  259. return lc!.image!.vec
  260. end;
  261. symbolic procedure get!.content u;
  262. % u is a univariate square free poly. gets the content of u (=integer);
  263. % if lc u is negative then the minus sign is pulled out as well;
  264. % nb. the content includes the variable if it is a factor of u;
  265. begin scalar c;
  266. c:=if poly!-minusp u then -(numeric!-content u)
  267. else numeric!-content u;
  268. if not didntgo quotf(u,!*k2f m!-image!-variable) then
  269. c:=adjoin!-term(mksp(m!-image!-variable,1),c,polyzero);
  270. return c
  271. end;
  272. %********************************************************************;
  273. % finally we have the routines that use the numbers generated
  274. % by unique.f.nos to determine the true leading coeffts in
  275. % the multivariate factorization we are doing and which image
  276. % factors will grow up to have which true leading coefft.
  277. %********************************************************************;
  278. symbolic procedure distribute!.lc(r,im!.factors,s,v);
  279. % v is the factored lc of a poly, say u, whose image factors (r of
  280. % them) are in the vector im.factors. s is a list containing the
  281. % image information including the image set, the image poly etc.
  282. % this uses wang's ideas for distributing the factors in v over
  283. % those in im.factors. result is (delta . vector of the lc's of
  284. % the full factors of u) , where delta is the remaining integer part
  285. % of the lc that we have been unable to distribute. ;
  286. (lambda factor!-level;
  287. begin scalar k,delta,div!.count,q,uf,i,d,max!.mult,f,numvec,
  288. dvec,wvec,dtwid,w;
  289. delta:=get!-image!-content s;
  290. % the content of the u image poly;
  291. dist!.lc!.msg1(delta,im!.factors,r,s,v);
  292. v:=cdr v;
  293. % we are not interested in the numeric factors of v;
  294. k:=length v;
  295. % number of things to distribute;
  296. numvec:=get!-f!-numvec s;
  297. % nos. associated with factors in v;
  298. dvec:=mkvect r;
  299. wvec:=mkvect r;
  300. for j:=1:r do <<
  301. putv(dvec,j,1);
  302. putv(wvec,j,delta*lc getv(im!.factors,j)) >>;
  303. % result lc's will go into dvec which we initialize to 1's;
  304. % wvec is a work vector that we use in the division process
  305. % below;
  306. v:=reverse v;
  307. for j:=k step -1 until 1 do
  308. << % (for each factor in v, call it f(j) );
  309. f:=caar v;
  310. % f(j) itself;
  311. max!.mult:=cdar v;
  312. % multiplicity of f(j) in v (=lc u);
  313. v:=cdr v;
  314. d:=getv(numvec,j);
  315. % number associated with f(j);
  316. i:=1; % we trial divide d into lc of each image
  317. % factor starting with 1st;
  318. div!.count:=0;
  319. % no. of d's that have been distributed;
  320. factor!-trace <<
  321. prin2!* "f("; prin2!* j; prin2!* ")= "; printsf f;
  322. prin2!* "There are "; prin2!* max!.mult;
  323. printstr " of these in the leading coefficient.";
  324. prin2!* "The absolute value of the image of f("; prin2!* j;
  325. prin2!* ")= "; printstr d >>;
  326. while ilessp(div!.count,max!.mult)
  327. and not igreaterp(i,r) do
  328. << q:=divide(getv(wvec,i),d);
  329. % first trial division;
  330. factor!-trace <<
  331. prin2!* " Trial divide into ";
  332. prin2!* getv(wvec,i); printstr " :" >>;
  333. while (zerop cdr q) and ilessp(div!.count,max!.mult) do
  334. << putv(dvec,i,multf(getv(dvec,i),f));
  335. % f(j) belongs in lc of ith factor;
  336. factor!-trace <<
  337. prin2!* " It goes so an f("; prin2!* j;
  338. prin2!* ") belongs in ";
  339. printsf getv(im!.factors,i);
  340. printstr " Try again..." >>;
  341. div!.count:=iadd1 div!.count;
  342. % another d done;
  343. putv(wvec,i,car q);
  344. % save the quotient for next factor to distribute;
  345. q:=divide(car q,d);
  346. % try again;
  347. >>;
  348. i:=iadd1 i;
  349. % as many d's as possible have gone into that
  350. % factor so now try next factor;
  351. factor!-trace
  352. <<printstr " no good so try another factor ..." >>>>;
  353. % at this point the whole of f(j) should have been
  354. % distributed by dividing d the maximum no. of times
  355. % (= max!.mult), otherwise we have an extraneous factor;
  356. if ilessp(div!.count,max!.mult) then
  357. <<bad!-case:=t; div!.count := max!.mult>>
  358. >>;
  359. if bad!-case then return;
  360. dist!.lc!.msg2(dvec,im!.factors,r);
  361. if onep delta then
  362. << for j:=1:r do <<
  363. w:=lc getv(im!.factors,j) /
  364. evaluate!-in!-order(getv(dvec,j),get!-image!-set s);
  365. if w<0 then begin
  366. scalar oldpoly;
  367. delta:= -delta;
  368. oldpoly:=getv(im!.factors,j);
  369. putv(im!.factors,j,negf oldpoly);
  370. % to keep the leading coefficients positive we negate the
  371. % image factors when necessary;
  372. multiply!-alphas(-1,oldpoly,getv(im!.factors,j));
  373. % remember to fix the alphas as well;
  374. end;
  375. putv(dvec,j,multf(abs w,getv(dvec,j))) >>;
  376. dist!.lc!.msg3(dvec,im!.factors,r);
  377. return (delta . dvec)
  378. >>;
  379. % if delta=1 then we know the true lc's exactly so put in their
  380. % integer contents and return with result.
  381. % otherwise try spreading delta out over the factors: ;
  382. dist!.lc!.msg4 delta;
  383. for j:=1:r do
  384. << dtwid:=evaluate!-in!-order(getv(dvec,j),get!-image!-set s);
  385. uf:=getv(im!.factors,j);
  386. d:=gcddd(lc uf,dtwid);
  387. putv(dvec,j,multf(lc uf/d,getv(dvec,j)));
  388. putv(im!.factors,j,multf(dtwid/d,uf));
  389. % have to fiddle the image factors by an integer multiple;
  390. multiply!-alphas!-recip(dtwid/d,uf,getv(im!.factors,j));
  391. % fix the alphas;
  392. delta:=delta/(dtwid/d)
  393. >>;
  394. % now we've done all we can to distribute delta so we return with
  395. % what's left: ;
  396. if delta<=0 then
  397. errorf list("FINAL DELTA IS -VE IN DISTRIBUTE!.LC",delta);
  398. factor!-trace <<
  399. printstr " Finally we have:";
  400. for j:=1:r do <<
  401. prinsf getv(im!.factors,j);
  402. prin2!* " with l.c. ";
  403. printsf getv(dvec,j) >> >>;
  404. return (delta . dvec)
  405. end) (factor!-level * 10);
  406. symbolic procedure dist!.lc!.msg1(delta,im!.factors,r,s,v);
  407. factor!-trace <<
  408. terpri(); terpri();
  409. printstr "We have a polynomial whose image factors (call";
  410. printstr "them the IM-factors) are:";
  411. prin2!* delta; printstr " (= numeric content, delta)";
  412. printvec(" f(",r,")= ",im!.factors);
  413. prin2!* " wrt the image set: ";
  414. for each x in get!-image!-set s do <<
  415. prinvar car x; prin2!* "="; prin2!* cdr x; prin2!* ";" >>;
  416. terpri!*(nil);
  417. printstr "We also have its true multivariate leading";
  418. printstr "coefficient whose factors (call these the";
  419. printstr "LC-factors) are:";
  420. fac!-printfactors v;
  421. printstr "We want to determine how these LC-factors are";
  422. printstr "distributed over the leading coefficients of each";
  423. printstr "IM-factor. This enables us to feed the resulting";
  424. printstr "image factors into a multivariate Hensel";
  425. printstr "construction.";
  426. printstr "We distribute each LC-factor in turn by dividing";
  427. printstr "its image into delta times the leading coefficient";
  428. printstr "of each IM-factor until it finds one that it";
  429. printstr "divides exactly. The image set is chosen such that";
  430. printstr "this will only happen for the IM-factors to which";
  431. printstr "this LC-factor belongs - (there may be more than";
  432. printstr "one if the LC-factor occurs several times in the";
  433. printstr "leading coefficient of the original polynomial).";
  434. printstr "This choice also requires that we distribute the";
  435. printstr "LC-factors in a specific order:"
  436. >>;
  437. symbolic procedure dist!.lc!.msg2(dvec,im!.factors,r);
  438. factor!-trace <<
  439. printstr "The leading coefficients are now correct to within an";
  440. printstr "integer factor and are as follows:";
  441. for j:=1:r do <<
  442. prinsf getv(im!.factors,j);
  443. prin2!* " with l.c. ";
  444. printsf getv(dvec,j) >> >>;
  445. symbolic procedure dist!.lc!.msg3(dvec,im!.factors,r);
  446. factor!-trace <<
  447. printstr "Since delta=1, we have no non-trivial content of the";
  448. printstr
  449. "image to deal with so we know the true leading coefficients";
  450. printstr
  451. "exactly. We fix the signs of the IM-factors to match those";
  452. printstr "of their true leading coefficients:";
  453. for j:=1:r do <<
  454. prinsf getv(im!.factors,j);
  455. prin2!* " with l.c. ";
  456. printsf getv(dvec,j) >> >>;
  457. symbolic procedure dist!.lc!.msg4 delta;
  458. factor!-trace <<
  459. prin2!* " Here delta is not 1 meaning that we have a content, ";
  460. printstr delta;
  461. printstr "of the image to distribute among the factors somehow.";
  462. printstr "For each IM-factor we can divide its leading";
  463. printstr "coefficient by the image of its determined leading";
  464. printstr "coefficient and see if there is a non-trivial result.";
  465. printstr "This will indicate a factor of delta belonging to this";
  466. printstr "IM-factor's leading coefficient." >>;
  467. endmodule;
  468. end;