| | 1244 | ############################################################# |
|---|
| | 1245 | # |
|---|
| | 1246 | # Explanation of the different division (also known as torsion) |
|---|
| | 1247 | # polynomial functions in Sage |
|---|
| | 1248 | # |
|---|
| | 1249 | # |
|---|
| | 1250 | # For odd $m$, the three functions pseudo_torsion_polynomial(m), |
|---|
| | 1251 | # torsion_polynomial(m), full_division_polynomial(m) all return the |
|---|
| | 1252 | # same polynomial of degree $(m^2-1)/2$ in $x$, though in the latter |
|---|
| | 1253 | # case the returned polynomial is an element of the bivariate |
|---|
| | 1254 | # polynomial ring in $x$ and $y$. As a function on the curve, this |
|---|
| | 1255 | # polynomial has $m^2-1$ zeros, namely the non-zero points $P$ such |
|---|
| | 1256 | # that $m*P=0$. (These degrees and multiplicities need adjusting in |
|---|
| | 1257 | # finite characteristic $p$ when $p$ divides $m$.) |
|---|
| 1245 | | ## def pseudo_torsion_polynomial(self, n, x=None, cache=None): |
|---|
| 1246 | | ## r""" |
|---|
| 1247 | | ## Returns the n-th torsion polynomial (division polynomial), without |
|---|
| 1248 | | ## the 2-torsion factor if n is even, as a polynomial in $x$. |
|---|
| | 1259 | # For even $m$, the three functions are all different. (1) |
|---|
| | 1260 | # pseudo_torsion_polynomial(m) returns a polynomial in $x$ of degree |
|---|
| | 1261 | # $(m^2-4)/2$ whose zeros (as a function on the curve) are the $m^2-4$ |
|---|
| | 1262 | # points $P$ which satisfy $m*P=0$ but $2*P\not=0$. (2) |
|---|
| | 1263 | # torsion_polynomial(m) includes an extra factor of degree $3$ which |
|---|
| | 1264 | # is zero at the $2$-torsion points, so as a function on the curve it |
|---|
| | 1265 | # has a double zero at these points, while as a polynomial in $x$ it |
|---|
| | 1266 | # has $(m^2+2)/2$ distinct roots which are the distinct |
|---|
| | 1267 | # $x$-coordinates of the nonzero points $P$ satisfying $m*P=0$. (3) |
|---|
| | 1268 | # full_division_polynomial(m), which is a bivariate polynomial, has |
|---|
| | 1269 | # instead an extra factor $2*y+a1*x+a3$, so as a function on the curve |
|---|
| | 1270 | # it again has precisely $m^2-1$ zeros, namely the non-zero points $P$ |
|---|
| | 1271 | # which satisfy $m*P=0$. |
|---|
| 1250 | | ## These are the polynomials $g_n$ defined in Mazur/Tate (``The p-adic |
|---|
| 1251 | | ## sigma function''), but with the sign flipped for even $n$, so that |
|---|
| 1252 | | ## the leading coefficient is always positive. |
|---|
| | 1273 | # Comparison with Magma: Magma's function DivisionPolynomial(E,m) |
|---|
| | 1274 | # returns a triple of univariate polynomials. For odd $m$ these are |
|---|
| | 1275 | # f,f,1 where f is the same as both Sage's |
|---|
| | 1276 | # E.pseudo_torsion_polynomial(m) and E.torsion_polynomial(m). For |
|---|
| | 1277 | # even $m$ they are f,g,h where f=E.torsion_polynomial(m), |
|---|
| | 1278 | # g=E.pseudo_torsion_polynomial(m), and h=f/g. Magma has no function |
|---|
| | 1279 | # equivalent to Sage's E.full_division_polynomial(m) except for the |
|---|
| | 1280 | # function TwoTorsionPolynomial(E) which is the same as |
|---|
| | 1281 | # E.full_division_polynomial(2), i.e. 2*y+a1*x+a3. |
|---|
| 1260 | | ## Note that the $g_n$'s are always polynomials in $x$, whereas the |
|---|
| 1261 | | ## $\psi_n$'s require the appearance of a $y$. |
|---|
| | 1287 | # The pseudo_torsion_polynomial() function allows the user to supply a |
|---|
| | 1288 | # value of 'x' which need not be the generator of a polynomial ring, |
|---|
| | 1289 | # allowing for fast evaluation of the polynomials. This feature is |
|---|
| | 1290 | # used, for example, in the division_points() function in |
|---|
| | 1291 | # ell_point.py. There are implications for the caching of these |
|---|
| | 1292 | # polynomials: see the docstrings of the individual functions for more |
|---|
| | 1293 | # about this. |
|---|
| 1268 | | ## INPUT: |
|---|
| 1269 | | ## n -- positive integer, or the special values -1 and -2 which |
|---|
| 1270 | | ## mean $B_6 = (2y + a_1 x + a_3)^2$ and $B_6^2$ respectively |
|---|
| 1271 | | ## (in the notation of Mazur/Tate). |
|---|
| 1272 | | ## x -- optional ring element to use as the "x" variable. If x |
|---|
| 1273 | | ## is None, then a new polynomial ring will be constructed over |
|---|
| 1274 | | ## the base ring of the elliptic curve, and its generator will |
|---|
| 1275 | | ## be used as x. Note that x does not need to be a generator of |
|---|
| 1276 | | ## a polynomial ring; any ring element is ok. This permits fast |
|---|
| 1277 | | ## calculation of the torsion polynomial *evaluated* on any |
|---|
| 1278 | | ## element of a ring. |
|---|
| 1279 | | ## cache -- optional dictionary, with integer keys. If the key m |
|---|
| 1280 | | ## is in cache, then cache[m] is assumed to be the value of |
|---|
| 1281 | | ## pseudo_torsion_polynomial(m) for the supplied x. New entries |
|---|
| 1282 | | ## will be added to the cache as they are computed. |
|---|
| | 1297 | def pseudo_torsion_polynomial(self, n, x=None, cache=None): |
|---|
| | 1298 | r""" |
|---|
| | 1299 | Returns the n-th torsion polynomial (division polynomial), without |
|---|
| | 1300 | the 2-torsion factor if n is even, as a polynomial in $x$. |
|---|
| 1295 | | ## EXAMPLES: |
|---|
| 1296 | | ## sage: E = EllipticCurve("37a") |
|---|
| 1297 | | ## sage: E.pseudo_torsion_polynomial(1) |
|---|
| 1298 | | ## 1 |
|---|
| 1299 | | ## sage: E.pseudo_torsion_polynomial(2) |
|---|
| 1300 | | ## 1 |
|---|
| 1301 | | ## sage: E.pseudo_torsion_polynomial(3) |
|---|
| 1302 | | ## 3*x^4 - 6*x^2 + 3*x - 1 |
|---|
| 1303 | | ## sage: E.pseudo_torsion_polynomial(4) |
|---|
| 1304 | | ## 2*x^6 - 10*x^4 + 10*x^3 - 10*x^2 + 2*x + 1 |
|---|
| 1305 | | ## sage: E.pseudo_torsion_polynomial(5) |
|---|
| 1306 | | ## 5*x^12 - 62*x^10 + 95*x^9 - 105*x^8 - 60*x^7 + 285*x^6 - 174*x^5 - 5*x^4 - 5*x^3 + 35*x^2 - 15*x + 2 |
|---|
| 1307 | | ## sage: E.pseudo_torsion_polynomial(6) |
|---|
| 1308 | | ## 3*x^16 - 72*x^14 + 168*x^13 - 364*x^12 + 1120*x^10 - 1144*x^9 + 300*x^8 - 540*x^7 + 1120*x^6 - 588*x^5 - 133*x^4 + 252*x^3 - 114*x^2 + 22*x - 1 |
|---|
| 1309 | | ## sage: E.pseudo_torsion_polynomial(7) |
|---|
| 1310 | | ## 7*x^24 - 308*x^22 + 986*x^21 - 2954*x^20 + 28*x^19 + 17171*x^18 - 23142*x^17 + 511*x^16 - 5012*x^15 + 43804*x^14 - 7140*x^13 - 96950*x^12 + 111356*x^11 - 19516*x^10 - 49707*x^9 + 40054*x^8 - 124*x^7 - 18382*x^6 + 13342*x^5 - 4816*x^4 + 1099*x^3 - 210*x^2 + 35*x - 3 |
|---|
| 1311 | | ## sage: E.pseudo_torsion_polynomial(8) |
|---|
| 1312 | | ## 4*x^30 - 292*x^28 + 1252*x^27 - 5436*x^26 + 2340*x^25 + 39834*x^24 - 79560*x^23 + 51432*x^22 - 142896*x^21 + 451596*x^20 - 212040*x^19 - 1005316*x^18 + 1726416*x^17 - 671160*x^16 - 954924*x^15 + 1119552*x^14 + 313308*x^13 - 1502818*x^12 + 1189908*x^11 - 160152*x^10 - 399176*x^9 + 386142*x^8 - 220128*x^7 + 99558*x^6 - 33528*x^5 + 6042*x^4 + 310*x^3 - 406*x^2 + 78*x - 5 |
|---|
| | 1316 | SEE ALSO: |
|---|
| | 1317 | -- torsion_polynomial() |
|---|
| | 1318 | -- multiple_x_numerator() |
|---|
| | 1319 | -- multiple_x_denominator() |
|---|
| | 1320 | -- full_division_polynomial() |
|---|
| 1314 | | ## sage: E.pseudo_torsion_polynomial(18) % E.pseudo_torsion_polynomial(6) == 0 |
|---|
| 1315 | | ## True |
|---|
| | 1322 | INPUT: |
|---|
| | 1323 | n -- positive integer, or the special values -1 and -2 which |
|---|
| | 1324 | mean $B_6 = (2y + a_1 x + a_3)^2$ and $B_6^2$ respectively |
|---|
| | 1325 | (in the notation of Mazur/Tate). |
|---|
| | 1326 | x -- optional ring element to use as the "x" variable. If x |
|---|
| | 1327 | is None, then a new polynomial ring will be constructed over |
|---|
| | 1328 | the base ring of the elliptic curve, and its generator will |
|---|
| | 1329 | be used as x. Note that x does not need to be a generator of |
|---|
| | 1330 | a polynomial ring; any ring element is ok. This permits fast |
|---|
| | 1331 | calculation of the torsion polynomial *evaluated* on any |
|---|
| | 1332 | element of a ring. |
|---|
| | 1333 | cache -- optional dictionary, with integer keys. If the key m |
|---|
| | 1334 | is in cache, then cache[m] is assumed to be the value of |
|---|
| | 1335 | pseudo_torsion_polynomial(m) for the supplied x. New entries |
|---|
| | 1336 | will be added to the cache as they are computed. |
|---|
| 1317 | | ## An example to illustrate the relationship with torsion points. |
|---|
| 1318 | | ## sage: F = GF(11) |
|---|
| 1319 | | ## sage: E = EllipticCurve(F, [0, 2]); E |
|---|
| 1320 | | ## Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field of size 11 |
|---|
| 1321 | | ## sage: f = E.pseudo_torsion_polynomial(5); f |
|---|
| 1322 | | ## 5*x^12 + x^9 + 8*x^6 + 4*x^3 + 7 |
|---|
| 1323 | | ## sage: f.factor() |
|---|
| 1324 | | ## (5) * (x^2 + 5) * (x^2 + 2*x + 5) * (x^2 + 5*x + 7) * (x^2 + 7*x + 7) * (x^2 + 9*x + 5) * (x^2 + 10*x + 7) |
|---|
| | 1338 | ALGORITHM: |
|---|
| | 1339 | -- Recursion described in Mazur/Tate. The recursive formulae are |
|---|
| | 1340 | evaluated $O((log n)^2)$ times. |
|---|
| 1326 | | ## This indicates that the x-coordinates of all the 5-torsion points |
|---|
| 1327 | | ## of $E$ are in $GF(11^2)$, and therefore the y-coordinates are in |
|---|
| 1328 | | ## $GF(11^4)$. |
|---|
| | 1342 | TODO: |
|---|
| | 1343 | -- for better unity of code, it might be good to make the regular |
|---|
| | 1344 | torsion_polynomial() function use this as a subroutine. At |
|---|
| | 1345 | present they are independent. |
|---|
| | 1346 | |
|---|
| | 1347 | AUTHORS: |
|---|
| | 1348 | -- David Harvey (2006-09-24) |
|---|
| | 1349 | |
|---|
| | 1350 | EXAMPLES: |
|---|
| | 1351 | sage: E = EllipticCurve("37a") |
|---|
| | 1352 | sage: E.pseudo_torsion_polynomial(1) |
|---|
| | 1353 | 1 |
|---|
| | 1354 | sage: E.pseudo_torsion_polynomial(2) |
|---|
| | 1355 | 1 |
|---|
| | 1356 | sage: E.pseudo_torsion_polynomial(3) |
|---|
| | 1357 | 3*x^4 - 6*x^2 + 3*x - 1 |
|---|
| | 1358 | sage: E.pseudo_torsion_polynomial(4) |
|---|
| | 1359 | 2*x^6 - 10*x^4 + 10*x^3 - 10*x^2 + 2*x + 1 |
|---|
| | 1360 | sage: E.pseudo_torsion_polynomial(5) |
|---|
| | 1361 | 5*x^12 - 62*x^10 + 95*x^9 - 105*x^8 - 60*x^7 + 285*x^6 - 174*x^5 - 5*x^4 - 5*x^3 + 35*x^2 - 15*x + 2 |
|---|
| | 1362 | sage: E.pseudo_torsion_polynomial(6) |
|---|
| | 1363 | 3*x^16 - 72*x^14 + 168*x^13 - 364*x^12 + 1120*x^10 - 1144*x^9 + 300*x^8 - 540*x^7 + 1120*x^6 - 588*x^5 - 133*x^4 + 252*x^3 - 114*x^2 + 22*x - 1 |
|---|
| | 1364 | sage: E.pseudo_torsion_polynomial(7) |
|---|
| | 1365 | 7*x^24 - 308*x^22 + 986*x^21 - 2954*x^20 + 28*x^19 + 17171*x^18 - 23142*x^17 + 511*x^16 - 5012*x^15 + 43804*x^14 - 7140*x^13 - 96950*x^12 + 111356*x^11 - 19516*x^10 - 49707*x^9 + 40054*x^8 - 124*x^7 - 18382*x^6 + 13342*x^5 - 4816*x^4 + 1099*x^3 - 210*x^2 + 35*x - 3 |
|---|
| | 1366 | sage: E.pseudo_torsion_polynomial(8) |
|---|
| | 1367 | 4*x^30 - 292*x^28 + 1252*x^27 - 5436*x^26 + 2340*x^25 + 39834*x^24 - 79560*x^23 + 51432*x^22 - 142896*x^21 + 451596*x^20 - 212040*x^19 - 1005316*x^18 + 1726416*x^17 - 671160*x^16 - 954924*x^15 + 1119552*x^14 + 313308*x^13 - 1502818*x^12 + 1189908*x^11 - 160152*x^10 - 399176*x^9 + 386142*x^8 - 220128*x^7 + 99558*x^6 - 33528*x^5 + 6042*x^4 + 310*x^3 - 406*x^2 + 78*x - 5 |
|---|
| | 1368 | |
|---|
| | 1369 | sage: E.pseudo_torsion_polynomial(18) % E.pseudo_torsion_polynomial(6) == 0 |
|---|
| | 1370 | True |
|---|
| | 1371 | |
|---|
| | 1372 | An example to illustrate the relationship with torsion points. |
|---|
| | 1373 | sage: F = GF(11) |
|---|
| | 1374 | sage: E = EllipticCurve(F, [0, 2]); E |
|---|
| | 1375 | Elliptic Curve defined by y^2 = x^3 + 2 over Finite Field of size 11 |
|---|
| | 1376 | sage: f = E.pseudo_torsion_polynomial(5); f |
|---|
| | 1377 | 5*x^12 + x^9 + 8*x^6 + 4*x^3 + 7 |
|---|
| | 1378 | sage: f.factor() |
|---|
| | 1379 | (5) * (x^2 + 5) * (x^2 + 2*x + 5) * (x^2 + 5*x + 7) * (x^2 + 7*x + 7) * (x^2 + 9*x + 5) * (x^2 + 10*x + 7) |
|---|
| | 1380 | |
|---|
| | 1381 | This indicates that the x-coordinates of all the 5-torsion points |
|---|
| | 1382 | of $E$ are in $GF(11^2)$, and therefore the y-coordinates are in |
|---|
| | 1383 | $GF(11^4)$. |
|---|
| 1330 | | ## sage: K = GF(11^4, 'a') |
|---|
| 1331 | | ## sage: X = E.change_ring(K) |
|---|
| 1332 | | ## sage: f = X.pseudo_torsion_polynomial(5) |
|---|
| 1333 | | ## sage: x_coords = [root for (root, _) in f.roots()]; x_coords |
|---|
| 1334 | | ## [10*a^3 + 4*a^2 + 5*a + 6, |
|---|
| 1335 | | ## 9*a^3 + 8*a^2 + 10*a + 8, |
|---|
| 1336 | | ## 8*a^3 + a^2 + 4*a + 10, |
|---|
| 1337 | | ## 8*a^3 + a^2 + 4*a + 8, |
|---|
| 1338 | | ## 8*a^3 + a^2 + 4*a + 4, |
|---|
| 1339 | | ## 6*a^3 + 9*a^2 + 3*a + 4, |
|---|
| 1340 | | ## 5*a^3 + 2*a^2 + 8*a + 7, |
|---|
| 1341 | | ## 3*a^3 + 10*a^2 + 7*a + 8, |
|---|
| 1342 | | ## 3*a^3 + 10*a^2 + 7*a + 3, |
|---|
| 1343 | | ## 3*a^3 + 10*a^2 + 7*a + 1, |
|---|
| 1344 | | ## 2*a^3 + 3*a^2 + a + 7, |
|---|
| 1345 | | ## a^3 + 7*a^2 + 6*a] |
|---|
| | 1385 | sage: K = GF(11^4, 'a') |
|---|
| | 1386 | sage: X = E.change_ring(K) |
|---|
| | 1387 | sage: f = X.pseudo_torsion_polynomial(5) |
|---|
| | 1388 | sage: x_coords = f.roots(multiplicities=False); x_coords |
|---|
| | 1389 | [10*a^3 + 4*a^2 + 5*a + 6, |
|---|
| | 1390 | 9*a^3 + 8*a^2 + 10*a + 8, |
|---|
| | 1391 | 8*a^3 + a^2 + 4*a + 10, |
|---|
| | 1392 | 8*a^3 + a^2 + 4*a + 8, |
|---|
| | 1393 | 8*a^3 + a^2 + 4*a + 4, |
|---|
| | 1394 | 6*a^3 + 9*a^2 + 3*a + 4, |
|---|
| | 1395 | 5*a^3 + 2*a^2 + 8*a + 7, |
|---|
| | 1396 | 3*a^3 + 10*a^2 + 7*a + 8, |
|---|
| | 1397 | 3*a^3 + 10*a^2 + 7*a + 3, |
|---|
| | 1398 | 3*a^3 + 10*a^2 + 7*a + 1, |
|---|
| | 1399 | 2*a^3 + 3*a^2 + a + 7, |
|---|
| | 1400 | a^3 + 7*a^2 + 6*a] |
|---|
| 1356 | | ## """ |
|---|
| 1357 | | ## if cache is None: |
|---|
| 1358 | | ## cache = {} |
|---|
| 1359 | | ## else: |
|---|
| 1360 | | ## try: |
|---|
| 1361 | | ## return cache[n] |
|---|
| 1362 | | ## except KeyError: |
|---|
| 1363 | | ## pass |
|---|
| | 1411 | sage: E=EllipticCurve('14a1') |
|---|
| | 1412 | sage: T=E.torsion_subgroup() |
|---|
| | 1413 | sage: [n*T.0 for n in range(6)] |
|---|
| | 1414 | [(0 : 1 : 0), |
|---|
| | 1415 | (9 : 23 : 1), |
|---|
| | 1416 | (2 : 2 : 1), |
|---|
| | 1417 | (1 : -1 : 1), |
|---|
| | 1418 | (2 : -5 : 1), |
|---|
| | 1419 | (9 : -33 : 1)] |
|---|
| | 1420 | sage: pol=E.pseudo_torsion_polynomial(6) |
|---|
| | 1421 | sage: xlist=pol.roots(multiplicities=False); xlist |
|---|
| | 1422 | [9, 2, -1/3, -5] |
|---|
| | 1423 | sage: [E.lift_x(x, all=True) for x in xlist] |
|---|
| | 1424 | [[(9 : 23 : 1), (9 : -33 : 1)], [(2 : 2 : 1), (2 : -5 : 1)], [], []] |
|---|
| 1370 | | ## n = int(n) |
|---|
| 1371 | | ## if n <= 4: |
|---|
| 1372 | | ## if n == -1: |
|---|
| 1373 | | ## answer = 4*x**3 + b2*x**2 + 2*b4*x + b6 |
|---|
| 1374 | | ## elif n == -2: |
|---|
| 1375 | | ## answer = self.pseudo_torsion_polynomial(-1, x, cache) ** 2 |
|---|
| 1376 | | ## elif n == 1 or n == 2: |
|---|
| 1377 | | ## answer = x.parent()(1) |
|---|
| 1378 | | ## elif n == 3: |
|---|
| 1379 | | ## answer = 3*x**4 + b2*x**3 + 3*b4*x**2 + 3*b6*x + b8 |
|---|
| 1380 | | ## elif n == 4: |
|---|
| 1381 | | ## answer = -self.pseudo_torsion_polynomial(-2, x, cache) + \ |
|---|
| 1382 | | ## (6*x**2 + b2*x + b4) * \ |
|---|
| 1383 | | ## self.pseudo_torsion_polynomial(3, x, cache) |
|---|
| 1384 | | ## else: |
|---|
| 1385 | | ## raise ValueError, "n must be a positive integer (or -1 or -2)" |
|---|
| 1386 | | ## else: |
|---|
| 1387 | | ## if n % 2 == 0: |
|---|
| 1388 | | ## m = (n-2) // 2 |
|---|
| 1389 | | ## g_mplus3 = self.pseudo_torsion_polynomial(m+3, x, cache) |
|---|
| 1390 | | ## g_mplus2 = self.pseudo_torsion_polynomial(m+2, x, cache) |
|---|
| 1391 | | ## g_mplus1 = self.pseudo_torsion_polynomial(m+1, x, cache) |
|---|
| 1392 | | ## g_m = self.pseudo_torsion_polynomial(m, x, cache) |
|---|
| 1393 | | ## g_mless1 = self.pseudo_torsion_polynomial(m-1, x, cache) |
|---|
| 1394 | | ## answer = g_mplus1 * \ |
|---|
| 1395 | | ## (g_mplus3 * g_m**2 - g_mless1 * g_mplus2**2) |
|---|
| 1396 | | ## else: |
|---|
| 1397 | | ## m = (n-1) // 2 |
|---|
| 1398 | | ## g_mplus2 = self.pseudo_torsion_polynomial(m+2, x, cache) |
|---|
| 1399 | | ## g_mplus1 = self.pseudo_torsion_polynomial(m+1, x, cache) |
|---|
| 1400 | | ## g_m = self.pseudo_torsion_polynomial(m, x, cache) |
|---|
| 1401 | | ## g_mless1 = self.pseudo_torsion_polynomial(m-1, x, cache) |
|---|
| 1402 | | ## B6_sqr = self.pseudo_torsion_polynomial(-2, x, cache) |
|---|
| 1403 | | ## if m % 2 == 0: |
|---|
| 1404 | | ## answer = B6_sqr * g_mplus2 * g_m**3 - \ |
|---|
| 1405 | | ## g_mless1 * g_mplus1**3 |
|---|
| 1406 | | ## else: |
|---|
| 1407 | | ## answer = g_mplus2 * g_m**3 - \ |
|---|
| 1408 | | ## B6_sqr * g_mless1 * g_mplus1**3 |
|---|
| | 1431 | """ |
|---|
| | 1432 | if cache is None: |
|---|
| | 1433 | cache = {} |
|---|
| | 1434 | else: |
|---|
| | 1435 | try: |
|---|
| | 1436 | return cache[n] |
|---|
| | 1437 | except KeyError: |
|---|
| | 1438 | pass |
|---|
| 1414 | | ## def multiple_x_numerator(self, n, x=None, cache=None): |
|---|
| 1415 | | ## r""" |
|---|
| 1416 | | ## Returns the numerator of the x-coordinate of the nth multiple of |
|---|
| 1417 | | ## a point, using torsion polynomials (division polynomials). |
|---|
| | 1445 | n = int(n) |
|---|
| | 1446 | if n <= 4: |
|---|
| | 1447 | if n == -1: |
|---|
| | 1448 | answer = 4*x**3 + b2*x**2 + 2*b4*x + b6 |
|---|
| | 1449 | elif n == -2: |
|---|
| | 1450 | answer = self.pseudo_torsion_polynomial(-1, x, cache) ** 2 |
|---|
| | 1451 | elif n == 1 or n == 2: |
|---|
| | 1452 | answer = x.parent()(1) |
|---|
| | 1453 | elif n == 3: |
|---|
| | 1454 | answer = 3*x**4 + b2*x**3 + 3*b4*x**2 + 3*b6*x + b8 |
|---|
| | 1455 | elif n == 4: |
|---|
| | 1456 | answer = -self.pseudo_torsion_polynomial(-2, x, cache) + \ |
|---|
| | 1457 | (6*x**2 + b2*x + b4) * \ |
|---|
| | 1458 | self.pseudo_torsion_polynomial(3, x, cache) |
|---|
| | 1459 | else: |
|---|
| | 1460 | raise ValueError, "n must be a positive integer (or -1 or -2)" |
|---|
| | 1461 | else: |
|---|
| | 1462 | if n % 2 == 0: |
|---|
| | 1463 | m = (n-2) // 2 |
|---|
| | 1464 | g_mplus3 = self.pseudo_torsion_polynomial(m+3, x, cache) |
|---|
| | 1465 | g_mplus2 = self.pseudo_torsion_polynomial(m+2, x, cache) |
|---|
| | 1466 | g_mplus1 = self.pseudo_torsion_polynomial(m+1, x, cache) |
|---|
| | 1467 | g_m = self.pseudo_torsion_polynomial(m, x, cache) |
|---|
| | 1468 | g_mless1 = self.pseudo_torsion_polynomial(m-1, x, cache) |
|---|
| | 1469 | answer = g_mplus1 * \ |
|---|
| | 1470 | (g_mplus3 * g_m**2 - g_mless1 * g_mplus2**2) |
|---|
| | 1471 | else: |
|---|
| | 1472 | m = (n-1) // 2 |
|---|
| | 1473 | g_mplus2 = self.pseudo_torsion_polynomial(m+2, x, cache) |
|---|
| | 1474 | g_mplus1 = self.pseudo_torsion_polynomial(m+1, x, cache) |
|---|
| | 1475 | g_m = self.pseudo_torsion_polynomial(m, x, cache) |
|---|
| | 1476 | g_mless1 = self.pseudo_torsion_polynomial(m-1, x, cache) |
|---|
| | 1477 | B6_sqr = self.pseudo_torsion_polynomial(-2, x, cache) |
|---|
| | 1478 | if m % 2 == 0: |
|---|
| | 1479 | answer = B6_sqr * g_mplus2 * g_m**3 - \ |
|---|
| | 1480 | g_mless1 * g_mplus1**3 |
|---|
| | 1481 | else: |
|---|
| | 1482 | answer = g_mplus2 * g_m**3 - \ |
|---|
| | 1483 | B6_sqr * g_mless1 * g_mplus1**3 |
|---|
| 1423 | | ## WARNING: |
|---|
| 1424 | | ## -- There may of course be cancellation between the numerator and |
|---|
| 1425 | | ## the denominator (multiple_x_denominator()). Be careful. For more |
|---|
| 1426 | | ## information on how to avoid cancellation, see Christopher Wuthrich's |
|---|
| 1427 | | ## thesis. |
|---|
| | 1489 | def multiple_x_numerator(self, n, x=None, cache=None): |
|---|
| | 1490 | r""" |
|---|
| | 1491 | Returns the numerator of the x-coordinate of the nth multiple of |
|---|
| | 1492 | a point, using torsion polynomials (division polynomials). |
|---|
| 1454 | | ## An example where cancellation occurs: |
|---|
| 1455 | | ## sage: E = EllipticCurve("88a1") |
|---|
| 1456 | | ## sage: P = E([2,2]) # fixed choice of generator |
|---|
| 1457 | | ## sage: n = E.multiple_x_numerator(11, P[0]); n |
|---|
| 1458 | | ## 442446784738847563128068650529343492278651453440 |
|---|
| 1459 | | ## sage: d = E.multiple_x_denominator(11, P[0]); d |
|---|
| 1460 | | ## 1427247692705959881058285969449495136382746624 |
|---|
| 1461 | | ## sage: n/d |
|---|
| 1462 | | ## 310 |
|---|
| 1463 | | ## sage: 11*P |
|---|
| 1464 | | ## (310 : -5458 : 1) |
|---|
| | 1510 | EXAMPLES: |
|---|
| | 1511 | sage: E = EllipticCurve("37a") |
|---|
| | 1512 | sage: P = E.gens()[0] |
|---|
| | 1513 | sage: x = P[0] |
|---|
| | 1514 | |
|---|
| | 1515 | sage: (35*P)[0] |
|---|
| | 1516 | -804287518035141565236193151/1063198259901027900600665796 |
|---|
| | 1517 | sage: E.multiple_x_numerator(35, x) |
|---|
| | 1518 | -804287518035141565236193151 |
|---|
| | 1519 | sage: E.multiple_x_denominator(35, x) |
|---|
| | 1520 | 1063198259901027900600665796 |
|---|
| | 1521 | |
|---|
| | 1522 | sage: (36*P)[0] |
|---|
| | 1523 | 54202648602164057575419038802/15402543997324146892198790401 |
|---|
| | 1524 | sage: E.multiple_x_numerator(36, x) |
|---|
| | 1525 | 54202648602164057575419038802 |
|---|
| | 1526 | sage: E.multiple_x_denominator(36, x) |
|---|
| | 1527 | 15402543997324146892198790401 |
|---|
| | 1528 | |
|---|
| | 1529 | An example where cancellation occurs: |
|---|
| | 1530 | sage: E = EllipticCurve("88a1") |
|---|
| | 1531 | sage: P = E([2,2]) # fixed choice of generator |
|---|
| | 1532 | sage: n = E.multiple_x_numerator(11, P[0]); n |
|---|
| | 1533 | 442446784738847563128068650529343492278651453440 |
|---|
| | 1534 | sage: d = E.multiple_x_denominator(11, P[0]); d |
|---|
| | 1535 | 1427247692705959881058285969449495136382746624 |
|---|
| | 1536 | sage: n/d |
|---|
| | 1537 | 310 |
|---|
| | 1538 | sage: 11*P |
|---|
| | 1539 | (310 : -5458 : 1) |
|---|
| 1477 | | ## self.pseudo_torsion_polynomial( -2, x, cache) |
|---|
| 1478 | | ## self.pseudo_torsion_polynomial(n-1, x, cache) |
|---|
| 1479 | | ## self.pseudo_torsion_polynomial(n , x, cache) |
|---|
| 1480 | | ## self.pseudo_torsion_polynomial(n+1, x, cache) |
|---|
| | 1552 | self.pseudo_torsion_polynomial( -2, x, cache) |
|---|
| | 1553 | self.pseudo_torsion_polynomial(n-1, x, cache) |
|---|
| | 1554 | self.pseudo_torsion_polynomial(n , x, cache) |
|---|
| | 1555 | self.pseudo_torsion_polynomial(n+1, x, cache) |
|---|
| 1488 | | ## def multiple_x_denominator(self, n, x=None, cache=None): |
|---|
| 1489 | | ## r""" |
|---|
| 1490 | | ## Returns the denominator of the x-coordinate of the nth multiple of |
|---|
| 1491 | | ## a point, using torsion polynomials (division polynomials). |
|---|
| | 1563 | def multiple_x_denominator(self, n, x=None, cache=None): |
|---|
| | 1564 | r""" |
|---|
| | 1565 | Returns the denominator of the x-coordinate of the nth multiple of |
|---|
| | 1566 | a point, using torsion polynomials (division polynomials). |
|---|
| 1717 | | # Get the invariants of the curve and make sure that the curve is |
|---|
| 1718 | | # in short Weierstrass form. |
|---|
| 1719 | | a0,a1,a2,A,B = self.a_invariants() |
|---|
| 1720 | | if a0 or a1 or a2: |
|---|
| 1721 | | raise NotImplementedError, "Full division polynomial only implemented for elliptic curves in short Weierstrass form" |
|---|
| | 1795 | # Get the invariants of the curve |
|---|
| | 1796 | a1,a2,a3,a4,a6 = self.a_invariants() |
|---|
| 1724 | | # division polynomial. The one subtle point here is the |
|---|
| 1725 | | # term order use of the variable y first. This is done |
|---|
| 1726 | | # so the natural reduction in the quotient ring mod y^2 - x^3 - A*x - B |
|---|
| 1727 | | # replaces all y^2's by polys in x. WARNING: Be careful |
|---|
| 1728 | | # that the gens are in the order y, x! |
|---|
| 1729 | | R, (y,x) = PolynomialRing(self.base_ring(), 2, 'y,x', order='lex').objgens() |
|---|
| | 1799 | # division polynomial. |
|---|
| | 1800 | |
|---|
| | 1801 | R, (x,y) = PolynomialRing(self.base_ring(), 2, 'x,y').objgens() |
|---|
| 1731 | | # In case m is odd we can just use the usual division |
|---|
| 1732 | | # polynomial code. Note however that we are careful to coerce |
|---|
| 1733 | | # into the multivariate polynomial ring, since the usual div |
|---|
| 1734 | | # poly code returns a polynomial in one variable. If we did |
|---|
| 1735 | | # that here it would lead to all kinds of problems later. |
|---|
| 1736 | | if use_divpoly and m % 2 == 1: |
|---|
| 1737 | | return R(self.division_polynomial(m)) |
|---|
| | 1803 | # The function pseudo_torsion_polynomial() gives the correct |
|---|
| | 1804 | # result when m is odd, and all we do in this case is evaluate |
|---|
| | 1805 | # this at the variable x in our bivariate polynomial ring. |
|---|
| 1759 | | # Finally we do the general part of the recurrence which |
|---|
| 1760 | | # divides into even and odd cases. |
|---|
| 1761 | | # We define psi to just be this full_division_polynomial function |
|---|
| 1762 | | # evaluated at a given integer k. This makes the code below |
|---|
| 1763 | | # more readable. |
|---|
| 1764 | | psi = lambda k: self.full_division_polynomial(k,use_divpoly=use_divpoly) |
|---|
| 1765 | | if m % 2 == 1: |
|---|
| 1766 | | n = m//2 |
|---|
| 1767 | | ans = psi(n+2) * psi(n)**3 - psi(n-1) * psi(n+1)**3 |
|---|
| 1768 | | elif m % 2 == 0: |
|---|
| 1769 | | n = m//2 |
|---|
| 1770 | | ans = (psi(n)*(psi(n+2)*psi(n-1)**2 - psi(n-2)*psi(n+1)**2))/(2*y) |
|---|
| 1771 | | |
|---|
| 1772 | | # Create the affine quotient ring so that we can replace all y^2 |
|---|
| 1773 | | # terms by polys in x. |
|---|
| 1774 | | Q = R.quotient(y**2 - x**3 - A*x - B) |
|---|
| 1775 | | |
|---|
| 1776 | | # Do the actual reduction and lift back to R. |
|---|
| 1777 | | f = Q(ans).lift() |
|---|
| | 1811 | f = self.pseudo_torsion_polynomial(m,x) |
|---|
| | 1812 | if m % 2 == 0: |
|---|
| | 1813 | f *= (2*y+a1*x+a3) |
|---|