| | 1462 | def two_division_polynomial(self, x = None): |
|---|
| | 1463 | r""" |
|---|
| | 1464 | Returns the 2-division polynomial of this elliptic curve evaluated at x. |
|---|
| | 1465 | |
|---|
| | 1466 | INPUT: |
|---|
| | 1467 | x -- optional ring element to use as the "x" variable. If x |
|---|
| | 1468 | is None, then a new polynomial ring will be constructed over |
|---|
| | 1469 | the base ring of the elliptic curve, and its generator will |
|---|
| | 1470 | be used as x. Note that x does not need to be a generator of |
|---|
| | 1471 | a polynomial ring; any ring element is ok. This permits fast |
|---|
| | 1472 | calculation of the torsion polynomial *evaluated* on any |
|---|
| | 1473 | element of a ring. |
|---|
| | 1474 | |
|---|
| | 1475 | EXAMPLES: |
|---|
| | 1476 | sage: E=EllipticCurve('5077a1') |
|---|
| | 1477 | sage: E.two_division_polynomial() |
|---|
| | 1478 | 4*x^3 - 28*x + 25 |
|---|
| | 1479 | sage: E=EllipticCurve(GF(3^2,'a'),[1,1,1,1,1]) |
|---|
| | 1480 | sage: E.two_division_polynomial() |
|---|
| | 1481 | x^3 + 2*x^2 + 2 |
|---|
| | 1482 | sage: E.two_division_polynomial().roots() |
|---|
| | 1483 | [(2, 1), (2*a, 1), (a + 2, 1)] |
|---|
| | 1484 | """ |
|---|
| | 1485 | return self.division_polynomial_0(-1,x) |
|---|
| | 1486 | |
|---|
| | 1487 | def division_polynomial(self, m, x=None, two_torsion_multiplicity=2): |
|---|
| | 1488 | r""" |
|---|
| | 1489 | Returns the $m$-th division polynomial of this elliptic curve. |
|---|
| | 1490 | |
|---|
| | 1491 | INPUT: |
|---|
| | 1492 | m -- positive integer. |
|---|
| | 1493 | x -- optional ring element to use as the "x" variable. If x |
|---|
| | 1494 | is None, then a new polynomial ring will be constructed over |
|---|
| | 1495 | the base ring of the elliptic curve, and its generator will |
|---|
| | 1496 | be used as x. Note that x does not need to be a generator of |
|---|
| | 1497 | a polynomial ring; any ring element is ok. This permits fast |
|---|
| | 1498 | calculation of the torsion polynomial *evaluated* on any |
|---|
| | 1499 | element of a ring. |
|---|
| | 1500 | two_torsion_multiplicity -- 0,1 or 2 |
|---|
| | 1501 | |
|---|
| | 1502 | If 0: for even $m$ when x is None, a univariate |
|---|
| | 1503 | polynomial over the base ring of the curve is |
|---|
| | 1504 | returned, which omits factors whose roots are the |
|---|
| | 1505 | $x$-coordinates of the $2$-torsion points. |
|---|
| | 1506 | Similarly when $x$ is not none, the evaluation of |
|---|
| | 1507 | such a polynomial at $x$ is returned. |
|---|
| | 1508 | |
|---|
| | 1509 | If 2: for even $m$ when x is None, a univariate |
|---|
| | 1510 | polynomial over the base ring of the curve is |
|---|
| | 1511 | returned, which includes a factor of degree 3 whose |
|---|
| | 1512 | roots are the $x$-coordinates of the $2$-torsion |
|---|
| | 1513 | points. Similarly when $x$ is not none, the |
|---|
| | 1514 | evaluation of such a polynomial at $x$ is returned. |
|---|
| | 1515 | |
|---|
| | 1516 | If 1: when x is None, a bivariate polynomial over |
|---|
| | 1517 | the base ring of the curve is returned, which |
|---|
| | 1518 | includes a factor 2*y+a1*x+a3 which has simple zeros |
|---|
| | 1519 | at the $2$-torsion points. When $x$ is not none, it |
|---|
| | 1520 | should be a tuple of length 2, and the evaluation of |
|---|
| | 1521 | such a polynomial at $x$ is returned. |
|---|
| | 1522 | |
|---|
| | 1523 | EXAMPLES: |
|---|
| | 1524 | sage: E = EllipticCurve([0,0,1,-1,0]) |
|---|
| | 1525 | sage: E.division_polynomial(1) |
|---|
| | 1526 | 1 |
|---|
| | 1527 | sage: E.division_polynomial(2, two_torsion_multiplicity=0) |
|---|
| | 1528 | 1 |
|---|
| | 1529 | sage: E.division_polynomial(2, two_torsion_multiplicity=1) |
|---|
| | 1530 | 2*y + 1 |
|---|
| | 1531 | sage: E.division_polynomial(2, two_torsion_multiplicity=2) |
|---|
| | 1532 | 4*x^3 - 4*x + 1 |
|---|
| | 1533 | sage: E.division_polynomial(2) |
|---|
| | 1534 | 4*x^3 - 4*x + 1 |
|---|
| | 1535 | sage: [E.division_polynomial(3, two_torsion_multiplicity=i) for i in range(3)] |
|---|
| | 1536 | [3*x^4 - 6*x^2 + 3*x - 1, 3*x^4 - 6*x^2 + 3*x - 1, 3*x^4 - 6*x^2 + 3*x - 1] |
|---|
| | 1537 | sage: [type(E.division_polynomial(3, two_torsion_multiplicity=i)) for i in range(3)] |
|---|
| | 1538 | [<class 'sage.rings.polynomial.polynomial_element_generic.Polynomial_rational_dense'>, |
|---|
| | 1539 | <type 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'>, |
|---|
| | 1540 | <class 'sage.rings.polynomial.polynomial_element_generic.Polynomial_rational_dense'>] |
|---|
| | 1541 | |
|---|
| | 1542 | sage: E = EllipticCurve([0, -1, 1, -10, -20]) |
|---|
| | 1543 | sage: R.<z>=PolynomialRing(QQ) |
|---|
| | 1544 | sage: E.division_polynomial(4,z,0) |
|---|
| | 1545 | 2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821 |
|---|
| | 1546 | sage: E.division_polynomial(4,z) |
|---|
| | 1547 | 8*z^9 - 24*z^8 - 464*z^7 - 2758*z^6 + 6636*z^5 + 34356*z^4 + 53510*z^3 + 99714*z^2 + 351024*z + 459859 |
|---|
| | 1548 | |
|---|
| | 1549 | This does not work, since when two_torsion_multiplicity is 1, |
|---|
| | 1550 | we compute a bivariate polynomial, and must evaluate at 2 |
|---|
| | 1551 | tuple of length 2: |
|---|
| | 1552 | sage: E.division_polynomial(4,z,1) |
|---|
| | 1553 | Traceback (most recent call last): |
|---|
| | 1554 | ... |
|---|
| | 1555 | ValueError: x should be a tuple of length 2 (or None) when two_torsion_multiplicity is 1 |
|---|
| | 1556 | sage: R.<z,w>=PolynomialRing(QQ,2) |
|---|
| | 1557 | sage: E.division_polynomial(4,(z,w),1).factor() |
|---|
| | 1558 | (2*w + 1) * (2*z^6 - 4*z^5 - 100*z^4 - 790*z^3 - 210*z^2 - 1496*z - 5821) |
|---|
| | 1559 | |
|---|
| | 1560 | We can also evaluate this bivariate polynomial at a point: |
|---|
| | 1561 | sage: P = E(5,5) |
|---|
| | 1562 | sage: E.division_polynomial(4,P,two_torsion_multiplicity=1) |
|---|
| | 1563 | -1771561 |
|---|
| | 1564 | """ |
|---|
| | 1565 | |
|---|
| | 1566 | if not two_torsion_multiplicity in [0,1,2]: |
|---|
| | 1567 | raise ValueError, "two_torsion_multiplicity must be 0,1 or 2" |
|---|
| | 1568 | |
|---|
| | 1569 | # Coerce the input m to be an integer |
|---|
| | 1570 | m = rings.Integer(m) |
|---|
| | 1571 | |
|---|
| | 1572 | if two_torsion_multiplicity == 0: |
|---|
| | 1573 | try: |
|---|
| | 1574 | return self.__divpoly0[(m,x)] |
|---|
| | 1575 | except AttributeError: |
|---|
| | 1576 | self.__divpoly0 = {} |
|---|
| | 1577 | except KeyError: |
|---|
| | 1578 | pass |
|---|
| | 1579 | f = self.division_polynomial_0(m,x) |
|---|
| | 1580 | self.__divpoly0[(m,x)] = f |
|---|
| | 1581 | return f |
|---|
| | 1582 | |
|---|
| | 1583 | if two_torsion_multiplicity == 1: |
|---|
| | 1584 | try: |
|---|
| | 1585 | return self.__divpoly1[(m,x)] |
|---|
| | 1586 | except AttributeError: |
|---|
| | 1587 | self.__divpoly1 = {} |
|---|
| | 1588 | except KeyError: |
|---|
| | 1589 | pass |
|---|
| | 1590 | xy = x |
|---|
| | 1591 | R, (x,y) = PolynomialRing(self.base_ring(), 2, 'x,y').objgens() |
|---|
| | 1592 | a1,a2,a3,a4,a6 = self.a_invariants() |
|---|
| | 1593 | f = self.division_polynomial_0(m,x) |
|---|
| | 1594 | if m % 2 == 0: |
|---|
| | 1595 | f *= (2*y+a1*x+a3) |
|---|
| | 1596 | if xy is None: |
|---|
| | 1597 | self.__divpoly1[(m,(x,y))] = f |
|---|
| | 1598 | return f |
|---|
| | 1599 | else: |
|---|
| | 1600 | if isinstance(xy,tuple) and len(xy)==2 or isinstance(xy, ell_point.EllipticCurvePoint_field): |
|---|
| | 1601 | fxy = f(xy[0],xy[1]) |
|---|
| | 1602 | self.__divpoly1[(m,xy)] = fxy |
|---|
| | 1603 | return fxy |
|---|
| | 1604 | else: |
|---|
| | 1605 | raise ValueError, "x should be a tuple of length 2 (or None) when two_torsion_multiplicity is 1" |
|---|
| | 1606 | |
|---|
| | 1607 | if two_torsion_multiplicity == 2: |
|---|
| | 1608 | try: |
|---|
| | 1609 | return self.__divpoly2[(m,x)] |
|---|
| | 1610 | except AttributeError: |
|---|
| | 1611 | self.__divpoly2 = {} |
|---|
| | 1612 | except KeyError: |
|---|
| | 1613 | pass |
|---|
| | 1614 | f = self.division_polynomial_0(m,x) |
|---|
| | 1615 | if m%2 == 0: |
|---|
| | 1616 | f *= self.division_polynomial_0(-1,x) |
|---|
| | 1617 | self.__divpoly2[(m,x)] = f |
|---|
| | 1618 | return f |
|---|
| | 1619 | |
|---|
| | 1620 | torsion_polynomial = division_polynomial |
|---|
| | 1621 | |
|---|
| | 1622 | # def torsion_polynomial_old(self, n, var='x', i=0): |
|---|
| | 1623 | # r""" |
|---|
| | 1624 | # Returns the n-th torsion polynomial (a.k.a., division polynomial). |
|---|
| | 1625 | |
|---|
| | 1626 | # INPUT: |
|---|
| | 1627 | # n -- non-negative integer |
|---|
| | 1628 | # var -- string; the indeterminate of the polynomial (default: x) |
|---|
| | 1629 | # i -- integer, either 0 (default) or 1. |
|---|
| | 1630 | |
|---|
| | 1631 | # OUTPUT: |
|---|
| | 1632 | # Polynomial -- n-th torsion polynomial, which is a polynomial over |
|---|
| | 1633 | # the base field of the elliptic curve. |
|---|
| | 1634 | |
|---|
| | 1635 | # SEE ALSO: _division_polynomial, full_division_polynomial |
|---|
| | 1636 | |
|---|
| | 1637 | # EXAMPLES: |
|---|
| | 1638 | # sage: E = EllipticCurve([0,0,1,-1,0]) |
|---|
| | 1639 | # sage: E.torsion_polynomial_old(1) |
|---|
| | 1640 | # 1 |
|---|
| | 1641 | # sage: E.torsion_polynomial_old(2) |
|---|
| | 1642 | # 4*x^3 - 4*x + 1 |
|---|
| | 1643 | # sage: E.torsion_polynomial_old(3, 'z') |
|---|
| | 1644 | # 3*z^4 - 6*z^2 + 3*z - 1 |
|---|
| | 1645 | |
|---|
| | 1646 | # sage: E = EllipticCurve([0, -1, 1, -10, -20]) |
|---|
| | 1647 | # sage: E.torsion_polynomial(0) |
|---|
| | 1648 | # 0 |
|---|
| | 1649 | # sage: E.torsion_polynomial(1) |
|---|
| | 1650 | # 1 |
|---|
| | 1651 | # sage: E.torsion_polynomial(2) |
|---|
| | 1652 | # 4*x^3 - 4*x^2 - 40*x - 79 |
|---|
| | 1653 | # sage: E.torsion_polynomial(3) |
|---|
| | 1654 | # 3*x^4 - 4*x^3 - 60*x^2 - 237*x - 21 |
|---|
| | 1655 | # sage: E.torsion_polynomial(4) |
|---|
| | 1656 | # 8*x^9 - 24*x^8 - 464*x^7 - 2758*x^6 + 6636*x^5 + 34356*x^4 + 53510*x^3 + 99714*x^2 + 351024*x + 459859 |
|---|
| | 1657 | |
|---|
| | 1658 | # sage: E = EllipticCurve([-4,0]) |
|---|
| | 1659 | # sage: E.torsion_polynomial(2) |
|---|
| | 1660 | # 4*x^3 - 16*x |
|---|
| | 1661 | # sage: E.torsion_polynomial(5) |
|---|
| | 1662 | # 5*x^12 - 248*x^10 - 1680*x^8 + 19200*x^6 - 32000*x^4 + 51200*x^2 + 4096 |
|---|
| | 1663 | # sage: E.torsion_polynomial(6) |
|---|
| | 1664 | # 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 |
|---|
| | 1665 | |
|---|
| | 1666 | # Check for consistency with division_polynomial_0: |
|---|
| | 1667 | # sage: assert all([E.torsion_polynomial(2*m-1)==E.division_polynomial_0(2*m-1) for m in range(1,20)]) |
|---|
| | 1668 | # sage: assert all([E.torsion_polynomial(2*m)==E.division_polynomial_0(2*m)*E.division_polynomial_0(-1) for m in range(1,20)]) |
|---|
| | 1669 | |
|---|
| | 1670 | # AUTHOR: David Kohel (kohel@maths.usyd.edu.au), 2005-04-25 |
|---|
| | 1671 | # """ |
|---|
| | 1672 | # n = int(n) |
|---|
| | 1673 | # try: |
|---|
| | 1674 | # return self.__torsion_polynomial[n] |
|---|
| | 1675 | # except AttributeError: |
|---|
| | 1676 | # self.__torsion_polynomial = {} |
|---|
| | 1677 | # except KeyError: |
|---|
| | 1678 | # pass |
|---|
| | 1679 | # E = self; i=int(i) |
|---|
| | 1680 | # if n < 0: |
|---|
| | 1681 | # raise ValueError, "n must be a non-negative integer." |
|---|
| | 1682 | # if i > 1 : |
|---|
| | 1683 | # raise ValueError, "i must be 0 or 1." |
|---|
| | 1684 | |
|---|
| | 1685 | # R = rings.PolynomialRing(E.base_ring(), var) |
|---|
| | 1686 | |
|---|
| | 1687 | # # This is just an abbreviation to make the following code clearer: |
|---|
| | 1688 | # tp = lambda m: E.torsion_polynomial(m) |
|---|
| | 1689 | |
|---|
| | 1690 | # if i == 1: |
|---|
| | 1691 | # if n == 0: |
|---|
| | 1692 | # f = tp(1) |
|---|
| | 1693 | # E.__torsion_polynomial[n] = f |
|---|
| | 1694 | # return f |
|---|
| | 1695 | # else: |
|---|
| | 1696 | # x = R.gen() |
|---|
| | 1697 | # psi2 = tp(2) |
|---|
| | 1698 | # if n%2 == 0: |
|---|
| | 1699 | # f = x * psi2 * (tp(n)//psi2)**2 - tp(n+1) * tp(n-1) |
|---|
| | 1700 | # E.__torsion_polynomial[n] = f |
|---|
| | 1701 | # return f |
|---|
| | 1702 | # else: |
|---|
| | 1703 | # f = x * tp(n)**2 - (tp(n+1)//psi2) * tp(n-1) |
|---|
| | 1704 | # E.__torsion_polynomial[n] = f |
|---|
| | 1705 | # return f |
|---|
| | 1706 | |
|---|
| | 1707 | # else: |
|---|
| | 1708 | |
|---|
| | 1709 | # if n == 0: return R(0) |
|---|
| | 1710 | # if n == 1: return R(1) |
|---|
| | 1711 | # x = R.gen() |
|---|
| | 1712 | # b2, b4, b6, b8 = E.b_invariants() |
|---|
| | 1713 | # psi2 = 4*x**3 + b2*x**2 + 2*b4*x + b6 |
|---|
| | 1714 | # if n == 2: |
|---|
| | 1715 | # f = psi2 |
|---|
| | 1716 | # E.__torsion_polynomial[n] = f; return f |
|---|
| | 1717 | # if n == 3: |
|---|
| | 1718 | # f = 3*x**4 + b2*x**3 + 3*b4*x**2 + 3*b6*x + b8 |
|---|
| | 1719 | # E.__torsion_polynomial[n] = f; return f |
|---|
| | 1720 | # if n == 4: |
|---|
| | 1721 | # f = psi2 * (2*x**6 + b2*x**5 + 5*b4*x**4 + 10*b6*x**3 \ |
|---|
| | 1722 | # + 10*b8*x**2 + (b2*b8 - b4*b6)*x + b4*b8 - b6**2) |
|---|
| | 1723 | # E.__torsion_polynomial[n] = f; return f |
|---|
| | 1724 | # if n%2 == 0: |
|---|
| | 1725 | # m = n//2 |
|---|
| | 1726 | # if m%2 == 0: |
|---|
| | 1727 | # f = tp(m) * \ |
|---|
| | 1728 | # ((tp(m+2)//psi2) * tp(m-1)**2 - \ |
|---|
| | 1729 | # (tp(m-2)//psi2) * tp(m+1)**2) |
|---|
| | 1730 | # E.__torsion_polynomial[n] = f; return f |
|---|
| | 1731 | # else: |
|---|
| | 1732 | # f = psi2 * tp(m)*( \ |
|---|
| | 1733 | # tp(m+2) * (tp(m-1)//psi2)**2 - \ |
|---|
| | 1734 | # tp(m-2) * (tp(m+1)//psi2)**2) |
|---|
| | 1735 | # E.__torsion_polynomial[n] = f; return f |
|---|
| | 1736 | # else: |
|---|
| | 1737 | # m = n//2 |
|---|
| | 1738 | # if m%2 == 0: |
|---|
| | 1739 | # f = psi2 * \ |
|---|
| | 1740 | # tp(m+2) * (tp(m)//psi2)**3 - \ |
|---|
| | 1741 | # tp(m-1) * tp(m+1)**3 |
|---|
| | 1742 | # E.__torsion_polynomial[n] = f; return f |
|---|
| | 1743 | # else: |
|---|
| | 1744 | # f = tp(m+2) * tp(m)**3 - psi2 * \ |
|---|
| | 1745 | # tp(m-1)*(tp(m+1)//psi2)**3 |
|---|
| | 1746 | # E.__torsion_polynomial[n] = f; return f |
|---|
| | 1747 | |
|---|
| | 1748 | # def full_division_polynomial(self, m): |
|---|
| | 1749 | # """ |
|---|
| | 1750 | # Return the $m$-th bivariate division polynomial in $x$ and |
|---|
| | 1751 | # $y$. When $m$ is odd this is exactly the same as the usual |
|---|
| | 1752 | # $m$th division polynomial. |
|---|
| | 1753 | |
|---|
| | 1754 | # For the usual division polynomial only in $x$, see the |
|---|
| | 1755 | # functions division_polynomial() and |
|---|
| | 1756 | # division_polynomial_0(). |
|---|
| | 1757 | |
|---|
| | 1758 | # INPUT: |
|---|
| | 1759 | # self -- elliptic curve |
|---|
| | 1760 | # m -- a positive integer |
|---|
| | 1761 | # OUTPUT: |
|---|
| | 1762 | # a polynomial in two variables $x$, $y$. |
|---|
| | 1763 | |
|---|
| | 1764 | # NOTE: The result is cached. |
|---|
| | 1765 | |
|---|
| | 1766 | # EXAMPLES: |
|---|
| | 1767 | # We create a curve and compute the first two full division |
|---|
| | 1768 | # polynomials. |
|---|
| | 1769 | # sage: E = EllipticCurve([2,3]) |
|---|
| | 1770 | # sage: E.full_division_polynomial(1) |
|---|
| | 1771 | # 1 |
|---|
| | 1772 | # sage: E.full_division_polynomial(2) |
|---|
| | 1773 | # 2*y |
|---|
| | 1774 | |
|---|
| | 1775 | # Note that for odd input the full division polynomial is |
|---|
| | 1776 | # just the usual division polynomial, but not for even input: |
|---|
| | 1777 | # sage: E.division_polynomial(2) |
|---|
| | 1778 | # 4*x^3 + 8*x + 12 |
|---|
| | 1779 | # sage: E.full_division_polynomial(3) |
|---|
| | 1780 | # 3*x^4 + 12*x^2 + 36*x - 4 |
|---|
| | 1781 | # sage: E.division_polynomial(3) |
|---|
| | 1782 | # 3*x^4 + 12*x^2 + 36*x - 4 |
|---|
| | 1783 | # sage: E.full_division_polynomial(4) |
|---|
| | 1784 | # 4*x^6*y + 40*x^4*y + 240*x^3*y - 80*x^2*y - 96*x*y - 320*y |
|---|
| | 1785 | # sage: E.full_division_polynomial(5) |
|---|
| | 1786 | # 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 |
|---|
| | 1787 | |
|---|
| | 1788 | # TESTS: |
|---|
| | 1789 | # We test that the full division polynomial as computed using |
|---|
| | 1790 | # the recurrence agrees with the normal division polynomial for |
|---|
| | 1791 | # a certain curve and all odd $n$ up to $23$: |
|---|
| | 1792 | |
|---|
| | 1793 | # sage: E = EllipticCurve([23,-105]) |
|---|
| | 1794 | # sage: for n in [1,3,..,23]: |
|---|
| | 1795 | # ... assert E.full_division_polynomial(n) == E.division_polynomial(n) |
|---|
| | 1796 | # """ |
|---|
| | 1797 | # # Coerce the input m to be an integer |
|---|
| | 1798 | # m = rings.Integer(m) |
|---|
| | 1799 | |
|---|
| | 1800 | # # Check whether the corresponding poly is cached already |
|---|
| | 1801 | # try: |
|---|
| | 1802 | # return self.__divpoly2[m] |
|---|
| | 1803 | # except AttributeError: |
|---|
| | 1804 | # self.__divpoly2 = {} |
|---|
| | 1805 | # except KeyError: |
|---|
| | 1806 | # pass |
|---|
| | 1807 | |
|---|
| | 1808 | # # Get the invariants of the curve |
|---|
| | 1809 | # a1,a2,a3,a4,a6 = self.a_invariants() |
|---|
| | 1810 | |
|---|
| | 1811 | # # Define the polynomial ring that will contain the full |
|---|
| | 1812 | # # division polynomial. |
|---|
| | 1813 | |
|---|
| | 1814 | # R, (x,y) = PolynomialRing(self.base_ring(), 2, 'x,y').objgens() |
|---|
| | 1815 | |
|---|
| | 1816 | # # The function division_polynomial_0() gives the correct |
|---|
| | 1817 | # # result when m is odd, and all we do in this case is evaluate |
|---|
| | 1818 | # # this at the variable x in our bivariate polynomial ring. |
|---|
| | 1819 | |
|---|
| | 1820 | # # For even m, we must multiply the result of |
|---|
| | 1821 | # # division_polynomial_0() by the full 2-torsion polynomial |
|---|
| | 1822 | # # which is 2*y+a1*x+a3 |
|---|
| | 1823 | |
|---|
| | 1824 | # f = self.division_polynomial_0(m,x) |
|---|
| | 1825 | # if m % 2 == 0: |
|---|
| | 1826 | # f *= (2*y+a1*x+a3) |
|---|
| | 1827 | |
|---|
| | 1828 | # # Cache the result and return it. |
|---|
| | 1829 | # self.__divpoly2[m] = f |
|---|
| | 1830 | # return f |
|---|
| 1604 | | |
|---|
| 1605 | | def torsion_polynomial(self, n, var='x', i=0): |
|---|
| 1606 | | r""" |
|---|
| 1607 | | Returns the n-th torsion polynomial (a.k.a., division polynomial). |
|---|
| 1608 | | |
|---|
| 1609 | | INPUT: |
|---|
| 1610 | | n -- non-negative integer |
|---|
| 1611 | | var -- string; the indeterminate of the polynomial (default: x) |
|---|
| 1612 | | i -- integer, either 0 (default) or 1. |
|---|
| 1613 | | |
|---|
| 1614 | | OUTPUT: |
|---|
| 1615 | | Polynomial -- n-th torsion polynomial, which is a polynomial over |
|---|
| 1616 | | the base field of the elliptic curve. |
|---|
| 1617 | | |
|---|
| 1618 | | SEE ALSO: pseudo_torsion_polynomial, full_division_polynomial |
|---|
| 1619 | | |
|---|
| 1620 | | ALIASES: division_polynomial, torsion_polynomial |
|---|
| 1621 | | |
|---|
| 1622 | | EXAMPLES: |
|---|
| 1623 | | sage: E = EllipticCurve([0,0,1,-1,0]) |
|---|
| 1624 | | sage: E.division_polynomial(1) |
|---|
| 1625 | | 1 |
|---|
| 1626 | | sage: E.division_polynomial(2) |
|---|
| 1627 | | 4*x^3 - 4*x + 1 |
|---|
| 1628 | | sage: E.division_polynomial(3, 'z') |
|---|
| 1629 | | 3*z^4 - 6*z^2 + 3*z - 1 |
|---|
| 1630 | | |
|---|
| 1631 | | sage: E = EllipticCurve([0, -1, 1, -10, -20]) |
|---|
| 1632 | | sage: E.torsion_polynomial(0) |
|---|
| 1633 | | 0 |
|---|
| 1634 | | sage: E.torsion_polynomial(1) |
|---|
| 1635 | | 1 |
|---|
| 1636 | | sage: E.torsion_polynomial(2) |
|---|
| 1637 | | 4*x^3 - 4*x^2 - 40*x - 79 |
|---|
| 1638 | | sage: E.torsion_polynomial(3) |
|---|
| 1639 | | 3*x^4 - 4*x^3 - 60*x^2 - 237*x - 21 |
|---|
| 1640 | | sage: E.torsion_polynomial(4) |
|---|
| 1641 | | 8*x^9 - 24*x^8 - 464*x^7 - 2758*x^6 + 6636*x^5 + 34356*x^4 + 53510*x^3 + 99714*x^2 + 351024*x + 459859 |
|---|
| 1642 | | |
|---|
| 1643 | | sage: E = EllipticCurve([-4,0]) |
|---|
| 1644 | | sage: E.torsion_polynomial(2) |
|---|
| 1645 | | 4*x^3 - 16*x |
|---|
| 1646 | | sage: E.torsion_polynomial(5) |
|---|
| 1647 | | 5*x^12 - 248*x^10 - 1680*x^8 + 19200*x^6 - 32000*x^4 + 51200*x^2 + 4096 |
|---|
| 1648 | | sage: E.torsion_polynomial(6) |
|---|
| 1649 | | 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 |
|---|
| 1650 | | |
|---|
| 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 | | |
|---|
| 1655 | | AUTHOR: David Kohel (kohel@maths.usyd.edu.au), 2005-04-25 |
|---|
| 1656 | | """ |
|---|
| 1657 | | n = int(n) |
|---|
| 1658 | | try: |
|---|
| 1659 | | return self.__torsion_polynomial[n] |
|---|
| 1660 | | except AttributeError: |
|---|
| 1661 | | self.__torsion_polynomial = {} |
|---|
| 1662 | | except KeyError: |
|---|
| 1663 | | pass |
|---|
| 1664 | | E = self; i=int(i) |
|---|
| 1665 | | if n < 0: |
|---|
| 1666 | | raise ValueError, "n must be a non-negative integer." |
|---|
| 1667 | | if i > 1 : |
|---|
| 1668 | | raise ValueError, "i must be 0 or 1." |
|---|
| 1669 | | |
|---|
| 1670 | | 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 | | |
|---|
| 1675 | | if i == 1: |
|---|
| 1676 | | if n == 0: |
|---|
| 1677 | | f = tp(1) |
|---|
| 1678 | | E.__torsion_polynomial[n] = f |
|---|
| 1679 | | return f |
|---|
| 1680 | | else: |
|---|
| 1681 | | x = R.gen() |
|---|
| 1682 | | psi2 = tp(2) |
|---|
| 1683 | | if n%2 == 0: |
|---|
| 1684 | | f = x * psi2 * (tp(n)//psi2)**2 - tp(n+1) * tp(n-1) |
|---|
| 1685 | | E.__torsion_polynomial[n] = f |
|---|
| 1686 | | return f |
|---|
| 1687 | | else: |
|---|
| 1688 | | f = x * tp(n)**2 - (tp(n+1)//psi2) * tp(n-1) |
|---|
| 1689 | | E.__torsion_polynomial[n] = f |
|---|
| 1690 | | return f |
|---|
| 1691 | | |
|---|
| 1692 | | else: |
|---|
| 1693 | | |
|---|
| 1694 | | if n == 0: return R(0) |
|---|
| 1695 | | if n == 1: return R(1) |
|---|
| 1696 | | x = R.gen() |
|---|
| 1697 | | b2, b4, b6, b8 = E.b_invariants() |
|---|
| 1698 | | psi2 = 4*x**3 + b2*x**2 + 2*b4*x + b6 |
|---|
| 1699 | | if n == 2: |
|---|
| 1700 | | f = psi2 |
|---|
| 1701 | | E.__torsion_polynomial[n] = f; return f |
|---|
| 1702 | | if n == 3: |
|---|
| 1703 | | f = 3*x**4 + b2*x**3 + 3*b4*x**2 + 3*b6*x + b8 |
|---|
| 1704 | | E.__torsion_polynomial[n] = f; return f |
|---|
| 1705 | | if n == 4: |
|---|
| 1706 | | f = psi2 * (2*x**6 + b2*x**5 + 5*b4*x**4 + 10*b6*x**3 \ |
|---|
| 1707 | | + 10*b8*x**2 + (b2*b8 - b4*b6)*x + b4*b8 - b6**2) |
|---|
| 1708 | | E.__torsion_polynomial[n] = f; return f |
|---|
| 1709 | | if n%2 == 0: |
|---|
| 1710 | | m = n//2 |
|---|
| 1711 | | if m%2 == 0: |
|---|
| 1712 | | f = tp(m) * \ |
|---|
| 1713 | | ((tp(m+2)//psi2) * tp(m-1)**2 - \ |
|---|
| 1714 | | (tp(m-2)//psi2) * tp(m+1)**2) |
|---|
| 1715 | | E.__torsion_polynomial[n] = f; return f |
|---|
| 1716 | | else: |
|---|
| 1717 | | f = psi2 * tp(m)*( \ |
|---|
| 1718 | | tp(m+2) * (tp(m-1)//psi2)**2 - \ |
|---|
| 1719 | | tp(m-2) * (tp(m+1)//psi2)**2) |
|---|
| 1720 | | E.__torsion_polynomial[n] = f; return f |
|---|
| 1721 | | else: |
|---|
| 1722 | | m = n//2 |
|---|
| 1723 | | if m%2 == 0: |
|---|
| 1724 | | f = psi2 * \ |
|---|
| 1725 | | tp(m+2) * (tp(m)//psi2)**3 - \ |
|---|
| 1726 | | tp(m-1) * tp(m+1)**3 |
|---|
| 1727 | | E.__torsion_polynomial[n] = f; return f |
|---|
| 1728 | | else: |
|---|
| 1729 | | f = tp(m+2) * tp(m)**3 - psi2 * \ |
|---|
| 1730 | | tp(m-1)*(tp(m+1)//psi2)**3 |
|---|
| 1731 | | E.__torsion_polynomial[n] = f; return f |
|---|
| 1732 | | |
|---|
| 1733 | | division_polynomial = torsion_polynomial |
|---|
| 1734 | | |
|---|
| 1735 | | def full_division_polynomial(self, m): |
|---|
| 1736 | | """ |
|---|
| 1737 | | Return the $m$-th bivariate division polynomial in $x$ and |
|---|
| 1738 | | $y$. When $m$ is odd this is exactly the same as the usual |
|---|
| 1739 | | $m$th division polynomial. |
|---|
| 1740 | | |
|---|
| 1741 | | For the usual division polynomial only in $x$, see the |
|---|
| 1742 | | functions division_polynomial() and |
|---|
| 1743 | | pseudo_torsion_polynomial(). |
|---|
| 1744 | | |
|---|
| 1745 | | INPUT: |
|---|
| 1746 | | self -- elliptic curve |
|---|
| 1747 | | m -- a positive integer |
|---|
| 1748 | | OUTPUT: |
|---|
| 1749 | | a polynomial in two variables $x$, $y$. |
|---|
| 1750 | | |
|---|
| 1751 | | NOTE: The result is cached. |
|---|
| 1752 | | |
|---|
| 1753 | | EXAMPLES: |
|---|
| 1754 | | We create a curve and compute the first two full division |
|---|
| 1755 | | polynomials. |
|---|
| 1756 | | sage: E = EllipticCurve([2,3]) |
|---|
| 1757 | | sage: E.full_division_polynomial(1) |
|---|
| 1758 | | 1 |
|---|
| 1759 | | sage: E.full_division_polynomial(2) |
|---|
| 1760 | | 2*y |
|---|
| 1761 | | |
|---|
| 1762 | | Note that for odd input the full division polynomial is |
|---|
| 1763 | | just the usual division polynomial, but not for even input: |
|---|
| 1764 | | sage: E.division_polynomial(2) |
|---|
| 1765 | | 4*x^3 + 8*x + 12 |
|---|
| 1766 | | sage: E.full_division_polynomial(3) |
|---|
| 1767 | | 3*x^4 + 12*x^2 + 36*x - 4 |
|---|
| 1768 | | sage: E.division_polynomial(3) |
|---|
| 1769 | | 3*x^4 + 12*x^2 + 36*x - 4 |
|---|
| 1770 | | sage: E.full_division_polynomial(4) |
|---|
| 1771 | | 4*x^6*y + 40*x^4*y + 240*x^3*y - 80*x^2*y - 96*x*y - 320*y |
|---|
| 1772 | | sage: E.full_division_polynomial(5) |
|---|
| 1773 | | 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 |
|---|
| 1774 | | |
|---|
| 1775 | | TESTS: |
|---|
| 1776 | | We test that the full division polynomial as computed using |
|---|
| 1777 | | the recurrence agrees with the normal division polynomial for |
|---|
| 1778 | | a certain curve and all odd $n$ up to $23$: |
|---|
| 1779 | | |
|---|
| 1780 | | sage: E = EllipticCurve([23,-105]) |
|---|
| 1781 | | sage: for n in [1,3,..,23]: |
|---|
| 1782 | | ... assert E.full_division_polynomial(n) == E.division_polynomial(n) |
|---|
| 1783 | | """ |
|---|
| 1784 | | # Coerce the input m to be an integer |
|---|
| 1785 | | m = rings.Integer(m) |
|---|
| 1786 | | |
|---|
| 1787 | | # Check whether the corresponding poly is cached already |
|---|
| 1788 | | try: |
|---|
| 1789 | | return self.__divpoly2[m] |
|---|
| 1790 | | except AttributeError: |
|---|
| 1791 | | self.__divpoly2 = {} |
|---|
| 1792 | | except KeyError: |
|---|
| 1793 | | pass |
|---|
| 1794 | | |
|---|
| 1795 | | # Get the invariants of the curve |
|---|
| 1796 | |
|---|