modsr.red 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. module modsr; % Modular Solve and Roots.
  2. % Author: Herbert Melenk, ZIB Berlin, Jan 95.
  3. create!-package('(modsr modsqrt modroots modsolve),'(solve));
  4. fluid '(current!-modulus);
  5. % Some routines from solve and factor(modpoly) are needed.
  6. load!-package 'solve;
  7. load!-package 'factor;
  8. % Now a few things that MIGHT have been in the factorizer but were not
  9. % It is quite possible that as a matter of style these few functions
  10. % should be put into factor.red, even though they are not used there,
  11. % since that way they live near their friends and are more generally
  12. % useful???
  13. symbolic procedure general!-evaluate!-mod!-p(a,v,n);
  14. % Evaluate polynomial A at the point V=N.
  15. if domainp a then a
  16. else if n=0 then general!-evaluate!-mod!-p(a,v,nil)
  17. else if v=nil then errorf "Variable=NIL in GENERAL-EVALUATE-MOD-P"
  18. else if mvar a=v
  19. then general!-horner!-rule!-mod!-p(lc a,ldeg a,red a,n,v)
  20. else adjoin!-term(lpow a,
  21. general!-evaluate!-mod!-p(lc a,v,n),
  22. general!-evaluate!-mod!-p(red a,v,n));
  23. symbolic procedure general!-horner!-rule!-mod!-p(v,degg,a,n,var);
  24. % V is the running total, and it must be multiplied by n**deg and
  25. % added to the value of a at n.
  26. if domainp a or not(mvar a=var)
  27. then if null n or zerop n then a
  28. else <<v:=general!-times!-mod!-p(v,
  29. general!-expt!-mod!-p(n,degg));
  30. general!-plus!-mod!-p(a,v)>>
  31. else begin scalar newdeg;
  32. newdeg:=ldeg a;
  33. return general!-horner!-rule!-mod!-p(
  34. if null n or zerop n then lc a
  35. else general!-plus!-mod!-p(lc a,
  36. general!-times!-mod!-p(v,
  37. general!-expt!-mod!-p(n,idifference(degg,newdeg)))),
  38. newdeg,red a,n,var)
  39. end;
  40. symbolic procedure general!-expt!-mod!-p(a,n);
  41. % a**n.
  42. if n=0 then 1
  43. else if n=1 then a
  44. else begin scalar w,x;
  45. w:=divide(n,2);
  46. x:=general!-expt!-mod!-p(a,car w);
  47. x:=general!-times!-mod!-p(x,x);
  48. if not (cdr w = 0) then x:=general!-times!-mod!-p(x,a);
  49. return x
  50. end;
  51. symbolic procedure general!-monic!-mod!-p a;
  52. % This procedure can only cope with polys that have a numeric
  53. % leading coeff.
  54. if a=nil then nil
  55. else if domainp a then 1
  56. else if lc a = 1 then a
  57. else if not domainp lc a then
  58. errorf "LC NOT NUMERIC IN GENERAL-MONIC-MOD-P"
  59. else general!-multiply!-by!-constant!-mod!-p(a,
  60. general!-modular!-reciprocal lc a);
  61. symbolic procedure general!-quotient!-mod!-p(a,b);
  62. % Truncated quotient of a by b.
  63. if null b then errorf "B=0 IN GENERAL-QUOTIENT-MOD-P"
  64. else if domainp b then general!-multiply!-by!-constant!-mod!-p(a,
  65. general!-modular!-reciprocal b)
  66. else if a=nil then nil
  67. else if domainp a then exact!-quotient!-flag:=nil
  68. else if mvar a=mvar b then general!-xquotient!-mod!-p(a,b,mvar b)
  69. else if ordop(mvar a,mvar b) then
  70. adjoin!-term(lpow a,
  71. general!-quotient!-mod!-p(lc a,b),
  72. general!-quotient!-mod!-p(red a,b))
  73. else exact!-quotient!-flag:=nil;
  74. symbolic procedure general!-xquotient!-mod!-p(a,b,v);
  75. % Truncated quotient a/b given that b is nontrivial.
  76. if a=nil then nil
  77. else if (domainp a) or (not(mvar a=v)) or
  78. ilessp(ldeg a,ldeg b) then exact!-quotient!-flag:=nil
  79. else if ldeg a = ldeg b then begin scalar w;
  80. w:=general!-quotient!-mod!-p(lc a,lc b);
  81. if general!-difference!-mod!-p(a,general!-times!-mod!-p(w,b)) then
  82. exact!-quotient!-flag:=nil;
  83. return w
  84. end
  85. else begin scalar term;
  86. term:=mksp(mvar a,idifference(ldeg a,ldeg b)) .*
  87. general!-quotient!-mod!-p(lc a,lc b);
  88. % That is the leading term of the quotient. Now subtract term*b from
  89. % a.
  90. a:=general!-plus!-mod!-p(red a,
  91. general!-times!-term!-mod!-p(general!-negate!-term term,
  92. red b));
  93. % or a:=a-b*term given leading terms must cancel.
  94. return term .+ general!-xquotient!-mod!-p(a,b,v)
  95. end;
  96. symbolic procedure general!-negate!-term term;
  97. % Negate a term.
  98. tpow term .* general!-minus!-mod!-p tc term;
  99. symbolic procedure general!-remainder!-mod!-p(a,b);
  100. % Remainder when a is divided by b.
  101. if null b then errorf "B=0 IN GENERAL-REMAINDER-MOD-P"
  102. else if domainp b then nil
  103. else if domainp a then a
  104. else general!-xremainder!-mod!-p(a,b,mvar b);
  105. symbolic procedure general!-xremainder!-mod!-p(a,b,v);
  106. % Remainder when the modular polynomial a is divided by b, given that
  107. % b is non degenerate.
  108. if (domainp a) or (not(mvar a=v)) or ilessp(ldeg a,ldeg b) then a
  109. else begin
  110. scalar q,w;
  111. q:=general!-quotient!-mod!-p(general!-minus!-mod!-p lc a,lc b);
  112. % compute -lc of quotient.
  113. w:=idifference(ldeg a,ldeg b); %ldeg of quotient;
  114. if w=0 then a:=general!-plus!-mod!-p(red a,
  115. general!-multiply!-by!-constant!-mod!-p(red b,q))
  116. else
  117. a:=general!-plus!-mod!-p(red a,general!-times!-term!-mod!-p(
  118. mksp(mvar b,w) .* q,red b));
  119. % The above lines of code use red a and red b because by construc-
  120. % tion the leading terms of the required % answers will cancel out.
  121. return general!-xremainder!-mod!-p(a,b,v)
  122. end;
  123. symbolic procedure general!-multiply!-by!-constant!-mod!-p(a,n);
  124. % Multiply the polynomial a by the constant n.
  125. if null a then nil
  126. else if n=1 then a
  127. else if domainp a then !*n2f general!-modular!-times(a,n)
  128. else adjoin!-term(lpow a,
  129. general!-multiply!-by!-constant!-mod!-p(lc a,n),
  130. general!-multiply!-by!-constant!-mod!-p(red a,n));
  131. symbolic procedure general!-gcd!-mod!-p(a,b);
  132. % Return the monic gcd of the two modular univariate polynomials a
  133. % and b. Set REDUCTION-COUNT to the number of steps taken in the
  134. % process.
  135. << reduction!-count := 0;
  136. if null a then monic!-mod!-p b
  137. else if null b then monic!-mod!-p a
  138. else if domainp a then 1
  139. else if domainp b then 1
  140. else if igreaterp(ldeg a,ldeg b) then
  141. general!-ordered!-gcd!-mod!-p(a,b)
  142. else general!-ordered!-gcd!-mod!-p(b,a) >>;
  143. symbolic procedure general!-ordered!-gcd!-mod!-p(a,b);
  144. % As above, but deg a > deg b.
  145. begin scalar steps;
  146. steps := 0;
  147. top:
  148. a := general!-reduce!-degree!-mod!-p(a,b);
  149. if null a then return general!-monic!-mod!-p b;
  150. steps := steps + 1;
  151. if domainp a then <<
  152. reduction!-count := reduction!-count+steps;
  153. return 1 >>
  154. else if ldeg a<ldeg b then begin
  155. scalar w;
  156. reduction!-count := reduction!-count + steps;
  157. steps := 0;
  158. w := a; a := b; b := w
  159. end;
  160. go to top
  161. end;
  162. symbolic procedure general!-reduce!-degree!-mod!-p(a,b);
  163. % Compute A-Q*B where Q is a single term chosen so that the result
  164. % has lower degree than A did.
  165. begin
  166. scalar q,w;
  167. q:=general!-modular!-quotient(general!-modular!-minus lc a,lc b);
  168. % compute -lc of quotient;
  169. w:=idifference(ldeg a,ldeg b); %ldeg of quotient;
  170. % The next lines of code use red a and red b because by construction
  171. % the leading terms of the required answers will cancel out.
  172. if w=0 then return general!-plus!-mod!-p(red a,
  173. general!-multiply!-by!-constant!-mod!-p(red b,q))
  174. else return general!-plus!-mod!-p(red a,
  175. general!-times!-term!-mod!-p(mksp(mvar b,w) .* q,
  176. red b))
  177. end;
  178. %%%%%%%
  179. symbolic procedure modp(a,p);
  180. <<a:=remainder(a,p); if a<0 then a+p else a>>;
  181. symbolic procedure lowestdeg(f,x,n);
  182. if null f then n else
  183. if domainp f or mvar f neq x then 0 else
  184. lowestdeg(red f,x,ldeg f);
  185. symbolic procedure reduce!-mod!-p!*(f,p);
  186. (general!-reduce!-mod!-p f) where current!-modulus = p;
  187. symbolic procedure moduntag f;
  188. if eqcar(f,'!:mod!:) then cdr f else
  189. if atom f then f else
  190. moduntag car f . moduntag cdr f;
  191. symbolic procedure safe!-modrecip u;
  192. % Return 1/u or nil.
  193. begin scalar q,!*msg,!*protfg;
  194. !*msg := nil; !*protfg := t;
  195. if eqcar(u,'!:mod!:) then u := cdr u;
  196. q := errorset({'general!-modular!-reciprocal, u},nil,nil);
  197. erfg!* := nil;
  198. return if errorp q then nil else car q
  199. end;
  200. endmodule;
  201. end;