nagell.red 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. module nagell;
  2. % Author: James H. Davenport.
  3. fluid '(!*tra !*trmin intvar);
  4. exports lutz!-nagell;
  5. symbolic procedure lutz!-nagell(divisor);
  6. begin
  7. scalar ans,places,mults,save!*tra;
  8. for each u in divisor do <<
  9. places:=(car u).places;
  10. mults :=(cdr u).mults >>;
  11. ans:=lutz!-nagell!-2(places,mults);
  12. if ans eq 'infinite
  13. then return 'provably!-impossible;
  14. save!*tra:=!*tra;
  15. if !*trmin
  16. then !*tra:=nil;
  17. ans:=coates!-multiple(places,mults,ans);
  18. !*tra:=save!*tra;
  19. return ans
  20. end;
  21. symbolic procedure lutz!-nagell!-2(places,mults);
  22. begin
  23. scalar wst,x,y,equation,point,a;
  24. wst:=weierstrass!-form getsqrtsfromplaces places;
  25. x:=car wst;
  26. y:=cadr wst;
  27. equation:=caddr wst;
  28. equation:=!*q2f !*multsq(equation,equation);
  29. equation:=makemainvar(equation,intvar);
  30. if ldeg equation = 3
  31. then equation:=red equation
  32. else interr "Equation not of correct form";
  33. if mvar equation eq intvar
  34. then if ldeg equation = 1
  35. then <<
  36. a:=(lc equation) ./ 1;
  37. equation:=red equation >>
  38. else interr "Equation should not have a x**2 term"
  39. else a:=nil ./ 1;
  40. equation:= a . (equation ./ 1);
  41. places:=for each u in places collect
  42. wst!-convert(u,x,y);
  43. point:=elliptic!-sum(places,mults,equation);
  44. a:=lutz!-nagell!-bound(point,equation);
  45. if !*tra or !*trmin then <<
  46. princ "Point actually is of order ";
  47. printc a >>;
  48. return a
  49. end;
  50. symbolic procedure wst!-convert(place,x,y);
  51. begin
  52. x:=subzero(xsubstitutesq(x,place),intvar);
  53. y:=subzero(xsubstitutesq(y,place),intvar);
  54. return x.y
  55. end;
  56. symbolic procedure elliptic!-sum(places,mults,equation);
  57. begin
  58. scalar point;
  59. point:=elliptic!-multiply(car places,car mults,equation);
  60. places:=cdr places;
  61. mults:=cdr mults;
  62. while places do <<
  63. point:=elliptic!-add(point,
  64. elliptic!-multiply(car places,car mults,
  65. equation),
  66. equation);
  67. places:=cdr places;
  68. mults:=cdr mults >>;
  69. return point
  70. end;
  71. symbolic procedure elliptic!-multiply(point,n,equation);
  72. if n < 0
  73. then elliptic!-multiply( (car point) . (negsq cdr point),
  74. -n,
  75. equation)
  76. else if n = 0
  77. then interr "N=0 in elliptic!-multiply"
  78. else if n = 1
  79. then point
  80. else begin
  81. scalar q,r;
  82. q:=divide(n,2);
  83. r:=cdr q;
  84. q:=car q;
  85. q:=elliptic!-multiply(elliptic!-add(point,point,equation),q,
  86. equation);
  87. if r = 0
  88. then return q
  89. else return elliptic!-add(point,q,equation)
  90. end;
  91. symbolic procedure elliptic!-add(p1,p2,equation);
  92. begin
  93. scalar x1,x2,y1,y2,x3,y3,inf,a,b,lhs,rhs;
  94. a:=car equation;
  95. b:=cdr equation;
  96. inf:=!*kk2q 'infinite;
  97. x1:=car p1;
  98. y1:=cdr p1;
  99. x2:=car p2;
  100. y2:=cdr p2;
  101. if x1 = x2
  102. then if y1 = y2
  103. then <<
  104. % this is the doubling case.
  105. x3:= multsq(4 ./ 1,
  106. !*addsq(b,!*multsq(x1,!*addsq(a, !*exptsq(x1,2)))));
  107. if null numr x3 then return inf . inf;
  108. % We doubled a point and got infinity.
  109. x3:=!*multsq(!*addsq(!*addsq(!*multsq(a,a),
  110. !*exptsq(x1,4)),
  111. !*addsq(multsq(-8 ./ 1,!*multsq(x1,b)),
  112. !*multsq(!*multsq(x1,x1),
  113. multsq(-2 ./ 1,a)))),
  114. !*invsq x3);
  115. y3:=!*addsq(y1,!*multsq(!*multsq(!*addsq(x3,negsq x1),
  116. !*addsq(a,multsq(3 ./ 1,
  117. !*multsq(x1,x1)))),
  118. !*invsq multsq(2 ./ 1,
  119. y1))) >>
  120. else x3:=(y3:=inf)
  121. else if x1 = inf
  122. then <<
  123. x3:=x2;
  124. y3:=y2 >>
  125. else if x2 = inf
  126. then <<
  127. x3:=x1;
  128. y3:=y1 >>
  129. else <<
  130. x3:=!*multsq(!*addsq(!*multsq(a,!*addsq(x1,x2)),
  131. !*addsq(multsq(2 ./ 1,b),
  132. !*addsq(!*multsq(!*multsq(x1,x2),
  133. !*addsq(x1,x2)),
  134. multsq(-2 ./ 1,
  135. !*multsq(y1,y2))))),
  136. !*invsq !*exptsq(!*addsq(x1,negsq x2),2));
  137. y3:=!*multsq(!*addsq(!*multsq(!*addsq(y2,negsq y1),x3),
  138. !*addsq(!*multsq(x2,y1),
  139. !*multsq(x1,negsq y2))),
  140. !*invsq !*addsq(x1,negsq x2)) >>;
  141. if x3 = inf
  142. then return x3.y3;
  143. lhs:=!*multsq(y3,y3);
  144. rhs:=!*addsq(b,!*multsq(x3,!*addsq(a,!*multsq(x3,x3))));
  145. if numr !*addsq(lhs,negsq rhs) % We can't just compare them
  146. % since they're algebraic numbers.
  147. % JHD Jan 14th. 1987.
  148. then <<
  149. prin2t "Point defined by X and Y as follows:";
  150. printsq x3;
  151. printsq y3;
  152. prin2t "on the curve defined by A and B as follows:";
  153. printsq a;
  154. printsq b;
  155. prin2t "gives a consistency check between:";
  156. printsq lhs;
  157. printsq rhs;
  158. interr "Consistency check failed in elliptic!-add" >>;
  159. return x3.y3
  160. end;
  161. symbolic procedure infinitep u;
  162. kernp u and (mvar numr u eq 'infinite);
  163. symbolic procedure lutz!-nagell!-bound(point,equation);
  164. begin
  165. scalar x,y,a,b,lutz!-alist,n,point2,p,l,ans;
  166. % THE LUTZ!-ALIST is an association list of elements of the form
  167. % [X-value].([Y-value].[value of N for this point])
  168. % See thesis, chapter 7, algorithm LUTZ!-NAGELL, step [1].
  169. x:=car point;
  170. y:=cdr point;
  171. if !*tra or !*trmin then <<
  172. printc "Point to have torsion investigated is";
  173. printsq x;
  174. printsq y >>;
  175. a:=car equation;
  176. b:=cdr equation;
  177. if denr y neq 1 then <<
  178. l:=denr y;
  179. % we can in fact make l an item whose cube is > denr y.
  180. y:=!*multsq(y,!*exptf(l,3) ./ 1);
  181. x:=!*multsq(x,!*exptf(l,2) ./ 1);
  182. a:=!*multsq(a,!*exptf(l,4) ./ 1);
  183. b:=!*multsq(b,!*exptf(l,6) ./ 1) >>;
  184. if denr x neq 1 then <<
  185. l:=denr x;
  186. % we can in fact make l an item whose square is > denr x.
  187. y:=!*multsq(y,!*exptf(l,3) ./ 1);
  188. x:=!*multsq(x,!*exptf(l,2) ./ 1);
  189. a:=!*multsq(a,!*exptf(l,4) ./ 1);
  190. b:=!*multsq(b,!*exptf(l,6) ./ 1) >>;
  191. % we now have integral co-ordinates for x,y.
  192. lutz!-alist:=list (x . (y . 0));
  193. if (x neq car point) and (!*tra or !*trmin) then <<
  194. printc "Point made integral as ";
  195. printsq x;
  196. printsq y;
  197. printc "on the curve with coefficients";
  198. printsq a;
  199. printsq b >>;
  200. point:=x.y;
  201. equation:=a.b;
  202. n:=0;
  203. loop:
  204. n:=n+1;
  205. point2:=elliptic!-multiply(x.y,2,equation);
  206. x:=car point2;
  207. y:=cdr point2;
  208. if infinitep x
  209. then return 2**n;
  210. if denr x neq 1
  211. then go to special!-denr;
  212. if a:=assoc(x,lutz!-alist)
  213. then if y = cadr a
  214. then return (ans:=lutz!-reduce(point,equation,2**n-2**(cddr a)))
  215. else if null numr !*addsq(y,cadr a)
  216. then return (ans:=lutz!-reduce(point,equation,2**n+2**(cddr a)))
  217. else interr "Cannot have 3 points here";
  218. lutz!-alist:=(x.(y.n)).lutz!-alist;
  219. if ans
  220. then return ans;
  221. go to loop;
  222. special!-denr:
  223. p:=denr x;
  224. if not primep p
  225. then return 'infinite;
  226. n:=1;
  227. n:=1;
  228. loop2:
  229. point:=elliptic!-multiply(point,p,equation);
  230. n:=n*p;
  231. if infinitep car point
  232. then return n;
  233. if quotf(p,denr car point)
  234. then go to loop2;
  235. return 'infinite
  236. end;
  237. symbolic procedure lutz!-reduce(point,equation,power);
  238. begin
  239. scalar n;
  240. if !*tra or !*trmin then <<
  241. princ "Point is of order dividing ";
  242. printc power >>;
  243. n:=1;
  244. while evenp power do <<
  245. power:=power/2;
  246. n:=n*2;
  247. point:=elliptic!-add(point,point,equation) >>;
  248. % we know that all the powers of 2 must appear in the answer.
  249. if power = 1
  250. then return n;
  251. if primep power
  252. then return n*power;
  253. return n*lutz!-reduce2(point,equation,power,3)
  254. end;
  255. symbolic procedure lutz!-reduce2(point,equation,power,prime);
  256. if power = 1
  257. then if infinitep car point
  258. then 1
  259. else nil
  260. else if infinitep car point
  261. then power
  262. else begin
  263. scalar n,prime2,u,ans;
  264. n:=0;
  265. while cdr divide(power,prime)=0 do <<
  266. n:=n+1;
  267. power:=power/prime >>;
  268. prime2:=nextprime prime;
  269. for i:=0:n do <<
  270. u:=lutz!-reduce2(point,equation,power,prime2);
  271. if u
  272. then <<
  273. ans:=u*prime**i;
  274. i:=n >>
  275. else <<
  276. power:=power*prime;
  277. point:=elliptic!-multiply(point,prime,equation) >> >>;
  278. if ans
  279. then return ans
  280. else return nil
  281. end;
  282. endmodule;
  283. end;