modroots.red 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. module modroots; % Roots of a univariate polynomial mod m,
  2. % m not necessarily prime.
  3. % Author: Herbert Melenk, ZIB Berlin.
  4. % Algebraic interface: m_roots(polynomial, modulus);
  5. symbolic procedure modroots0(f,m);
  6. % f: univariate standard form with modular coeffients,
  7. % m: positive integer modulus.
  8. % Algorithm: compute roots modulo the biggest factor of m
  9. % and lift these for the remaining factors. During lifing
  10. % the number of factors may change in both directions.
  11. begin scalar ml;
  12. ml := sort(for each q in zfactor m join
  13. for i:=1:cdr q collect car q,'lessp);
  14. return sort(modroots1(f,ml),'lessp);
  15. end;
  16. symbolic procedure modroots1(f,ml);
  17. if null cdr ml then modroots2(f,car ml,nil) else
  18. begin scalar f1,p,q,pq,r,s,x,y;
  19. p:=car ml; ml:=cdr ml;
  20. r := modroots1(f,ml);
  21. if null r then return nil;
  22. x:=mvar f; y:=gensym();
  23. q:=for each m in ml product m;
  24. pq:=p*q;
  25. % lift roots to p*q:
  26. % if f(r)=0 mod q, solve f(n*q+r)=0 mod p.
  27. for each w in r do
  28. <<f1:=numr subf(f,{x . {'plus,{'times,y,q},w}});
  29. for each y in modroots2(reduce!-mod!-p!*(f1,p),p,t)
  30. do <<y:= modp(y*q+w,pq);
  31. if null reduce!-mod!-p!*(numr subf(f,{x . y}),pq)
  32. and not member(y,s) then s:=y.s>>;
  33. >>;
  34. return s;
  35. end;
  36. symbolic procedure modroots2(f,p,rec);
  37. if domainp f and f then nil
  38. else if null f then
  39. if p=2 and rec then '(-1 0 1)
  40. else for i:=0:(p-1) collect i
  41. else if p=2 then modroots4(f,t,rec)
  42. else modroots3(f,p);
  43. symbolic procedure x!*!*p!-w(x,p,w);
  44. % Make a form x^p - w mod p.
  45. general!-difference!-mod!-p(x .** p .*1 .+ nil,w);
  46. symbolic procedure modroots3(f,current!-modulus);
  47. % Roots of a polynomial f mod p, p prime.
  48. % Algorithm:
  49. % H. Cohen: Computational Algebraic Number theory, 1.6.1
  50. begin scalar a,d,p,r,x; integer n;
  51. % From now on, we compute with untagged modular coefficients
  52. % using the routines in "factor/modpoly".
  53. p := current!-modulus;
  54. f := general!-reduce!-mod!-p f;
  55. x := mvar f;
  56. % gcd(f, x^p - x)
  57. a := general!-gcd!-mod!-p(f , x!*!*p!-w(x,p,!*k2f x));
  58. d := ldeg a;
  59. n := lowestdeg(a,x,0);
  60. if n>0 then
  61. <<r:='(0); a:=general!-quotient!-mod!-p(a,x!*!*p!-w(x,n,nil))>>;
  62. return append(r,modroots31(a,x,p));
  63. end;
  64. symbolic procedure modroots31(a,x,p);
  65. begin scalar a0,a1,a2,b,d,e,s,w;
  66. s2:
  67. if domainp a then return nil;
  68. if ldeg a = 1 then
  69. return {general!-modular!-quotient(
  70. if red a then general!-modular!-minus red a else 0,
  71. lc a)};
  72. if ldeg a = 2 then
  73. <<
  74. a2:=lc a; a:=red a;
  75. if not domainp a then
  76. <<a1:= lc a; a:=red a>> else a1:=0;
  77. a0:=if null a then 0 else a;
  78. d:=general!-modular!-difference(
  79. general!-modular!-times(a1,a1),
  80. general!-modular!-times(4,general!-modular!-times(a0,a2)));
  81. s:=legendre!-symbol(d,p);
  82. if s=-1 then return nil;
  83. e:= modsqrt(d,p);
  84. a2:=general!-modular!-reciprocal general!-modular!-plus(a2,a2);
  85. a1:=general!-modular!-minus a1;
  86. return
  87. {general!-modular!-times(general!-modular!-plus(a1,e),a2),
  88. general!-modular!-times(general!-modular!-difference(a1,e),a2)};
  89. >>;
  90. s3:
  91. e:=random(p);
  92. % compute gcd[x ^((p-1)/2) - 1, A(x - e)]
  93. w:=x!*!*p!-w(x,(p-1)/2,1);
  94. a1:=general!-reduce!-mod!-p numr subf(a,{x.{'difference,x,e}});
  95. b:=general!-gcd!-mod!-p(w,a1);
  96. if domainp b or ldeg b = ldeg a then go to s3;
  97. s4:
  98. % Compute both root groups and transform roots back to x - e;
  99. return
  100. for each w in union(modroots31(general!-quotient!-mod!-p(a1,b),x,p),
  101. modroots31(b,x,p))
  102. collect general!-modular!-difference(w,e)
  103. end;
  104. symbolic procedure modroots4(f,w,rec);
  105. % roots of f mod 2: count terms.
  106. if domainp f then
  107. <<
  108. if f then w:=not w;
  109. append(
  110. if null f then '(0),
  111. if w then (if rec then '(-1 1) else '(1))
  112. )
  113. >>
  114. else modroots4(red f,not w,rec);
  115. put('m_roots,'psopfn,
  116. function(lambda(u);
  117. 'list . modroots0(numr simp car u,reval cadr u)));
  118. endmodule;
  119. end;