modpoly.red 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. module modpoly; % Routines for performing arithmetic on multivariate
  2. % polynomials with coefficients that are modular
  3. % numbers as defined by modular!-plus etc.
  4. % Authors: A. C. Norman and P. M. A. Moore, 1979.
  5. fluid '(current!-modulus
  6. exact!-quotient!-flag
  7. m!-image!-variable
  8. modulus!/2
  9. reduction!-count);
  10. % Note that the datastructure used is the same as that used in
  11. % REDUCE except that it is assumed that domain elements are atomic.
  12. symbolic smacro procedure comes!-before(p1,p2);
  13. % Similar to the REDUCE function ORDPP, but does not cater for non-
  14. % commutative terms and assumes that exponents are small integers.
  15. (car p1=car p2 and igreaterp(cdr p1,cdr p2)) or
  16. (not(car p1=car p2) and ordop(car p1,car p2));
  17. symbolic procedure plus!-mod!-p(a,b);
  18. % form the sum of the two polynomials a and b working over the
  19. % ground domain defined by the routines % modular!-plus,
  20. % modular!-times etc. the inputs to this % routine are assumed to
  21. % have coefficients already in the required domain.
  22. if null a then b
  23. else if null b then a
  24. else if domainp a then
  25. if domainp b then !*n2f modular!-plus(a,b)
  26. else (lt b) .+ plus!-mod!-p(a,red b)
  27. else if domainp b then (lt a) .+ plus!-mod!-p(red a,b)
  28. else if lpow a = lpow b then
  29. adjoin!-term(lpow a,
  30. plus!-mod!-p(lc a,lc b),plus!-mod!-p(red a,red b))
  31. else if comes!-before(lpow a,lpow b) then
  32. (lt a) .+ plus!-mod!-p(red a,b)
  33. else (lt b) .+ plus!-mod!-p(a,red b);
  34. symbolic procedure times!-mod!-p(a,b);
  35. if (null a) or (null b) then nil
  36. else if domainp a then multiply!-by!-constant!-mod!-p(b,a)
  37. else if domainp b then multiply!-by!-constant!-mod!-p(a,b)
  38. else if mvar a=mvar b then plus!-mod!-p(
  39. plus!-mod!-p(times!-term!-mod!-p(lt a,b),
  40. times!-term!-mod!-p(lt b,red a)),
  41. times!-mod!-p(red a,red b))
  42. else if ordop(mvar a,mvar b) then
  43. adjoin!-term(lpow a,times!-mod!-p(lc a,b),times!-mod!-p(red a,b))
  44. else adjoin!-term(lpow b,
  45. times!-mod!-p(a,lc b),times!-mod!-p(a,red b));
  46. symbolic procedure times!-term!-mod!-p(term,b);
  47. % Multiply the given polynomial by the given term.
  48. if null b then nil
  49. else if domainp b then
  50. adjoin!-term(tpow term,
  51. multiply!-by!-constant!-mod!-p(tc term,b),nil)
  52. else if tvar term=mvar b then
  53. adjoin!-term(mksp(tvar term,iplus2(tdeg term,ldeg b)),
  54. times!-mod!-p(tc term,lc b),
  55. times!-term!-mod!-p(term,red b))
  56. else if ordop(tvar term,mvar b) then
  57. adjoin!-term(tpow term,times!-mod!-p(tc term,b),nil)
  58. else adjoin!-term(lpow b,
  59. times!-term!-mod!-p(term,lc b),
  60. times!-term!-mod!-p(term,red b));
  61. symbolic procedure difference!-mod!-p(a,b);
  62. plus!-mod!-p(a,minus!-mod!-p b);
  63. symbolic procedure minus!-mod!-p a;
  64. if null a then nil
  65. else if domainp a then modular!-minus a
  66. else (lpow a .* minus!-mod!-p lc a) .+ minus!-mod!-p red a;
  67. symbolic procedure reduce!-mod!-p a;
  68. % Converts a multivariate poly from normal into modular polynomial.
  69. if null a then nil
  70. else if domainp a then !*n2f modular!-number a
  71. else adjoin!-term(lpow a,reduce!-mod!-p lc a,reduce!-mod!-p red a);
  72. symbolic procedure monic!-mod!-p a;
  73. % This procedure can only cope with polys that have a numeric
  74. % leading coeff.
  75. if a=nil then nil
  76. else if domainp a then 1
  77. else if lc a = 1 then a
  78. else if not domainp lc a then
  79. errorf "LC NOT NUMERIC IN MONIC-MOD-P"
  80. else multiply!-by!-constant!-mod!-p(a,
  81. modular!-reciprocal lc a);
  82. symbolic procedure quotfail!-mod!-p(a,b);
  83. % Form quotient A/B, but complain if the division is not exact.
  84. begin scalar c;
  85. exact!-quotient!-flag:=t;
  86. c:=quotient!-mod!-p(a,b);
  87. if exact!-quotient!-flag then return c
  88. else errorf "QUOTIENT NOT EXACT (MOD P)"
  89. end;
  90. symbolic procedure quotient!-mod!-p(a,b);
  91. % Truncated quotient of a by b.
  92. if null b then errorf "B=0 IN QUOTIENT-MOD-P"
  93. else if domainp b then multiply!-by!-constant!-mod!-p(a,
  94. modular!-reciprocal b)
  95. else if a=nil then nil
  96. else if domainp a then exact!-quotient!-flag:=nil
  97. else if mvar a=mvar b then xquotient!-mod!-p(a,b,mvar b)
  98. else if ordop(mvar a,mvar b) then
  99. adjoin!-term(lpow a,
  100. quotient!-mod!-p(lc a,b),
  101. quotient!-mod!-p(red a,b))
  102. else exact!-quotient!-flag:=nil;
  103. symbolic procedure xquotient!-mod!-p(a,b,v);
  104. % Truncated quotient a/b given that b is nontrivial.
  105. if a=nil then nil
  106. else if (domainp a) or (not(mvar a=v)) or
  107. ilessp(ldeg a,ldeg b) then exact!-quotient!-flag:=nil
  108. else if ldeg a = ldeg b then begin scalar w;
  109. w:=quotient!-mod!-p(lc a,lc b);
  110. if difference!-mod!-p(a,times!-mod!-p(w,b)) then
  111. exact!-quotient!-flag:=nil;
  112. return w
  113. end
  114. else begin scalar term;
  115. term:=mksp(mvar a,idifference(ldeg a,ldeg b)) .*
  116. quotient!-mod!-p(lc a,lc b);
  117. % That is the leading term of the quotient. Now subtract term*b from
  118. % a.
  119. a:=plus!-mod!-p(red a,
  120. times!-term!-mod!-p(negate!-term term,red b));
  121. % or a:=a-b*term given leading terms must cancel.
  122. return term .+ xquotient!-mod!-p(a,b,v)
  123. end;
  124. symbolic procedure negate!-term term;
  125. % Negate a term.
  126. tpow term .* minus!-mod!-p tc term;
  127. symbolic procedure remainder!-mod!-p(a,b);
  128. % Remainder when a is divided by b.
  129. if null b then errorf "B=0 IN REMAINDER-MOD-P"
  130. else if domainp b then nil
  131. else if domainp a then a
  132. else xremainder!-mod!-p(a,b,mvar b);
  133. symbolic procedure xremainder!-mod!-p(a,b,v);
  134. % Remainder when the modular polynomial a is divided by b, given that
  135. % b is non degenerate.
  136. if (domainp a) or (not(mvar a=v)) or ilessp(ldeg a,ldeg b) then a
  137. else begin
  138. scalar q,w;
  139. q:=quotient!-mod!-p(minus!-mod!-p lc a,lc b);
  140. % compute -lc of quotient.
  141. w:=idifference(ldeg a,ldeg b); %ldeg of quotient;
  142. if w=0 then a:=plus!-mod!-p(red a,
  143. multiply!-by!-constant!-mod!-p(red b,q))
  144. else
  145. a:=plus!-mod!-p(red a,times!-term!-mod!-p(
  146. mksp(mvar b,w) .* q,red b));
  147. % The above lines of code use red a and red b because by construc-
  148. % tion the leading terms of the required % answers will cancel out.
  149. return xremainder!-mod!-p(a,b,v)
  150. end;
  151. symbolic procedure multiply!-by!-constant!-mod!-p(a,n);
  152. % Multiply the polynomial a by the constant n.
  153. if null a then nil
  154. else if n=1 then a
  155. else if domainp a then !*n2f modular!-times(a,n)
  156. else adjoin!-term(lpow a,multiply!-by!-constant!-mod!-p(lc a,n),
  157. multiply!-by!-constant!-mod!-p(red a,n));
  158. symbolic procedure gcd!-mod!-p(a,b);
  159. % Return the monic gcd of the two modular univariate polynomials a
  160. % and b. Set REDUCTION-COUNT to the number of steps taken in the
  161. % process.
  162. << reduction!-count := 0;
  163. if null a then monic!-mod!-p b
  164. else if null b then monic!-mod!-p a
  165. else if domainp a then 1
  166. else if domainp b then 1
  167. else if igreaterp(ldeg a,ldeg b) then
  168. ordered!-gcd!-mod!-p(a,b)
  169. else ordered!-gcd!-mod!-p(b,a) >>;
  170. symbolic procedure ordered!-gcd!-mod!-p(a,b);
  171. % As above, but deg a > deg b.
  172. begin scalar steps;
  173. steps := 0;
  174. top:
  175. a := reduce!-degree!-mod!-p(a,b);
  176. if null a then return monic!-mod!-p b;
  177. steps := steps + 1;
  178. if domainp a then <<
  179. reduction!-count := reduction!-count+steps;
  180. return 1 >>
  181. else if ldeg a<ldeg b then begin
  182. scalar w;
  183. reduction!-count := reduction!-count + steps;
  184. steps := 0;
  185. w := a; a := b; b := w
  186. end;
  187. go to top
  188. end;
  189. symbolic procedure reduce!-degree!-mod!-p(a,b);
  190. % Compute A-Q*B where Q is a single term chosen so that the result
  191. % has lower degree than A did.
  192. begin
  193. scalar q,w;
  194. q:=modular!-quotient(modular!-minus lc a,lc b);
  195. % compute -lc of quotient;
  196. w:=idifference(ldeg a,ldeg b); %ldeg of quotient;
  197. % The next lines of code use red a and red b because by construction
  198. % the leading terms of the required answers will cancel out.
  199. if w=0 then return plus!-mod!-p(red a,
  200. multiply!-by!-constant!-mod!-p(red b,q))
  201. else return plus!-mod!-p(red a,times!-term!-mod!-p(
  202. mksp(mvar b,w) .* q,red b))
  203. end;
  204. symbolic procedure derivative!-mod!-p a;
  205. % Derivative of a wrt its main variable.
  206. if domainp a then nil
  207. else if ldeg a=1 then lc a
  208. else derivative!-mod!-p!-1(a,mvar a);
  209. symbolic procedure derivative!-mod!-p!-1(a,v);
  210. if domainp a then nil
  211. else if not(mvar a=v) then nil
  212. else if ldeg a=1 then lc a
  213. else adjoin!-term(mksp(v,isub1 ldeg a),
  214. multiply!-by!-constant!-mod!-p(lc a,
  215. modular!-number ldeg a),
  216. derivative!-mod!-p!-1(red a,v));
  217. symbolic procedure square!-free!-mod!-p a;
  218. % predicate that tests if a is square-free as a modular univariate
  219. % polynomial.
  220. domainp a or domainp gcd!-mod!-p(a,derivative!-mod!-p a);
  221. symbolic procedure evaluate!-mod!-p(a,v,n);
  222. % Evaluate polynomial A at the point V=N.
  223. if domainp a then a
  224. else if n=0 then evaluate!-mod!-p(a,v,nil)
  225. else if v=nil then errorf "Variable=NIL in EVALUATE-MOD-P"
  226. else if mvar a=v then horner!-rule!-mod!-p(lc a,ldeg a,red a,n,v)
  227. else adjoin!-term(lpow a,
  228. evaluate!-mod!-p(lc a,v,n),
  229. evaluate!-mod!-p(red a,v,n));
  230. symbolic procedure horner!-rule!-mod!-p(v,degg,a,n,var);
  231. % V is the running total, and it must be multiplied by n**deg and
  232. % added to the value of a at n.
  233. if domainp a or not(mvar a=var)
  234. then if null n or zerop n then a
  235. else <<v:=times!-mod!-p(v,expt!-mod!-p(n,degg));
  236. plus!-mod!-p(a,v)>>
  237. else begin scalar newdeg;
  238. newdeg:=ldeg a;
  239. return horner!-rule!-mod!-p(if null n or zerop n then lc a
  240. else plus!-mod!-p(lc a,
  241. times!-mod!-p(v,expt!-mod!-p(n,idifference(degg,newdeg)))),
  242. newdeg,red a,n,var)
  243. end;
  244. symbolic procedure expt!-mod!-p(a,n);
  245. % a**n.
  246. if n=0 then 1
  247. else if n=1 then a
  248. else begin scalar w,x;
  249. w:=divide(n,2);
  250. x:=expt!-mod!-p(a,car w);
  251. x:=times!-mod!-p(x,x);
  252. if not (cdr w = 0) then x:=times!-mod!-p(x,a);
  253. return x
  254. end;
  255. symbolic procedure make!-bivariate!-mod!-p(u,imset,v);
  256. % Substitute into U for all variables in IMSET which should result in
  257. % a bivariate poly. One variable is M-IMAGE-VARIABLE and V is the
  258. % other U is modular multivariate with these two variables at top 2
  259. % levels - V at 2nd level.
  260. if domainp u then u
  261. else if mvar u = m!-image!-variable then
  262. adjoin!-term(lpow u,make!-univariate!-mod!-p(lc u,imset,v),
  263. make!-bivariate!-mod!-p(red u,imset,v))
  264. else make!-univariate!-mod!-p(u,imset,v);
  265. symbolic procedure make!-univariate!-mod!-p(u,imset,v);
  266. % Substitute into U for all variables in IMSET giving a univariate
  267. % poly in V. U is modular multivariate with V at top level.
  268. if domainp u then u
  269. else if mvar u = v then
  270. adjoin!-term(lpow u,!*n2f evaluate!-in!-order!-mod!-p(lc u,imset),
  271. make!-univariate!-mod!-p(red u,imset,v))
  272. else !*n2f evaluate!-in!-order!-mod!-p(u,imset);
  273. symbolic procedure evaluate!-in!-order!-mod!-p(u,imset);
  274. % Makes an image of u wrt imageset, imset, using Horner's rule.
  275. % Result should be purely numeric (and modular).
  276. if domainp u then !*d2n u
  277. else if mvar u=caar imset then
  278. horner!-rule!-in!-order!-mod!-p(
  279. evaluate!-in!-order!-mod!-p(lc u,cdr imset),ldeg u,red u,imset)
  280. else evaluate!-in!-order!-mod!-p(u,cdr imset);
  281. symbolic procedure horner!-rule!-in!-order!-mod!-p(c,degg,a,vset);
  282. % C is running total and a is what is left.
  283. if domainp a then modular!-plus(!*d2n a,
  284. modular!-times(c,modular!-expt(cdar vset,degg)))
  285. else if not(mvar a=caar vset) then
  286. modular!-plus(
  287. evaluate!-in!-order!-mod!-p(a,cdr vset),
  288. modular!-times(c,modular!-expt(cdar vset,degg)))
  289. else begin scalar newdeg;
  290. newdeg:=ldeg a;
  291. return horner!-rule!-in!-order!-mod!-p(
  292. modular!-plus(
  293. evaluate!-in!-order!-mod!-p(lc a,cdr vset),
  294. modular!-times(c,
  295. modular!-expt(cdar vset,(idifference(degg,newdeg))))),
  296. newdeg,red a,vset)
  297. end;
  298. symbolic procedure make!-modular!-symmetric a;
  299. % Input is a multivariate MODULAR poly A with nos in range 0->(p-1).
  300. % This folds it onto the symmetric range (-p/2)->(p/2).
  301. if null a then nil
  302. else if domainp a then
  303. if a>modulus!/2 then !*n2f(a - current!-modulus)
  304. else a
  305. else adjoin!-term(lpow a,make!-modular!-symmetric lc a,
  306. make!-modular!-symmetric red a);
  307. endmodule;
  308. end;