Ticket #3883: sage-trac3883.patch

File sage-trac3883.patch, 57.9 kB (added by cremona, 5 months ago)
  • a/sage/schemes/elliptic_curves/ell_generic.py

    old new  
    644644            if K.characteristic() == 2: 
    645645                R = PolynomialRing(K, 'y') 
    646646                F = R([-f,b,1]) 
    647                 ys = F.roots(
     647                ys = F.roots(multiplicities=False
    648648                if all: 
    649                     return [self.point([x, y[0], one], check=False) for y in ys] 
     649                    return [self.point([x, y, one], check=False) for y in ys] 
    650650                elif len(ys) > 0: 
    651                     return self.point([x, ys[0][0], one], check=False) 
     651                    return self.point([x, ys[0], one], check=False) 
    652652            elif D.is_square(): 
    653653                if all: 
    654654                    return [self.point([x, (-b+d)/2, one], check=False) for d in D.sqrt(all=True)] 
     
    12411241            self.__j_invariant = c4**3 / self.discriminant() 
    12421242            return self.__j_invariant 
    12431243 
     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$.) 
    12441258 
    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$. 
    12491272 
    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. 
    12531282 
    1254 ##         The full torsion polynomials may be recovered as follows: 
    1255 ##         \begin{itemize} 
    1256 ##         \item $\psi_n = g_n$ for odd $n$. 
    1257 ##         \item $\psi_n = (2y + a_1 x + a_3) g_n$ for even $n$. 
    1258 ##         \end{itemize} 
     1283# All these polynomials belong to the polynomial rings K[x] or K[x,y], 
     1284# where K is the base field, and not to either the affine coordinate 
     1285# ring of the curve or the function field. 
    12591286 
    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. 
    12621294 
    1263 ##         SEE ALSO: 
    1264 ##             -- torsion_polynomial() 
    1265 ##             -- multiple_x_numerator() 
    1266 ##             -- multiple_x_denominator() 
     1295############################################################# 
    12671296 
    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$. 
    12831301 
    1284 ##         ALGORITHM: 
    1285 ##             -- Recursion described in Mazur/Tate. The recursive formulae are 
    1286 ##             evaluated $O((log n)^2)$ times
     1302         These are the polynomials $g_n$ defined in Mazur/Tate (``The p-adic 
     1303         sigma function''), but with the sign flipped for even $n$, so that 
     1304         the leading coefficient is always positive
    12871305 
    1288 ##         TODO: 
    1289 ##             -- for better unity of code, it might be good to make the regular 
    1290 ##             torsion_polynomial() function use this as a subroutine. 
     1306         The full torsion polynomials may be recovered as follows 
     1307         (see the function full_division_polynomial()): 
     1308         \begin{itemize} 
     1309         \item $\psi_n = g_n$ for odd $n$. 
     1310         \item $\psi_n = (2y + a_1 x + a_3) g_n$ for even $n$. 
     1311         \end{itemize} 
    12911312 
    1292 ##         AUTHORS: 
    1293 ##             -- David Harvey (2006-09-24) 
     1313         Note that the $g_n$'s are always polynomials in $x$, whereas the 
     1314         $\psi_n$'s require the appearance of a $y$. 
    12941315 
    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() 
    13131321 
    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. 
    13161337 
    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. 
    13251341 
    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)$. 
    13291384           
    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] 
    13461401 
    1347 ##           Now we check that these are exactly the x coordinates of the 
    1348 ##           5-torsion points of E. 
    1349 ##            sage: for x in x_coords: 
    1350 ##            ...       y = (x**3 + 2).square_root() 
    1351 ##            ...       P = X([x, y]) 
    1352 ##            ...       assert P.order(disable_warning=True) == 5 
     1402           Now we check that these are exactly the x coordinates of the 
     1403           5-torsion points of E. 
     1404            sage: for x in x_coords: 
     1405            ...       assert X.lift_x(x).order() == 5 
    13531406 
    1354 ##           todo: need to show an example where the 2-torsion is missing 
     1407             
     1408          The roots of the polynomial are the x-coordinates of the 
     1409          points P such that m*P==0 but 2*P!=0: 
    13551410 
    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)], [], []] 
    13641425 
    1365 ##         if x is None: 
    1366 ##             x = rings.PolynomialRing(self.base_ring(), 'x').gen() 
     1426          NOTE: (1) the point of order 2 (and the identity) do not 
     1427          appear; (2) the points with x=-1/3 and x=-5 are not 
     1428          rational. 
    13671429 
    1368 ##         b2, b4, b6, b8 = self.b_invariants() 
    13691430 
    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 
    14091439 
    1410 ##         cache[n] = answer 
    1411 ##         return answer 
     1440         if x is None: 
     1441             x = rings.PolynomialRing(self.base_ring(), 'x').gen() 
    14121442 
     1443         b2, b4, b6, b8 = self.b_invariants() 
    14131444 
    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 
    14181484 
    1419 ##         The inputs n, x, cache are as described in pseudo_torsion_polynomial(). 
     1485         cache[n] = answer 
     1486         return answer 
    14201487 
    1421 ##         The result is adjusted to be correct for both even and odd n. 
    14221488 
    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). 
    14281493 
    1429 ##         SEE ALSO: 
    1430 ##           -- multiple_x_denominator() 
     1494         The inputs n, x, cache are as described in pseudo_torsion_polynomial(). 
    14311495 
    1432 ##         AUTHORS: 
    1433 ##            -- David Harvey (2006-09-24) 
     1496         The result is adjusted to be correct for both even and odd n. 
    14341497 
    1435 ##         EXAMPLES: 
    1436 ##           sage: E = EllipticCurve("37a") 
    1437 ##           sage: P = E.gens()[0] 
    1438 ##           sage: x = P[0] 
     1498         WARNING: 
     1499           -- There may of course be cancellation between the numerator and 
     1500           the denominator (multiple_x_denominator()). Be careful. For more 
     1501           information on how to avoid cancellation, see Christopher Wuthrich's 
     1502           thesis. 
    14391503 
    1440 ##           sage: (35*P)[0] 
    1441 ##           -804287518035141565236193151/1063198259901027900600665796 
    1442 ##           sage: E.multiple_x_numerator(35, x) 
    1443 ##           -804287518035141565236193151 
    1444 ##           sage: E.multiple_x_denominator(35, x) 
    1445 ##           1063198259901027900600665796 
     1504         SEE ALSO: 
     1505           -- multiple_x_denominator() 
    14461506 
    1447 ##           sage: (36*P)[0] 
    1448 ##           54202648602164057575419038802/15402543997324146892198790401 
    1449 ##           sage: E.multiple_x_numerator(36, x) 
    1450 ##           54202648602164057575419038802 
    1451 ##           sage: E.multiple_x_denominator(36, x) 
    1452 ##           15402543997324146892198790401 
     1507         AUTHORS: 
     1508            -- David Harvey (2006-09-24) 
    14531509 
    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) 
    14651540           
    1466 ##         """ 
    1467 ##         if cache is None: 
    1468 ##             cache = {} 
     1541         """ 
     1542         if cache is None: 
     1543             cache = {} 
    14691544 
    1470 ##         if x is None: 
    1471 ##             x = rings.PolynomialRing(self.base_ring(), 'x').gen() 
     1545         if x is None: 
     1546             x = rings.PolynomialRing(self.base_ring(), 'x').gen() 
    14721547 
    1473 ##         n = int(n) 
    1474 ##         if n < 2: 
    1475 ##             print "n must be at least 2" 
     1548         n = int(n) 
     1549         if n < 2: 
     1550             print "n must be at least 2" 
    14761551 
    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) 
    14811556 
    1482 ##         if n % 2 == 0: 
    1483 ##             return x * cache[-1] * cache[n]**2 - cache[n-1] * cache[n+1] 
    1484 ##         else: 
    1485 ##             return x * cache[n]**2 - cache[-1] * cache[n-1] * cache[n+1] 
     1557         if n % 2 == 0: 
     1558             return x * cache[-1] * cache[n]**2 - cache[n-1] * cache[n+1] 
     1559         else: 
     1560             return x * cache[n]**2 - cache[-1] * cache[n-1] * cache[n+1] 
    14861561 
    14871562 
    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). 
    14921567 
    1493 ##         The inputs n, x, cache are as described in pseudo_torsion_polynomial(). 
     1568         The inputs n, x, cache are as described in pseudo_torsion_polynomial(). 
    14941569 
    1495 ##         The result is adjusted to be correct for both even and odd n. 
     1570         The result is adjusted to be correct for both even and odd n. 
    14961571 
    1497 ##         SEE ALSO: 
    1498 ##           -- multiple_x_numerator() 
     1572         SEE ALSO: 
     1573           -- multiple_x_numerator() 
    14991574 
    1500 ##         TODO: the numerator and denominator versions share a calculation, 
    1501 ##         namely squaring $\psi_n$. Maybe would be good to offer a combined 
    1502 ##         version to make this more efficient. 
     1575         TODO: the numerator and denominator versions share a calculation, 
     1576         namely squaring $\psi_n$. Maybe would be good to offer a combined 
     1577         version to make this more efficient. 
    15031578 
    1504 ##         EXAMPLES: 
    1505 ##            -- see multiple_x_numerator() 
     1579         EXAMPLES: 
     1580            -- see multiple_x_numerator() 
    15061581 
    1507 ##         AUTHORS: 
    1508 ##            -- David Harvey (2006-09-24) 
     1582         AUTHORS: 
     1583            -- David Harvey (2006-09-24) 
    15091584 
    1510 ##         """ 
    1511 ##         if cache is None: 
    1512 ##             cache = {} 
     1585         """ 
     1586         if cache is None: 
     1587             cache = {} 
    15131588 
    1514 ##         if x is None: 
    1515 ##             x = rings.PolynomialRing(self.base_ring(), 'x').gen() 
     1589         if x is None: 
     1590             x = rings.PolynomialRing(self.base_ring(), 'x').gen() 
    15161591 
    1517 ##         n = int(n) 
    1518 ##         if n < 2: 
    1519 ##             print "n must be at least 2" 
     1592         n = int(n) 
     1593         if n < 2: 
     1594             print "n must be at least 2" 
    15201595 
    1521 ##         self.pseudo_torsion_polynomial(-2, x, cache) 
    1522 ##         self.pseudo_torsion_polynomial(n , x, cache) 
     1596         self.pseudo_torsion_polynomial(-2, x, cache) 
     1597         self.pseudo_torsion_polynomial(n , x, cache) 
    15231598 
    1524 ##         if n % 2 == 0: 
    1525 ##             return cache[-1] * cache[n]**2 
    1526 ##         else: 
    1527 ##             return cache[n]**2 
     1599         if n % 2 == 0: 
     1600             return cache[-1] * cache[n]**2 
     1601         else: 
     1602             return cache[n]**2 
    15281603 
    15291604 
    15301605    def torsion_polynomial(self, n, var='x', i=0): 
    1531         """ 
     1606        r""" 
    15321607        Returns the n-th torsion polynomial (a.k.a., division polynomial). 
    15331608 
    15341609        INPUT: 
     
    15401615            Polynomial -- n-th torsion polynomial, which is a polynomial over 
    15411616                          the base field of the elliptic curve. 
    15421617 
    1543         SEE ALSO: full_division_polynomial 
     1618        SEE ALSO: pseudo_torsion_polynomial, full_division_polynomial 
    15441619 
    15451620        ALIASES: division_polynomial, torsion_polynomial 
    15461621 
     
    15731648            sage: E.torsion_polynomial(6) 
    15741649            12*x^19 - 1200*x^17 - 18688*x^15 + 422912*x^13 - 2283520*x^11 + 9134080*x^9 - 27066368*x^7 + 19136512*x^5 + 19660800*x^3 - 3145728*x 
    15751650 
     1651            Check for consistency with pseudo_torsion_polynomial: 
     1652            sage: assert all([E.torsion_polynomial(2*m-1)==E.pseudo_torsion_polynomial(2*m-1) for m in range(1,20)]) 
     1653            sage: assert all([E.torsion_polynomial(2*m)==E.pseudo_torsion_polynomial(2*m)*E.pseudo_torsion_polynomial(-1) for m in range(1,20)]) 
     1654       
    15761655        AUTHOR: David Kohel (kohel@maths.usyd.edu.au), 2005-04-25 
    15771656        """ 
    15781657        n = int(n) 
     
    15891668            raise ValueError, "i must be 0 or 1." 
    15901669         
    15911670        R = rings.PolynomialRing(E.base_ring(), var) 
     1671 
     1672# This is just an abbreviation to make the following code clearer: 
     1673        tp = lambda m: E.torsion_polynomial(m) 
     1674 
    15921675        if i == 1: 
    15931676            if n == 0: 
    1594                 f = E.torsion_polynomial(1) 
     1677                f = tp(1) 
    15951678                E.__torsion_polynomial[n] = f  
    15961679                return f 
    15971680            else:  
    15981681                x = R.gen() 
    1599                 psi2 = E.torsion_polynomial(2) 
     1682                psi2 = tp(2) 
    16001683                if n%2 == 0:  
    1601                     f = x * psi2 * (E.torsion_polynomial(n)//psi2)**2 - \ 
    1602                         E.torsion_polynomial(n+1) * E.torsion_polynomial(n-1) 
     1684                    f = x * psi2 * (tp(n)//psi2)**2 - tp(n+1) * tp(n-1) 
    16031685                    E.__torsion_polynomial[n] = f 
    16041686                    return f 
    16051687                else: 
    1606                     f = x * E.torsion_polynomial(n)**2 - \ 
    1607                         (E.torsion_polynomial(n+1)//psi2) * E.torsion_polynomial(n-1) 
     1688                    f = x * tp(n)**2 - (tp(n+1)//psi2) * tp(n-1) 
    16081689                    E.__torsion_polynomial[n] = f 
    16091690                    return f 
    16101691                 
     
    16281709            if n%2 == 0: 
    16291710                m = n//2  
    16301711                if m%2 == 0: 
    1631                     f = E.torsion_polynomial(m) * (
    1632                         (E.torsion_polynomial(m+2)//psi2) * E.torsion_polynomial(m-1)**2 - \ 
    1633                         (E.torsion_polynomial(m-2)//psi2) * E.torsion_polynomial(m+1)**2) 
     1712                    f = tp(m) *
     1713                        ((tp(m+2)//psi2) * tp(m-1)**2 - \ 
     1714                        (tp(m-2)//psi2) * tp(m+1)**2) 
    16341715                    E.__torsion_polynomial[n] = f; return f 
    16351716                else: 
    1636                     f = psi2 * E.torsion_polynomial(m)*( \ 
    1637                         E.torsion_polynomial(m+2) * (E.torsion_polynomial(m-1)//psi2)**2 - \ 
    1638                         E.torsion_polynomial(m-2) * (E.torsion_polynomial(m+1)//psi2)**2) 
     1717                    f = psi2 * tp(m)*( \ 
     1718                        tp(m+2) * (tp(m-1)//psi2)**2 - \ 
     1719                        tp(m-2) * (tp(m+1)//psi2)**2) 
    16391720                    E.__torsion_polynomial[n] = f; return f                     
    16401721            else:   
    16411722                m = n//2  
    16421723                if m%2 == 0: 
    16431724                    f = psi2 * \ 
    1644                         E.torsion_polynomial(m+2) * (E.torsion_polynomial(m)//psi2)**3 - \ 
    1645                         E.torsion_polynomial(m-1) * E.torsion_polynomial(m+1)**3 
     1725                        tp(m+2) * (tp(m)//psi2)**3 - \ 
     1726                        tp(m-1) * tp(m+1)**3 
    16461727                    E.__torsion_polynomial[n] = f; return f                     
    16471728                else: 
    1648                     f = E.torsion_polynomial(m+2) * E.torsion_polynomial(m)**3 - psi2 * \ 
    1649                         E.torsion_polynomial(m-1)*(E.torsion_polynomial(m+1)//psi2)**3 
     1729                    f = tp(m+2) * tp(m)**3 - psi2 * \ 
     1730                        tp(m-1)*(tp(m+1)//psi2)**3 
    16501731                    E.__torsion_polynomial[n] = f; return f 
    16511732 
    16521733    division_polynomial = torsion_polynomial 
    16531734 
    1654     def full_division_polynomial(self, m, use_divpoly=True): 
     1735    def full_division_polynomial(self, m): 
    16551736        """ 
    16561737        Return the $m$-th bivariate division polynomial in $x$ and 
    16571738        $y$.  When $m$ is odd this is exactly the same as the usual 
    16581739        $m$th division polynomial. 
    16591740 
    16601741        For the usual division polynomial only in $x$, see the 
    1661         division_polynomial function.  
     1742        functions division_polynomial() and 
     1743        pseudo_torsion_polynomial(). 
    16621744 
    16631745        INPUT: 
    1664             self -- elliptic curve in short Weierstrass form 
     1746            self -- elliptic curve 
    16651747            m    -- a positive integer 
    1666             use_divpoly -- whether to call the division_polynomial 
    1667                            function directly in case $m$ is odd. 
    16681748        OUTPUT: 
    16691749            a polynomial in two variables $x$, $y$. 
    16701750 
    16711751        NOTE: The result is cached.             
    1672  
    1673         REFERENCE: Exercise III.3.7 of Silverman AEC 1, 1986, page 105.  
    16741752 
    16751753        EXAMPLES: 
    16761754        We create a curve and compute the first two full division 
     
    16901768            sage: E.division_polynomial(3) 
    16911769            3*x^4 + 12*x^2 + 36*x - 4 
    16921770            sage: E.full_division_polynomial(4) 
    1693             4*y*x^6 + 40*y*x^4 + 240*y*x^3 - 80*y*x^2 - 96*y*x - 320*y 
     1771            4*x^6*y + 40*x^4*y + 240*x^3*y - 80*x^2*y - 96*x*y - 320*y 
    16941772            sage: E.full_division_polynomial(5) 
    16951773            5*x^12 + 124*x^10 + 1140*x^9 - 420*x^8 + 1440*x^7 - 4560*x^6 - 8352*x^5 - 36560*x^4 - 45120*x^3 - 10240*x^2 - 39360*x - 22976 
    16961774 
    16971775        TESTS: 
    16981776        We test that the full division polynomial as computed using 
    1699         the recurrence agrees with the norml division polynomial for 
     1777        the recurrence agrees with the normal division polynomial for 
    17001778        a certain curve and all odd $n$ up to $23$: 
    17011779         
    17021780            sage: E = EllipticCurve([23,-105]) 
    17031781            sage: for n in [1,3,..,23]: 
    1704             ...       assert E.full_division_polynomial(n, use_divpoly=False) == E.division_polynomial(n)         
     1782            ...       assert E.full_division_polynomial(n) == E.division_polynomial(n)         
    17051783        """ 
    17061784        # Coerce the input m to be an integer 
    17071785        m = rings.Integer(m) 
     
    17141792        except KeyError: 
    17151793            pass 
    17161794 
    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() 
    17221797 
    17231798        # Define the polynomial ring that will contain the full 
    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() 
    17301802 
    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. 
    17381806 
    1739         # Do each case of the recurrence, exactly as in 
    1740         # Silverman's exercise in III.3.7 on page 105. 
    1741         if m <= 1: 
    1742             f = R(1) 
    1743             self.__divpoly2[m] = f 
    1744             return f 
    1745         elif m == 2: 
    1746             f = 2*y 
    1747             self.__divpoly2[m] = f 
    1748             return f 
    1749         elif m == 3: 
    1750             f = 3*x**4 + 6*A*x**2 + 12*B*x - A**2 
    1751             self.__divpoly2[m] = f 
    1752             return f 
    1753         elif m == 4: 
    1754             f = 4*y*(x**6 + 5*A*x**4 + 20*B*x**3 - 5*A**2*x**2 -  
    1755                         4*A*B*x - 8*B**2 - A**3) 
    1756             self.__divpoly2[m] = f 
    1757             return f 
     1807        # For even m, we must multiply the result of 
     1808        # pseudo_torsion_polynomial() by the full 2-torsion polynomial 
     1809        # which is 2*y+a1*x+a3 
    17581810 
    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) 
    17781814 
    17791815        # Cache the result and return it.  
    17801816        self.__divpoly2[m] = f 
     
    17821818 
    17831819    def multiplication_by_m(self, m, x_only=False): 
    17841820        """ 
    1785         Return the multiplication-by-m map from self to self as a rational 
    1786         function.    
     1821        Return the multiplication-by-m map from self to self as a pair 
     1822        of rational functions in two variables x,y. 
    17871823 
    17881824        INPUT: 
    17891825            self -- an elliptic curve in short Weierstrass form 
    1790             m -- a positive integer 
     1826            m -- a nonzero integer 
    17911827            x_only -- bool (default: False) if True, return only the x 
    17921828                      coordinate of the map. 
    17931829 
    17941830        OUTPUT: 
    17951831            2-tuple -- (f(x), g(x,y)) where f and g are rational functions 
    1796                        with the degree of y in g(x,y) at most 1. 
     1832                       with the degree of y in g(x,y) exactly 1. 
    17971833 
    1798         NOTE: The result is not cached. 
     1834        NOTES: 1. The result is not cached. 
     1835               2. m is allowed to be negative (but not 0). 
    17991836         
    18001837        EXAMPLES: 
    18011838        We create an elliptic curve. 
     
    18081845        Multiplication by 2 is more complicated.  
    18091846            sage: f = E.multiplication_by_m(2) 
    18101847            sage: f 
    1811             ((x^4 + 2*x^2 - 24*x + 1)/(4*x^3 - 4*x + 12), (2*x^6 - 10*x^4 + 120*x^3 - 10*x^2 + 24*x - 142)/(16*y*x^3 - 16*y*x + 48*y)) 
     1848            ((x^4 + 2*x^2 - 24*x + 1)/(4*x^3 - 4*x + 12), (8*x^6*y - 40*x^4*y + 480*x^3*y - 40*x^2*y + 96*x*y - 568*y)/(64*x^6 - 128*x^4 + 384*x^3 + 64*x^2 - 384*x + 576)) 
    18121849 
    18131850        Grab only the x-coordinate (less work): 
    18141851            sage: E.multiplication_by_m(2, x_only=True) 
    &helli