[arch-commits] Commit in sagemath/trunk (PKGBUILD sagemath-eclib-20210310.patch)

Antonio Rojas arojas at archlinux.org
Thu Mar 11 22:21:37 UTC 2021


    Date: Thursday, March 11, 2021 @ 22:21:37
  Author: arojas
Revision: 887625

eclib 20210310 rebuild

Added:
  sagemath/trunk/sagemath-eclib-20210310.patch
Modified:
  sagemath/trunk/PKGBUILD

-------------------------------+
 PKGBUILD                      |   10 
 sagemath-eclib-20210310.patch | 1388 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1395 insertions(+), 3 deletions(-)

Modified: PKGBUILD
===================================================================
--- PKGBUILD	2021-03-11 22:19:10 UTC (rev 887624)
+++ PKGBUILD	2021-03-11 22:21:37 UTC (rev 887625)
@@ -8,7 +8,7 @@
 pkgbase=sagemath
 pkgname=(sagemath sagemath-jupyter)
 pkgver=9.2
-pkgrel=14
+pkgrel=15
 pkgdesc="Open Source Mathematics Software, free alternative to Magma, Maple, Mathematica, and Matlab"
 arch=(x86_64)
 url="http://www.sagemath.org"
@@ -45,7 +45,8 @@
         sagemath-cypari-2.1.2.patch
         sagemath-pari-2.13.patch
         sagemath-threejs-sage.patch::"https://github.com/sagemath/sage/commit/f4909e1c.patch"
-        sagemath-lrcalc2.patch)
+        sagemath-lrcalc2.patch
+        sagemath-eclib-20210310.patch)
 sha256sums=('edc89776461247cf74a16473851378e70a2de867309978ca2346ef6f93af0f90'
             '00cf73534c10bb8694c77639670aa041b4b8c897babb01751a5f65648bcfdcf6'
             'af922e1f978821a9a1f6c9a56130d71e5011c84a7aee7bf66a591bee658af30b'
@@ -57,7 +58,8 @@
             'dc507eeb75eae1109273879771b4eb56172b7417e87a0693381106afd7554e04'
             '84875c90268436cb6a740a4e1bffd70b4895458ef9e1ee268a3c4aa0564e893f'
             'c27f7697a94cfe9d0581819fcd9dabcec5fb8471ea761ad2db91399355249a06'
-            '240ac4c29d96d56407a20e1b7f9846e342a7eb2bb4edd6e5c86b3b5a8ff462f9')
+            '240ac4c29d96d56407a20e1b7f9846e342a7eb2bb4edd6e5c86b3b5a8ff462f9'
+            '2abc90fe042799e0ebcbef70af258ca774c697d36dfa3d4c7d2ceba3a7089798')
 
 prepare(){
   cd sage-$pkgver
@@ -81,6 +83,8 @@
   patch -p1 -i ../sagemath-threejs-sage.patch
 # Replace lrcalc.pyx with a wrapper over lrcalc's python bindings https://trac.sagemath.org/ticket/31355
   patch -p1 -i ../sagemath-lrcalc2.patch
+# Fix build with eclib 20210310 https://trac.sagemath.org/ticket/31443
+  patch -p1 -i ../sagemath-eclib-20210310.patch
 
 # Arch-specific patches
 # assume all optional packages are installed

Added: sagemath-eclib-20210310.patch
===================================================================
--- sagemath-eclib-20210310.patch	                        (rev 0)
+++ sagemath-eclib-20210310.patch	2021-03-11 22:21:37 UTC (rev 887625)
@@ -0,0 +1,1388 @@
+diff --git a/build/pkgs/eclib/checksums.ini b/build/pkgs/eclib/checksums.ini
+index 4daaf05..b37bff9 100644
+--- a/build/pkgs/eclib/checksums.ini
++++ b/build/pkgs/eclib/checksums.ini
+@@ -1,4 +1,4 @@
+-tarball=eclib-20190909.tar.bz2
+-sha1=0e994c0de95ef03ef19ad5030a2cacbb83c76bbd
+-md5=1a67217a7fa762646d43c7bec8a73028
+-cksum=4240278408
++tarball=eclib-20210310.tar.bz2
++sha1=73437ac8deae94f00e7713405b3251d9c81f95e4
++md5=4ac988bc46869866f076f7bea0fdaa6b
++cksum=2130748042
+diff --git a/build/pkgs/eclib/package-version.txt b/build/pkgs/eclib/package-version.txt
+index 4defdea..3384f6c 100644
+--- a/build/pkgs/eclib/package-version.txt
++++ b/build/pkgs/eclib/package-version.txt
+@@ -1 +1 @@
+-20190909
++20210310
+diff --git a/src/sage/libs/eclib/__init__.pxd b/src/sage/libs/eclib/__init__.pxd
+index 7ff4ac1..825f600 100644
+--- a/src/sage/libs/eclib/__init__.pxd
++++ b/src/sage/libs/eclib/__init__.pxd
+@@ -8,9 +8,11 @@ from libcpp.pair cimport pair
+ from sage.libs.ntl.types cimport ZZ_c
+ 
+ 
+-# NOTE: eclib includes have specific dependencies and must be included
+-# in a specific order. So we start by listing all relevant include files
+-# in the correct order.
++# NOTE: eclib used to have specific dependencies, so that they had to
++# be included in a specific order. Although this is no longer the
++# case, we start by listing all relevant include files in the correct
++# order.
++
+ cdef extern from "eclib/vector.h": pass
+ cdef extern from "eclib/xmod.h": pass
+ cdef extern from "eclib/svector.h": pass
+@@ -141,7 +143,7 @@ cdef extern from "eclib/newforms.h":
+ 
+         newforms(long n, int disp)
+ 
+-        void createfromcurve(int sign, CurveRed CR)
++        void createfromcurve(int sign, CurveRed CR, int nap)
+         void display()
+         # Here i is the index of the relevant newform in the space,
+         # which for us will always be 0:
+diff --git a/src/sage/libs/eclib/interface.py b/src/sage/libs/eclib/interface.py
+index e898456..493b5f1 100644
+--- a/src/sage/libs/eclib/interface.py
++++ b/src/sage/libs/eclib/interface.py
+@@ -21,17 +21,16 @@ Check that ``eclib`` is imported as needed::
+     sage: [k for k in sys.modules if k.startswith("sage.libs.eclib")]
+     []
+     sage: EllipticCurve('11a1').mwrank_curve()
+-    y^2+ y = x^3 - x^2 - 10*x - 20
++    y^2 + y = x^3 - x^2 - 10 x - 20
+     sage: [k for k in sys.modules if k.startswith("sage.libs.eclib")]
+     ['...']
+ """
+-
++import sys
+ from sage.structure.sage_object import SageObject
+ from sage.rings.all import Integer
+ from sage.rings.integer_ring import IntegerRing
+ 
+-from .mwrank import _Curvedata, _two_descent, _mw
+-
++from .mwrank import _Curvedata, _two_descent, _mw, parse_point_list
+ 
+ class mwrank_EllipticCurve(SageObject):
+     r"""
+@@ -67,7 +66,7 @@ class mwrank_EllipticCurve(SageObject):
+ 
+         sage: e = mwrank_EllipticCurve([3, -4])
+         sage: e
+-        y^2 = x^3 + 3*x - 4
++        y^2 = x^3 + 3 x - 4
+         sage: e.ainvs()
+         [0, 0, 0, 3, -4]
+ 
+@@ -127,6 +126,7 @@ class mwrank_EllipticCurve(SageObject):
+ 
+         # place holders
+         self.__saturate = -2  # not yet saturated
++        self.__descent = None
+ 
+     def __reduce__(self):
+         r"""
+@@ -137,12 +137,9 @@ class mwrank_EllipticCurve(SageObject):
+             sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
+             sage: E.__reduce__()
+             (<class 'sage.libs.eclib.interface.mwrank_EllipticCurve'>, ([0, 0, 1, -7, 6], False))
+-
+-
+         """
+         return mwrank_EllipticCurve, (self.__ainvs, self.__verbose)
+ 
+-
+     def set_verbose(self, verbose):
+         """
+         Set the verbosity of printing of output by the :meth:`two_descent()` and
+@@ -247,53 +244,27 @@ class mwrank_EllipticCurve(SageObject):
+ 
+             sage: E = mwrank_EllipticCurve([0,-1,1,0,0])
+             sage: E.__repr__()
+-            'y^2+ y = x^3 - x^2 '
++            'y^2 + y = x^3 - x^2'
+         """
+-        # TODO: Is the use (or omission) of spaces here intentional?
+-        a = self.ainvs()
+-        s = "y^2"
+-        if a[0] == -1:
+-            s += "- x*y "
+-        elif a[0] == 1:
+-            s += "+ x*y "
+-        elif a[0] != 0:
+-            s += "+ %s*x*y "%a[0]
+-        if a[2] == -1:
+-            s += " - y"
+-        elif a[2] == 1:
+-            s += "+ y"
+-        elif a[2] != 0:
+-            s += "+ %s*y"%a[2]
+-        s += " = x^3 "
+-        if a[1] == -1:
+-            s += "- x^2 "
+-        elif a[1] == 1:
+-            s += "+ x^2 "
+-        elif a[1] != 0:
+-            s += "+ %s*x^2 "%a[1]
+-        if a[3] == -1:
+-            s += "- x "
+-        elif a[3] == 1:
+-            s += "+ x "
+-        elif a[3] != 0:
+-            s += "+ %s*x "%a[3]
+-        if a[4] == -1:
+-            s += "-1"
+-        elif a[4] == 1:
+-            s += "+1"
+-        elif a[4] != 0:
+-            s += "+ %s"%a[4]
+-        s = s.replace("+ -","- ")
+-        return s
+-
++        a1, a2, a3, a4, a6 = self.__ainvs
++        # we do not assume a1, a2, a3 are reduced to {0,1}, {-1,0,1}, {0,1}
++        coeff = lambda a: ''.join([" +" if a > 0 else " -",
++                                   " " + str(abs(a)) if abs(a) > 1 else ""])
++        return ''.join(['y^2',
++                        ' '.join([coeff(a1), 'xy']) if a1 else '',
++                        ' '.join([coeff(a3), 'y']) if a3 else '',
++                        ' = x^3',
++                        ' '.join([coeff(a2), 'x^2']) if a2 else '',
++                        ' '.join([coeff(a4), 'x']) if a4 else '',
++                        ' '.join([" +" if a6 > 0 else " -", str(abs(a6))]) if a6 else ''])
+ 
+     def two_descent(self,
+-                    verbose = True,
+-                    selmer_only = False,
+-                    first_limit = 20,
+-                    second_limit = 8,
+-                    n_aux = -1,
+-                    second_descent = True):
++                    verbose=True,
++                    selmer_only=False,
++                    first_limit=20,
++                    second_limit=8,
++                    n_aux=-1,
++                    second_descent=True):
+         r"""
+         Compute 2-descent data for this curve.
+ 
+@@ -374,16 +345,14 @@ class mwrank_EllipticCurve(SageObject):
+         second_limit = int(second_limit)
+         n_aux = int(n_aux)
+         second_descent = int(second_descent)    # convert from bool to (int) 0 or 1
+-        # TODO:  Don't allow limits above some value...???
+-        #   (since otherwise mwrank just sets limit tiny)
+         self.__descent = _two_descent()
+         self.__descent.do_descent(self.__curve,
+-                                      verbose,
+-                                      selmer_only,
+-                                      first_limit,
+-                                      second_limit,
+-                                      n_aux,
+-                                      second_descent)
++                                  verbose,
++                                  selmer_only,
++                                  first_limit,
++                                  second_limit,
++                                  n_aux,
++                                  second_descent)
+         if not self.__descent.ok():
+             raise RuntimeError("A 2-descent did not complete successfully.")
+         self.__saturate = -2  # not yet saturated
+@@ -398,11 +367,9 @@ class mwrank_EllipticCurve(SageObject):
+             sage: E._mwrank_EllipticCurve__two_descent_data()
+             <sage.libs.eclib.mwrank._two_descent object at ...>
+         """
+-        try:
+-            return self.__descent
+-        except AttributeError:
++        if self.__descent is None:
+             self.two_descent(self.__verbose)
+-            return self.__descent
++        return self.__descent
+ 
+     def conductor(self):
+         """
+@@ -565,22 +532,24 @@ class mwrank_EllipticCurve(SageObject):
+         R = self.__two_descent_data().regulator()
+         return float(R)
+ 
+-    def saturate(self, bound=-1):
++    def saturate(self, bound=-1, lower=2):
+         """
+-        Compute the saturation of the Mordell-Weil group at all
+-        primes up to ``bound``.
++        Compute the saturation of the Mordell-Weil group.
+ 
+         INPUT:
+ 
+-        - ``bound`` (int, default -1) -- Use `-1` (the default) to
+-          saturate at *all* primes, `0` for no saturation, or `n` (a
+-          positive integer) to saturate at all primes up to `n`.
++        - ``bound`` (int, default -1) -- If `-1`, saturate at *all*
++          primes by computing a bound on the saturation index,
++          otherwise saturate at all primes up to the minimum of
++          ``bound`` and the saturation index bound.
++
++        - ``lower`` (int, default 2) -- Only saturate at primes not
++          less than this.
+ 
+         EXAMPLES:
+ 
+         Since the 2-descent automatically saturates at primes up to
+-        20, it is not easy to come up with an example where saturation
+-        has any effect::
++        20, further saturation often has no effect::
+ 
+             sage: E = mwrank_EllipticCurve([0, 0, 0, -1002231243161, 0])
+             sage: E.gens()
+@@ -599,7 +568,7 @@ class mwrank_EllipticCurve(SageObject):
+         """
+         bound = int(bound)
+         if self.__saturate < bound:
+-            self.__two_descent_data().saturate(bound)
++            self.__two_descent_data().saturate(bound, lower)
+             self.__saturate = bound
+ 
+     def gens(self):
+@@ -613,8 +582,7 @@ class mwrank_EllipticCurve(SageObject):
+             [[0, -1, 1]]
+         """
+         self.saturate()
+-        L = eval(self.__two_descent_data().getbasis().replace(":",","))
+-        return [[Integer(x), Integer(y), Integer(z)] for (x,y,z) in L]
++        return parse_point_list(self.__two_descent_data().getbasis())
+ 
+     def certain(self):
+         r"""
+@@ -760,65 +728,37 @@ class mwrank_MordellWeil(SageObject):
+         sage: EQ.search(1)
+         P1 = [0:1:0]     is torsion point, order 1
+         P1 = [-3:0:1]     is generator number 1
+-        saturating up to 20...Checking 2-saturation
+-        Points have successfully been 2-saturated (max q used = 7)
+-        Checking 3-saturation
+-        Points have successfully been 3-saturated (max q used = 7)
+-        Checking 5-saturation
+-        Points have successfully been 5-saturated (max q used = 23)
+-        Checking 7-saturation
+-        Points have successfully been 7-saturated (max q used = 41)
+-        Checking 11-saturation
+-        Points have successfully been 11-saturated (max q used = 17)
+-        Checking 13-saturation
+-        Points have successfully been 13-saturated (max q used = 43)
+-        Checking 17-saturation
+-        Points have successfully been 17-saturated (max q used = 31)
+-        Checking 19-saturation
+-        Points have successfully been 19-saturated (max q used = 37)
++        saturating up to 20...Saturation index bound (for points of good reduction)  = 3
++        Reducing saturation bound from given value 20 to computed index bound 3
++        Checking saturation at [ 2 3 ]
++        Checking 2-saturation 
++        Points were proved 2-saturated (max q used = 7)
++        Checking 3-saturation 
++        Points were proved 3-saturated (max q used = 7)
+         done
+         P2 = [-2:3:1]     is generator number 2
+-        saturating up to 20...Checking 2-saturation
++        saturating up to 20...Saturation index bound (for points of good reduction)  = 4
++        Reducing saturation bound from given value 20 to computed index bound 4
++        Checking saturation at [ 2 3 ]
++        Checking 2-saturation 
+         possible kernel vector = [1,1]
+         This point may be in 2E(Q): [14:-52:1]
+-        ...and it is!
++        ...and it is! 
+         Replacing old generator #1 with new generator [1:-1:1]
++        Reducing index bound from 4 to 2
+         Points have successfully been 2-saturated (max q used = 7)
+         Index gain = 2^1
+-        Checking 3-saturation
+-        Points have successfully been 3-saturated (max q used = 13)
+-        Checking 5-saturation
+-        Points have successfully been 5-saturated (max q used = 67)
+-        Checking 7-saturation
+-        Points have successfully been 7-saturated (max q used = 53)
+-        Checking 11-saturation
+-        Points have successfully been 11-saturated (max q used = 73)
+-        Checking 13-saturation
+-        Points have successfully been 13-saturated (max q used = 103)
+-        Checking 17-saturation
+-        Points have successfully been 17-saturated (max q used = 113)
+-        Checking 19-saturation
+-        Points have successfully been 19-saturated (max q used = 47)
+-        done (index = 2).
++        done, index = 2.
+         Gained index 2, new generators = [ [1:-1:1] [-2:3:1] ]
+         P3 = [-14:25:8]   is generator number 3
+-        saturating up to 20...Checking 2-saturation
+-        Points have successfully been 2-saturated (max q used = 11)
+-        Checking 3-saturation
+-        Points have successfully been 3-saturated (max q used = 13)
+-        Checking 5-saturation
+-        Points have successfully been 5-saturated (max q used = 71)
+-        Checking 7-saturation
+-        Points have successfully been 7-saturated (max q used = 101)
+-        Checking 11-saturation
+-        Points have successfully been 11-saturated (max q used = 127)
+-        Checking 13-saturation
+-        Points have successfully been 13-saturated (max q used = 151)
+-        Checking 17-saturation
+-        Points have successfully been 17-saturated (max q used = 139)
+-        Checking 19-saturation
+-        Points have successfully been 19-saturated (max q used = 179)
+-        done (index = 1).
++        saturating up to 20...Saturation index bound (for points of good reduction)  = 3
++        Reducing saturation bound from given value 20 to computed index bound 3
++        Checking saturation at [ 2 3 ]
++        Checking 2-saturation 
++        Points were proved 2-saturated (max q used = 11)
++        Checking 3-saturation 
++        Points were proved 3-saturated (max q used = 13)
++        done, index = 1.
+         P4 = [-1:3:1]    = -1*P1 + -1*P2 + -1*P3 (mod torsion)
+         P4 = [0:2:1]     = 2*P1 + 0*P2 + 1*P3 (mod torsion)
+         P4 = [2:13:8]    = -3*P1 + 1*P2 + -1*P3 (mod torsion)
+@@ -878,7 +818,7 @@ class mwrank_MordellWeil(SageObject):
+             sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
+             sage: EQ = mwrank_MordellWeil(E)
+             sage: EQ.__reduce__()
+-            (<class 'sage.libs.eclib.interface.mwrank_MordellWeil'>, (y^2+ y = x^3 - 7*x + 6, True, 1, 999))
++            (<class 'sage.libs.eclib.interface.mwrank_MordellWeil'>, (y^2 + y = x^3 - 7 x + 6, True, 1, 999))
+         """
+         return mwrank_MordellWeil, (self.__curve, self.__verbose, self.__pp, self.__maxr)
+ 
+@@ -902,12 +842,10 @@ class mwrank_MordellWeil(SageObject):
+         """
+         return "Subgroup of Mordell-Weil group: %s"%self.__mw
+ 
+-    def process(self, v, sat=0):
+-        """
+-        This function allows one to add points to a :class:`mwrank_MordellWeil` object.
++    def process(self, v, saturation_bound=0):
++        """Process points in the list ``v``.
+ 
+-        Process points in the list ``v``, with saturation at primes up to
+-        ``sat``.  If ``sat`` is zero (the default), do no saturation.
++        This function allows one to add points to a :class:`mwrank_MordellWeil` object.
+ 
+         INPUT:
+ 
+@@ -915,8 +853,9 @@ class mwrank_MordellWeil(SageObject):
+           list of triples of integers, which define points on the
+           curve.
+ 
+-        - ``sat`` (int, default 0) -- saturate at primes up to ``sat``, or at
+-          *all* primes if ``sat`` is zero.
++        - ``saturation_bound`` (int, default 0) -- saturate at primes up to
++          ``saturation_bound``, or at *all* primes if ``saturation_bound`` is -1; when ``saturation_bound``
++          is 0 (the default), do no saturation..
+ 
+         OUTPUT:
+ 
+@@ -939,11 +878,11 @@ class mwrank_MordellWeil(SageObject):
+             sage: EQ.points()
+             [[1, -1, 1], [-2, 3, 1], [-14, 25, 8]]
+ 
+-        Example to illustrate the saturation parameter ``sat``::
++        Example to illustrate the saturation parameter ``saturation_bound``::
+ 
+             sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
+             sage: EQ = mwrank_MordellWeil(E)
+-            sage: EQ.process([[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]], sat=20)
++            sage: EQ.process([[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]], saturation_bound=20)
+             P1 = [1547:-2967:343]         is generator number 1
+             ...
+             Gained index 5, new generators = [ [-2:3:1] [-14:25:8] [1:-1:1] ]
+@@ -956,7 +895,7 @@ class mwrank_MordellWeil(SageObject):
+ 
+             sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
+             sage: EQ = mwrank_MordellWeil(E)
+-            sage: EQ.process([[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]], sat=0)
++            sage: EQ.process([[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]], saturation_bound=0)
+             P1 = [1547:-2967:343]         is generator number 1
+             P2 = [2707496766203306:864581029138191:2969715140223272]      is generator number 2
+             P3 = [-13422227300:-49322830557:12167000000]          is generator number 3
+@@ -965,55 +904,92 @@ class mwrank_MordellWeil(SageObject):
+             sage: EQ.regulator()
+             375.42920288254555
+             sage: EQ.saturate(2)  # points were not 2-saturated
+-            saturating basis...Saturation index bound = 93
+-            WARNING: saturation at primes p > 2 will not be done;
+-            ...
++            saturating basis...Saturation index bound (for points of good reduction)  = 93
++            Only p-saturating for p up to given value 2.
++            The resulting points may not be p-saturated for p between this and the computed index bound 93
++            Checking saturation at [ 2 ]
++            Checking 2-saturation 
++            possible kernel vector = [1,0,0]
++            This point may be in 2E(Q): [1547:-2967:343]
++            ...and it is! 
++            Replacing old generator #1 with new generator [-2:3:1]
++            Reducing index bound from 93 to 46
++            Points have successfully been 2-saturated (max q used = 11)
++            Index gain = 2^1
++            done
+             Gained index 2
+-            New regulator =  93.857...
+-            (False, 2, '[ ]')
++            New regulator =  93.85730072
++            (True, 2, '[ ]')
+             sage: EQ.points()
+             [[-2, 3, 1], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]]
+             sage: EQ.regulator()
+             93.85730072063639
+             sage: EQ.saturate(3)  # points were not 3-saturated
+-            saturating basis...Saturation index bound = 46
+-            WARNING: saturation at primes p > 3 will not be done;
+-            ...
++            saturating basis...Saturation index bound (for points of good reduction)  = 46
++            Only p-saturating for p up to given value 3.
++            The resulting points may not be p-saturated for p between this and the computed index bound 46
++            Checking saturation at [ 2 3 ]
++            Checking 2-saturation 
++            Points were proved 2-saturated (max q used = 11)
++            Checking 3-saturation 
++            possible kernel vector = [0,1,0]
++            This point may be in 3E(Q): [2707496766203306:864581029138191:2969715140223272]
++            ...and it is! 
++            Replacing old generator #2 with new generator [-14:25:8]
++            Reducing index bound from 46 to 15
++            Points have successfully been 3-saturated (max q used = 13)
++            Index gain = 3^1
++            done
+             Gained index 3
+-            New regulator =  10.428...
+-            (False, 3, '[ ]')
++            New regulator =  10.42858897
++            (True, 3, '[ ]')
+             sage: EQ.points()
+             [[-2, 3, 1], [-14, 25, 8], [-13422227300, -49322830557, 12167000000]]
+             sage: EQ.regulator()
+             10.4285889689596
+             sage: EQ.saturate(5)  # points were not 5-saturated
+-            saturating basis...Saturation index bound = 15
+-            WARNING: saturation at primes p > 5 will not be done;
+-            ...
++            saturating basis...Saturation index bound (for points of good reduction)  = 15
++            Only p-saturating for p up to given value 5.
++            The resulting points may not be p-saturated for p between this and the computed index bound 15
++            Checking saturation at [ 2 3 5 ]
++            Checking 2-saturation 
++            Points were proved 2-saturated (max q used = 11)
++            Checking 3-saturation 
++            Points were proved 3-saturated (max q used = 13)
++            Checking 5-saturation 
++            possible kernel vector = [0,0,1]
++            This point may be in 5E(Q): [-13422227300:-49322830557:12167000000]
++            ...and it is! 
++            Replacing old generator #3 with new generator [1:-1:1]
++            Reducing index bound from 15 to 3
++            Points have successfully been 5-saturated (max q used = 71)
++            Index gain = 5^1
++            done
+             Gained index 5
+-            New regulator =  0.417...
+-            (False, 5, '[ ]')
++            New regulator =  0.4171435588
++            (True, 5, '[ ]')
+             sage: EQ.points()
+             [[-2, 3, 1], [-14, 25, 8], [1, -1, 1]]
+             sage: EQ.regulator()
+             0.417143558758384
+             sage: EQ.saturate()   # points are now saturated
+-            saturating basis...Saturation index bound = 3
++            saturating basis...Saturation index bound (for points of good reduction)  = 3
++            Tamagawa index primes are [ ]
+             Checking saturation at [ 2 3 ]
+-            Checking 2-saturation
++            Checking 2-saturation 
+             Points were proved 2-saturated (max q used = 11)
+-            Checking 3-saturation
++            Checking 3-saturation 
+             Points were proved 3-saturated (max q used = 13)
+             done
+             (True, 1, '[ ]')
+         """
+         if not isinstance(v, list):
+             raise TypeError("v (=%s) must be a list"%v)
+-        sat = int(sat)
++        saturation_bound = int(saturation_bound)
+         for P in v:
+-            if not isinstance(P, (list,tuple)) or len(P) != 3:
++            if not isinstance(P, (list, tuple)) or len(P) != 3:
+                 raise TypeError("v (=%s) must be a list of 3-tuples (or 3-element lists) of ints"%v)
+-            self.__mw.process(P, sat)
++            self.__mw.process(P, saturation_bound)
+ 
+     def regulator(self):
+         """
+@@ -1091,23 +1067,21 @@ class mwrank_MordellWeil(SageObject):
+         """
+         return self.__mw.rank()
+ 
+-    def saturate(self, max_prime=-1, odd_primes_only=False):
+-        r"""
+-        Saturate this subgroup of the Mordell-Weil group.
++    def saturate(self, max_prime=-1, min_prime=2):
++        r"""Saturate this subgroup of the Mordell-Weil group.
+ 
+         INPUT:
+ 
+-        - ``max_prime`` (int, default -1) -- saturation is performed for
+-          all primes up to ``max_prime``. If `-1` (the default), an
++        - ``max_prime`` (int, default -1) -- If `-1` (the default), an
+           upper bound is computed for the primes at which the subgroup
+-          may not be saturated, and this is used; however, if the
+-          computed bound is greater than a value set by the ``eclib``
+-          library (currently 97) then no saturation will be attempted
+-          at primes above this.
++          may not be saturated, and saturation is performed for all
++          primes up to this bound.  Otherwise, the bound used is the
++          minimum of ``max_prime`` and the computed bound.
+ 
+-        - ``odd_primes_only`` (bool, default ``False``) -- only do
+-          saturation at odd primes.  (If the points have been found
+-          via :meth:`two_descent` they should already be 2-saturated.)
++        - ``min_prime`` (int, default 2) -- only do saturation at
++          primes no less than this.  (For example, if the points have
++          been found via :meth:`two_descent` they should already be
++          2-saturated so a value of 3 is appropriate.)
+ 
+         OUTPUT:
+ 
+@@ -1115,40 +1089,35 @@ class mwrank_MordellWeil(SageObject):
+ 
+         - ``ok`` (bool) -- ``True`` if and only if the saturation was
+           provably successful at all primes attempted.  If the default
+-          was used for ``max_prime`` and no warning was output about
+-          the computed saturation bound being too high, then ``True``
+-          indicates that the subgroup is saturated at *all*
+-          primes.
++          was used for ``max_prime``, then ``True`` indicates that the
++          subgroup is saturated at *all* primes.
+ 
+         - ``index`` (int) -- the index of the group generated by the
+           original points in their saturation.
+ 
+         - ``unsatlist`` (list of ints) -- list of primes at which
+-          saturation could not be proved or achieved.  Increasing the
+-          precision should correct this, since it happens when
+-          a linear combination of the points appears to be a multiple
+-          of `p` but cannot be divided by `p`.  (Note that ``eclib``
+-          uses floating point methods based on elliptic logarithms to
+-          divide points.)
++          saturation could not be proved or achieved.
+ 
+         .. note::
+ 
+-           We emphasize that if this function returns ``True`` as the
+-           first return argument (``ok``), and if the default was used for the
+-           parameter ``max_prime``, then the points in the basis after
+-           calling this function are saturated at *all* primes,
+-           i.e., saturating at the primes up to ``max_prime`` are
+-           sufficient to saturate at all primes.  Note that the
+-           function might not have needed to saturate at all primes up
+-           to ``max_prime``.  It has worked out what prime you need to
+-           saturate up to, and that prime might be smaller than ``max_prime``.
++          In versions up to v20190909, ``eclib`` used floating point
++          methods based on elliptic logarithms to divide points, and
++          did not compute the precision necessary, which could casue
++          failures. Since v20210310, ``eclib`` uses exact method based
++          on division polynomials, which should mean that such
++          failures does not happen.
+ 
+         .. note::
+ 
+-           Currently (May 2010), this does not remember the result of
+-           calling :meth:`search()`.  So calling :meth:`search()` up
+-           to height 20 then calling :meth:`saturate()` results in
+-           another search up to height 18.
++           We emphasize that if this function returns ``True`` as the
++           first return argument (``ok``), and if the default was used
++           for the parameter ``max_prime``, then the points in the
++           basis after calling this function are saturated at *all*
++           primes, i.e., saturating at the primes up to ``max_prime``
++           are sufficient to saturate at all primes.  Note that the
++           function computes an upper bound for the index of
++           saturation, and does no work for primes greater than this
++           even if ``max_prime`` is larger.
+ 
+         EXAMPLES::
+ 
+@@ -1160,7 +1129,7 @@ class mwrank_MordellWeil(SageObject):
+         automatic saturation at this stage we set the parameter
+         ``sat`` to 0 (which is in fact the default)::
+ 
+-            sage: EQ.process([[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]], sat=0)
++            sage: EQ.process([[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]], saturation_bound=0)
+             P1 = [1547:-2967:343]         is generator number 1
+             P2 = [2707496766203306:864581029138191:2969715140223272]      is generator number 2
+             P3 = [-13422227300:-49322830557:12167000000]          is generator number 3
+@@ -1172,12 +1141,12 @@ class mwrank_MordellWeil(SageObject):
+         Now we saturate at `p=2`, and gain index 2::
+ 
+             sage: EQ.saturate(2)  # points were not 2-saturated
+-            saturating basis...Saturation index bound = 93
+-            WARNING: saturation at primes p > 2 will not be done;
++            saturating basis...Saturation index bound (for points of good reduction) = 93
++            Only p-saturating for p up to given value 2.
+             ...
+             Gained index 2
+             New regulator =  93.857...
+-            (False, 2, '[ ]')
++            (True, 2, '[ ]')
+             sage: EQ
+             Subgroup of Mordell-Weil group: [[-2:3:1], [2707496766203306:864581029138191:2969715140223272], [-13422227300:-49322830557:12167000000]]
+             sage: EQ.regulator()
+@@ -1186,12 +1155,12 @@ class mwrank_MordellWeil(SageObject):
+         Now we saturate at `p=3`, and gain index 3::
+ 
+             sage: EQ.saturate(3)  # points were not 3-saturated
+-            saturating basis...Saturation index bound = 46
+-            WARNING: saturation at primes p > 3 will not be done;
++            saturating basis...Saturation index bound (for points of good reduction) = 46
++            Only p-saturating for p up to given value 3.
+             ...
+             Gained index 3
+             New regulator =  10.428...
+-            (False, 3, '[ ]')
++            (True, 3, '[ ]')
+             sage: EQ
+             Subgroup of Mordell-Weil group: [[-2:3:1], [-14:25:8], [-13422227300:-49322830557:12167000000]]
+             sage: EQ.regulator()
+@@ -1200,12 +1169,12 @@ class mwrank_MordellWeil(SageObject):
+         Now we saturate at `p=5`, and gain index 5::
+ 
+             sage: EQ.saturate(5)  # points were not 5-saturated
+-            saturating basis...Saturation index bound = 15
+-            WARNING: saturation at primes p > 5 will not be done;
++            saturating basis...Saturation index bound (for points of good reduction) = 15
++            Only p-saturating for p up to given value 5.
+             ...
+             Gained index 5
+             New regulator =  0.417...
+-            (False, 5, '[ ]')
++            (True, 5, '[ ]')
+             sage: EQ
+             Subgroup of Mordell-Weil group: [[-2:3:1], [-14:25:8], [1:-1:1]]
+             sage: EQ.regulator()
+@@ -1215,7 +1184,8 @@ class mwrank_MordellWeil(SageObject):
+         the points are now provably saturated at all primes::
+ 
+             sage: EQ.saturate()   # points are now saturated
+-            saturating basis...Saturation index bound = 3
++            saturating basis...Saturation index bound (for points of good reduction) = 3
++            Tamagawa index primes are [ ]
+             Checking saturation at [ 2 3 ]
+             Checking 2-saturation
+             Points were proved 2-saturated (max q used = 11)
+@@ -1229,7 +1199,7 @@ class mwrank_MordellWeil(SageObject):
+ 
+             sage: E = mwrank_EllipticCurve([0,0,1,-7,6])
+             sage: EQ = mwrank_MordellWeil(E)
+-            sage: EQ.process([[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]], sat=5)
++            sage: EQ.process([[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]], saturation_bound=5)
+             P1 = [1547:-2967:343]         is generator number 1
+             ...
+             Gained index 5, new generators = [ [-2:3:1] [-14:25:8] [1:-1:1] ]
+@@ -1242,7 +1212,8 @@ class mwrank_MordellWeil(SageObject):
+         verify that full saturation has been done::
+ 
+             sage: EQ.saturate()
+-            saturating basis...Saturation index bound = 3
++            saturating basis...Saturation index bound (for points of good reduction) = 3
++            Tamagawa index primes are [ ]
+             Checking saturation at [ 2 3 ]
+             Checking 2-saturation
+             Points were proved 2-saturated (max q used = 11)
+@@ -1255,8 +1226,9 @@ class mwrank_MordellWeil(SageObject):
+         index of the points in their saturation is at most 3, then
+         proves saturation at 2 and at 3, by reducing the points modulo
+         all primes of good reduction up to 11, respectively 13.
++
+         """
+-        ok, index, unsat = self.__mw.saturate(int(max_prime), odd_primes_only)
++        ok, index, unsat = self.__mw.saturate(int(max_prime), int(min_prime))
+         return bool(ok), int(str(index)), unsat
+ 
+     def search(self, height_limit=18, verbose=False):
+@@ -1271,9 +1243,9 @@ class mwrank_MordellWeil(SageObject):
+ 
+         .. note::
+ 
+-          On 32-bit machines, this *must* be < 21.48 else
++          On 32-bit machines, this *must* be < 21.48 (`31\log(2)`) else
+           `\exp(h_{\text{lim}}) > 2^{31}` and overflows.  On 64-bit machines, it
+-          must be *at most* 43.668.  However, this bound is a logarithmic
++          must be *at most* 43.668  (`63\log(2)`) .  However, this bound is a logarithmic
+           bound and increasing it by just 1 increases the running time
+           by (roughly) `\exp(1.5)=4.5`, so searching up to even 20
+           takes a very long time.
+@@ -1320,8 +1292,10 @@ class mwrank_MordellWeil(SageObject):
+             Subgroup of Mordell-Weil group: [[4413270:10381877:27000]]
+         """
+         height_limit = float(height_limit)
+-        if height_limit >= 21.4:        # TODO: docstring says 21.48 (for 32-bit machines; what about 64-bit...?)
+-            raise ValueError("The height limit must be < 21.4.")
++        int_bits = sys.maxsize.bit_length()
++        max_height_limit = int_bits * 0.693147 # log(2.0) = 0.693147 approx
++        if height_limit >= max_height_limit:
++            raise ValueError("The height limit must be < {} = {}log(2) on a {}-bit machine.".format(max_height_limit, int_bits, int_bits+1))
+ 
+         moduli_option = 0  # Use Stoll's sieving program... see strategies in ratpoints-1.4.c
+ 
+@@ -1352,5 +1326,4 @@ class mwrank_MordellWeil(SageObject):
+             [[1, -1, 1], [-2, 3, 1], [-14, 25, 8]]
+ 
+         """
+-        L = eval(self.__mw.getbasis().replace(":",","))
+-        return [[Integer(x), Integer(y), Integer(z)] for (x,y,z) in L]
++        return self.__mw.getbasis()
+diff --git a/src/sage/libs/eclib/mwrank.pyx b/src/sage/libs/eclib/mwrank.pyx
+index b82831d..ce5090c 100644
+--- a/src/sage/libs/eclib/mwrank.pyx
++++ b/src/sage/libs/eclib/mwrank.pyx
+@@ -28,6 +28,7 @@ from cysignals.signals cimport sig_on, sig_off
+ from sage.cpython.string cimport char_to_str, str_to_bytes
+ from sage.cpython.string import FS_ENCODING
+ from sage.libs.eclib cimport bigint, Curvedata, mw, two_descent
++from sage.rings.all import Integer
+ 
+ cdef extern from "wrap.cpp":
+     ### misc functions ###
+@@ -55,8 +56,8 @@ cdef extern from "wrap.cpp":
+     char* mw_getbasis(mw* m)
+     double mw_regulator(mw* m)
+     int mw_rank(mw* m)
+-    int mw_saturate(mw* m, bigint* index, char** unsat,
+-                    long sat_bd, int odd_primes_only)
++    int mw_saturate(mw* m, long* index, char** unsat,
++                    long sat_bd, long sat_low_bd)
+     void mw_search(mw* m, char* h_lim, int moduli_option, int verb)
+ 
+     ### two_descent ###
+@@ -67,8 +68,7 @@ cdef extern from "wrap.cpp":
+     long two_descent_get_rank(two_descent* t)
+     long two_descent_get_rank_bound(two_descent* t)
+     long two_descent_get_selmer_rank(two_descent* t)
+-    void two_descent_saturate(two_descent* t, long sat_bd)
+-
++    void two_descent_saturate(two_descent* t, long sat_bd, long sat_low_bd)
+ 
+ cdef object string_sigoff(char* s):
+     sig_off()
+@@ -445,7 +445,6 @@ cdef class _Curvedata:   # cython class wrapping eclib's Curvedata class
+             -1269581104000000
+         """
+         sig_on()
+-        from sage.rings.all import Integer
+         return Integer(string_sigoff(Curvedata_getdiscr(self.x)))
+ 
+     def conductor(self):
+@@ -467,7 +466,6 @@ cdef class _Curvedata:   # cython class wrapping eclib's Curvedata class
+             126958110400
+         """
+         sig_on()
+-        from sage.rings.all import Integer
+         return Integer(string_sigoff(Curvedata_conductor(self.x)))
+ 
+     def isogeny_class(self, verbose=False):
+@@ -503,6 +501,36 @@ cdef class _Curvedata:   # cython class wrapping eclib's Curvedata class
+ 
+ ############# _mw #################
+ 
++def parse_point_list(s):
++    r"""
++    Parse a string representing a list of points.
++
++    INPUT:
++
++    - ``s`` (string) -- string representation of a list of points, for
++      example '[]', '[[1:2:3]]', or '[[1:2:3],[4:5:6]]'.
++
++    OUTPUT:
++
++    (list)  a list of triples of integers, for example [], [[1,2,3]], [[1,2,3],[4,5,6]].
++
++    EXAMPLES::
++
++        sage: from sage.libs.eclib.mwrank import parse_point_list
++        sage: parse_point_list('[]')
++        []
++        sage: parse_point_list('[[1:2:3]]')
++        [[1, 2, 3]]
++        sage: parse_point_list('[[1:2:3],[4:5:6]]')
++        [[1, 2, 3], [4, 5, 6]]
++
++    """
++    s = s.replace(":", ",").replace(" ", "")
++    if s == '[]':
++        return []
++    pts = s[2:-2].split('],[')
++    return [[Integer(x) for x in pt.split(",")] for pt in pts]
++
+ cdef class _mw:
+     """
+     Cython class wrapping eclib's mw class.
+@@ -561,72 +589,37 @@ cdef class _mw:
+             sage: EQ.search(1)
+             P1 = [0:1:0]         is torsion point, order 1
+             P1 = [-3:0:1]         is generator number 1
+-            ...
+-            P4 = [12:35:27]      = 1*P1 + -1*P2 + -1*P3 (mod torsion)
+-
+-        The previous command produces the following output::
+-
+-            P1 = [0:1:0]         is torsion point, order 1
+-            P1 = [-3:0:1]         is generator number 1
+-            saturating up to 20...Checking 2-saturation
+-            Points have successfully been 2-saturated (max q used = 7)
+-            Checking 3-saturation
+-            Points have successfully been 3-saturated (max q used = 7)
+-            Checking 5-saturation
+-            Points have successfully been 5-saturated (max q used = 23)
+-            Checking 7-saturation
+-            Points have successfully been 7-saturated (max q used = 41)
+-            Checking 11-saturation
+-            Points have successfully been 11-saturated (max q used = 17)
+-            Checking 13-saturation
+-            Points have successfully been 13-saturated (max q used = 43)
+-            Checking 17-saturation
+-            Points have successfully been 17-saturated (max q used = 31)
+-            Checking 19-saturation
+-            Points have successfully been 19-saturated (max q used = 37)
++            saturating up to 20...Saturation index bound (for points of good reduction)  = 3
++            Reducing saturation bound from given value 20 to computed index bound 3
++            Checking saturation at [ 2 3 ]
++            Checking 2-saturation 
++            Points were proved 2-saturated (max q used = 7)
++            Checking 3-saturation 
++            Points were proved 3-saturated (max q used = 7)
+             done
+             P2 = [-2:3:1]         is generator number 2
+-            saturating up to 20...Checking 2-saturation
++            saturating up to 20...Saturation index bound (for points of good reduction)  = 4
++            Reducing saturation bound from given value 20 to computed index bound 4
++            Checking saturation at [ 2 3 ]
++            Checking 2-saturation 
+             possible kernel vector = [1,1]
+             This point may be in 2E(Q): [14:-52:1]
+-            ...and it is!
++            ...and it is! 
+             Replacing old generator #1 with new generator [1:-1:1]
++            Reducing index bound from 4 to 2
+             Points have successfully been 2-saturated (max q used = 7)
+             Index gain = 2^1
+-            Checking 3-saturation
+-            Points have successfully been 3-saturated (max q used = 13)
+-            Checking 5-saturation
+-            Points have successfully been 5-saturated (max q used = 67)
+-            Checking 7-saturation
+-            Points have successfully been 7-saturated (max q used = 53)
+-            Checking 11-saturation
+-            Points have successfully been 11-saturated (max q used = 73)
+-            Checking 13-saturation
+-            Points have successfully been 13-saturated (max q used = 103)
+-            Checking 17-saturation
+-            Points have successfully been 17-saturated (max q used = 113)
+-            Checking 19-saturation
+-            Points have successfully been 19-saturated (max q used = 47)
+-            done (index = 2).
++            done, index = 2.
+             Gained index 2, new generators = [ [1:-1:1] [-2:3:1] ]
+             P3 = [-14:25:8]       is generator number 3
+-            saturating up to 20...Checking 2-saturation
+-            Points have successfully been 2-saturated (max q used = 11)
+-            Checking 3-saturation
+-            Points have successfully been 3-saturated (max q used = 13)
+-            Checking 5-saturation
+-            Points have successfully been 5-saturated (max q used = 71)
+-            Checking 7-saturation
+-            Points have successfully been 7-saturated (max q used = 101)
+-            Checking 11-saturation
+-            Points have successfully been 11-saturated (max q used = 127)
+-            Checking 13-saturation
+-            Points have successfully been 13-saturated (max q used = 151)
+-            Checking 17-saturation
+-            Points have successfully been 17-saturated (max q used = 139)
+-            Checking 19-saturation
+-            Points have successfully been 19-saturated (max q used = 179)
+-            done (index = 1).
++            saturating up to 20...Saturation index bound (for points of good reduction)  = 3
++            Reducing saturation bound from given value 20 to computed index bound 3
++            Checking saturation at [ 2 3 ]
++            Checking 2-saturation 
++            Points were proved 2-saturated (max q used = 11)
++            Checking 3-saturation 
++            Points were proved 3-saturated (max q used = 13)
++            done, index = 1.
+             P4 = [-1:3:1]        = -1*P1 + -1*P2 + -1*P3 (mod torsion)
+             P4 = [0:2:1]         = 2*P1 + 0*P2 + 1*P3 (mod torsion)
+             P4 = [2:13:8]        = -3*P1 + 1*P2 + -1*P3 (mod torsion)
+@@ -687,7 +680,7 @@ cdef class _mw:
+         sig_on()
+         return string_sigoff(mw_getbasis(self.x))
+ 
+-    def process(self, point, sat=0):
++    def process(self, point, saturation_bound=0):
+         """
+         Processes the given point, adding it to the mw group.
+ 
+@@ -697,10 +690,12 @@ cdef class _mw:
+           An ``ArithmeticError`` is raised if the point is not on the
+           curve.
+ 
+-        - ``sat`` (int, default 0) --saturate at primes up to ``sat``.
+-          No saturation is done if ``sat=0``.  (Note that it is more
+-          efficient to add several points at once and then saturate
+-          just once at the end).
++        - ``saturation_bound`` (int, default 0) --saturate at primes up to ``saturation_bound``.
++          No saturation is done if ``saturation_bound=0``.  If ``saturation_bound=-1`` then
++          saturation is done at all primes, by computing a bound on
++          the saturation index.  Note that it is more efficient to add
++          several points at once and then saturate just once at the
++          end.
+ 
+         .. NOTE::
+ 
+@@ -746,7 +741,7 @@ cdef class _mw:
+         cdef _bigint x,y,z
+         sig_on()
+         x,y,z = _bigint(point[0]), _bigint(point[1]), _bigint(point[2])
+-        r = mw_process(self.curve, self.x, x.x, y.x, z.x, sat)
++        r = mw_process(self.curve, self.x, x.x, y.x, z.x, saturation_bound)
+         sig_off()
+         if r != 0:
+             raise ArithmeticError("point (=%s) not on curve." % point)
+@@ -757,8 +752,8 @@ cdef class _mw:
+ 
+         OUTPUT:
+ 
+-        (string) String representation of the points in the basis of
+-        the mw group.
++        (list) list of integer triples giving the projective
++        coordinates of the points in the basis.
+ 
+         EXAMPLES::
+ 
+@@ -768,13 +763,13 @@ cdef class _mw:
+             sage: EQ = _mw(E)
+             sage: EQ.search(3)
+             sage: EQ.getbasis()
+-            '[[0:-1:1], [-1:1:1]]'
++            [[0, -1, 1], [-1, 1, 1]]
+             sage: EQ.rank()
+             2
+         """
+         sig_on()
+         s = string_sigoff(mw_getbasis(self.x))
+-        return s
++        return parse_point_list(s)
+ 
+     def regulator(self):
+         """
+@@ -797,7 +792,7 @@ cdef class _mw:
+             sage: EQ = _mw(E)
+             sage: EQ.search(3)
+             sage: EQ.getbasis()
+-            '[[0:-1:1], [-1:1:1]]'
++            [[0, -1, 1], [-1, 1, 1]]
+             sage: EQ.rank()
+             2
+             sage: EQ.regulator()
+@@ -824,39 +819,54 @@ cdef class _mw:
+             sage: EQ = _mw(E)
+             sage: EQ.search(3)
+             sage: EQ.getbasis()
+-            '[[0:-1:1], [-1:1:1]]'
++            [[0, -1, 1], [-1, 1, 1]]
+             sage: EQ.rank()
+             2
+         """
+         sig_on()
+         r = mw_rank(self.x)
+         sig_off()
+-        from sage.rings.all import Integer
+         return Integer(r)
+ 
+-    def saturate(self, int sat_bd=-1, int odd_primes_only=0):
++    def saturate(self, int sat_bd=-1, int sat_low_bd=2):
+         """
+         Saturates the current subgroup of the mw group.
+ 
+         INPUT:
+ 
+-        - ``sat_bnd`` (int, default -1) -- bound on primes at which to
+-          saturate.  If -1 (default), compute a bound for the primes
+-          which may not be saturated, and use that.
++        - ``sat_bnd`` (int, default -1) -- upper bound on primes at
++          which to saturate.  If -1 (default), compute a bound for the
++          primes which may not be saturated, and use that.  Otherwise,
++          the bound used is the minumum of the value of ``sat_bnd``
++          and the computed bound.
+ 
+-        - ``odd_primes_only`` (bool, default ``False``) -- only do
+-          saturation at odd primes.  (If the points have been found
+-          via 2-descent they should already be 2-saturated.)
++        - ``sat_low_bd`` (int, default 2) -- only do saturation at
++          prime not less than this.  For exampe, if the points have
++          been found via 2-descent they should already be 2-saturated,
++          and ``sat_low_bd=3`` is appropriate.
+ 
+         OUTPUT:
+ 
+         (tuple) (success flag, index, list) The success flag will be 1
+         unless something failed (usually an indication that the points
+-        were not saturated but the precision is not high enough to
+-        divide out successfully).  The index is the index of the mw
+-        group before saturation in the mw group after.  The list is a
+-        string representation of the primes at which saturation was
+-        not proved or achieved.
++        were not saturated but eclib was not able to divide out
++        successfully).  The index is the index of the mw group before
++        saturation in the mw group after.  The list is a string
++        representation of the primes at which saturation was not
++        proved or achieved.
++
++        .. NOTE::
++
++        ``eclib`` will compute a bound on the saturation index.  If
++        the computed saturation bound is very large and ``sat_bnd`` is
++        -1, ``eclib`` may output a warning, but will still attempt to
++        saturate up to the computed bound.  If a positive value of
++        ``sat_bnd`` is given which is greater than the computed bound,
++        `p`-saturation will only be carried out for primes up to the
++        compated bound.  Setting ``sat_low_bnd`` to a value greater
++        than 2 allows for saturation to be done incrementally, or for
++        exactly one prime `p` by setting both ``sat_bd`` and
++        ``sat_low_bd`` to `p`.
+ 
+         EXAMPLES::
+ 
+@@ -872,34 +882,23 @@ cdef class _mw:
+             sage: EQ
+             [[-1:1:1]]
+ 
+-        If we set the saturation bound at 2, then saturation will fail::
++        If we set the saturation bound at 2, then saturation will not
++        enlarge the basis, but the success flag is still 1 (True)
++        since we did not ask to check 3-saturation::
+ 
+             sage: EQ = _mw(E)
+             sage: EQ.process([494, -5720, 6859]) # 3 times another point
+             sage: EQ.saturate(sat_bd=2)
+-            Saturation index bound = 10
+-            WARNING: saturation at primes p > 2 will not be done;
+-            points may be unsaturated at primes between 2 and index bound
+-            Failed to saturate MW basis at primes [ ]
+-            (0, 1, '[ ]')
++            (1, 1, '[ ]')
+             sage: EQ
+             [[494:-5720:6859]]
+ 
+-        The following output is also seen in the preceding example::
+-
+-            Saturation index bound = 10
+-            WARNING: saturation at primes p > 2 will not be done;
+-            points may be unsaturated at primes between 2 and index bound
+-            Failed to saturate MW basis at primes [ ]
+-
+-
+         """
+-        cdef _bigint index
++        cdef long index
+         cdef char* s
+         cdef int ok
+         sig_on()
+-        index = _bigint()
+-        ok = mw_saturate(self.x, index.x, &s, sat_bd, odd_primes_only)
++        ok = mw_saturate(self.x, &index, &s, sat_bd, sat_low_bd)
+         unsat = string_sigoff(s)
+         return ok, index, unsat
+ 
+@@ -1094,7 +1093,6 @@ cdef class _two_descent:
+         sig_on()
+         r = two_descent_get_rank(self.x)
+         sig_off()
+-        from sage.rings.all import Integer
+         return Integer(r)
+ 
+     def getrankbound(self):
+@@ -1128,7 +1126,6 @@ cdef class _two_descent:
+         sig_on()
+         r = two_descent_get_rank_bound(self.x)
+         sig_off()
+-        from sage.rings.all import Integer
+         return Integer(r)
+ 
+     def getselmer(self):
+@@ -1161,7 +1158,6 @@ cdef class _two_descent:
+         sig_on()
+         r = two_descent_get_selmer_rank(self.x)
+         sig_off()
+-        from sage.rings.all import Integer
+         return Integer(r)
+ 
+     def ok(self):
+@@ -1222,10 +1218,21 @@ cdef class _two_descent:
+         """
+         return two_descent_get_certain(self.x)
+ 
+-    def saturate(self, saturation_bound=0):
++    def saturate(self, saturation_bound=0, lower=3):
+         """
+         Carries out saturation of the points found by a 2-descent.
+ 
++        INPUT:
++
++        - ``saturation_bound`` (int) -- an upper bound on the primes
++          `p` at which `p`-saturation will be carried out, or -1, in
++          which case ``eclib`` will compute an upper bound on the
++          saturation index.
++
++        - ``lower`` (int, default 3) -- do no `p`-saturation for `p`
++          less than this.  The default is 3 since the points found
++          during 2-descent will be 2-saturated.
++
+         OUTPUT:
+ 
+         None.
+@@ -1257,7 +1264,7 @@ cdef class _two_descent:
+             '[[1:-1:1], [-2:3:1], [-14:25:8]]'
+         """
+         sig_on()
+-        two_descent_saturate(self.x, saturation_bound)
++        two_descent_saturate(self.x, saturation_bound, 3)
+         sig_off()
+ 
+     def getbasis(self):
+diff --git a/src/sage/libs/eclib/newforms.pyx b/src/sage/libs/eclib/newforms.pyx
+index 8e655f6..9039cc6 100644
+--- a/src/sage/libs/eclib/newforms.pyx
++++ b/src/sage/libs/eclib/newforms.pyx
+@@ -184,6 +184,7 @@ cdef class ECModularSymbol:
+         cdef Curvedata CD
+         cdef CurveRed CR
+         cdef int n
++        cdef int nap
+ 
+         if E.base_field() is not QQ:
+             raise TypeError("the elliptic curve must have coefficients in the rational numbers")
+@@ -211,7 +212,8 @@ cdef class ECModularSymbol:
+         self.sign = sign
+ 
+         self.nfs = new newforms(n, 0)
+-        self.nfs.createfromcurve(sign,CR)
++        nap = 500 # eclib will increase this to 100*sqrt(N) if necessary
++        self.nfs.createfromcurve(sign, CR, nap)
+         sig_off()
+ 
+     def __dealloc__(self):
+@@ -245,9 +247,7 @@ cdef class ECModularSymbol:
+         - ``sign`` (int) - either +1, -1 or 0.  If the sign of the
+           space is +1, only sign +1 is allowed.  Default: self.sign, or +1 when self.sign=0.
+ 
+-
+-
+-           - ``base_at_infinity`` (bool) - if True, evaluates
++        - ``base_at_infinity`` (bool) - if True, evaluates
+           {oo,r}. otherwise (default) evaluates {0,r}.
+ 
+         OUTPUT:
+diff --git a/src/sage/libs/eclib/t b/src/sage/libs/eclib/t
+new file mode 100644
+index 00000000..e69de29
+--- /dev/null
++++ b/src/sage/libs/eclib/t
+diff --git a/src/sage/libs/eclib/wrap.cpp b/src/sage/libs/eclib/wrap.cpp
+index 58c18ab..28e6da8 100644
+--- a/src/sage/libs/eclib/wrap.cpp
++++ b/src/sage/libs/eclib/wrap.cpp
+@@ -178,11 +178,11 @@ int mw_rank(struct mw* m)
+ }
+ 
+ /* Returns index and unsat long array, which user must deallocate */
+-int mw_saturate(struct mw* m, bigint* index, char** unsat,
+-                       long sat_bd, int odd_primes_only)
++int mw_saturate(struct mw* m, long* index, char** unsat,
++                       long sat_bd, long sat_low_bd)
+ {
+   vector<long> v;
+-  int s = m->saturate(*index, v, sat_bd, odd_primes_only);
++  int s = m->saturate(*index, v, sat_bd, sat_low_bd);
+   ostringstream instore;
+   instore << v;
+   *unsat  = stringstream_to_char(instore);
+@@ -236,9 +236,9 @@ long two_descent_get_certain(const two_descent* t)
+   return t->getcertain();
+ }
+ 
+-void two_descent_saturate(struct two_descent* t, long sat_bd)
++void two_descent_saturate(struct two_descent* t, long sat_bd, long sat_low_bd)
+ {
+-  t->saturate(sat_bd);
++  t->saturate(sat_bd, sat_low_bd);
+ }
+ 
+ double two_descent_regulator(struct two_descent* t)
+diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py
+index 2953e80..35e5759 100644
+--- a/src/sage/schemes/elliptic_curves/ell_rational_field.py
++++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py
+@@ -779,7 +779,7 @@ class EllipticCurve_rational_field(EllipticCurve_number_field):
+             sage: E = EllipticCurve('11a1')
+             sage: EE = E.mwrank_curve()
+             sage: EE
+-            y^2+ y = x^3 - x^2 - 10*x - 20
++            y^2 + y = x^3 - x^2 - 10 x - 20
+             sage: type(EE)
+             <class 'sage.libs.eclib.interface.mwrank_EllipticCurve'>
+             sage: EE.isogeny_class()
+@@ -2520,7 +2520,7 @@ class EllipticCurve_rational_field(EllipticCurve_number_field):
+         assert reg.parent() is R
+         return reg
+ 
+-    def saturation(self, points, verbose=False, max_prime=0, odd_primes_only=False):
++    def saturation(self, points, verbose=False, max_prime=-1, min_prime=2):
+         """
+         Given a list of rational points on E, compute the saturation in
+         E(Q) of the subgroup they generate.
+@@ -2533,17 +2533,24 @@ class EllipticCurve_rational_field(EllipticCurve_number_field):
+         -  ``verbose (bool)`` - (default: ``False``), if ``True``, give
+            verbose output
+ 
+-        -  ``max_prime (int)`` - (default: 0), saturation is
+-           performed for all primes up to max_prime. If max_prime==0,
+-           perform saturation at *all* primes, i.e., compute the true
+-           saturation.
++        - ``max_prime`` (int, default -1) -- If `-1` (the default), an
++          upper bound is computed for the primes at which the subgroup
++          may not be saturated, and saturation is performed for all
++          primes up to this bound.  Otherwise, the bound used is the
++          minimum of ``max_prime`` and the computed bound.
+ 
+-        -  ``odd_primes_only (bool)`` - only do saturation at
+-           odd primes
++        - ``min_prime (int)`` - (default: 2), only do `p`-saturation
++            at primes `p` greater than or equal to this.
+ 
++        .. note::
+ 
+-        OUTPUT:
++           To saturate at a single prime `p`, set ``max_prime`` and
++           ``min_prime`` both to `p`.  One situation where this is
++           useful is after mapping saturated points from another
++           elliptic curve by a `p`-isogeny, since the images may not
++           be `p`-saturated but with be saturated at all other primes.
+ 
++        OUTPUT:
+ 
+         -  ``saturation (list)`` - points that form a basis for
+            the saturation
+@@ -2554,12 +2561,32 @@ class EllipticCurve_rational_field(EllipticCurve_number_field):
+         -  ``regulator (real with default precision)`` -
+            regulator of saturated points.
+ 
++        ALGORITHM: Uses Cremona's ``eclib`` package, which computes a
++        bound on the saturation index.  To `p`-saturate, or prove
++        `p`-saturation, we consider the reductions of the points
++        modulo primes `q` of good reduction such that `E(\FF_q)` has
++        order divisible by `p`.
++
++        .. note::
++
++           In versons of ``eclib`` up to ``v20190909``, division of
++           points in ``eclib`` was done using floating point methods,
++           without automatic handling of precision, so that
++           `p`-saturation sometimes failed unless
++           ``mwrank_set_precision()`` was called in advance with a
++           suitably high bit precision.  Since version ``v20210310``
++           of ``eclib``, division is done using exact methods based on
++           division polynomials, and `p`-saturation cannot fail in
++           this way.
++
++        .. note::
++
++           The computed index of saturation may be large, in which
++           case saturation may take a long time.  For example, the
++           rank 4 curve ``EllipticCurve([0,1,1,-9872,374262])`` has a
++           saturation index bound of 86682 and takes around 15 minutes
++           to prove saturation.
+ 
+-        ALGORITHM: Uses Cremona's ``mwrank`` package. With ``max_prime=0``,
+-        we call ``mwrank`` with successively larger prime bounds until the full
+-        saturation is provably found. The results of saturation at the
+-        previous primes is stored in each case, so this should be
+-        reasonably fast.
+ 
+         EXAMPLES::
+ 
+@@ -2572,7 +2599,9 @@ class EllipticCurve_rational_field(EllipticCurve_number_field):
+ 
+         TESTS:
+ 
+-        See :trac:`10590`.  This example would loop forever at default precision::
++        See :trac:`10590`.  With ``eclib`` versions up to
++        ``v20190909``, this example would loop forever at default
++        precision.  Since version ``v20210310`` it runs fine::
+ 
+             sage: E = EllipticCurve([1, 0, 1, -977842, -372252745])
+             sage: P = E([-192128125858676194585718821667542660822323528626273/336995568430319276695106602174283479617040716649, 70208213492933395764907328787228427430477177498927549075405076353624188436/195630373799784831667835900062564586429333568841391304129067339731164107, 1])
+@@ -2580,7 +2609,7 @@ class EllipticCurve_rational_field(EllipticCurve_number_field):
+             113.302910926080
+             sage: E.saturation([P])
+             ([(-192128125858676194585718821667542660822323528626273/336995568430319276695106602174283479617040716649 : 70208213492933395764907328787228427430477177498927549075405076353624188436/195630373799784831667835900062564586429333568841391304129067339731164107 : 1)], 1, 113.302910926080)
+-            sage: (Q,), ind, reg = E.saturation([2*P])  # needs higher precision, handled by eclib
++            sage: (Q,), ind, reg = E.saturation([2*P])
+             sage: 2*Q == 2*P
+             True
+             sage: ind
+@@ -2629,34 +2658,16 @@ class EllipticCurve_rational_field(EllipticCurve_number_field):
+         c = Emin.mwrank_curve()
+         from sage.libs.eclib.all import mwrank_MordellWeil
+         mw = mwrank_MordellWeil(c, verbose)
+-        mw.process(v)
+-        repeat_until_saturated = False
+-        if max_prime == 0:
+-            repeat_until_saturated = True
+-            max_prime = 9973
+-        from sage.libs.all import mwrank_get_precision, mwrank_set_precision
+-        prec0 = mwrank_get_precision()
+-        prec = 100
+-        if prec0<prec:
+-            mwrank_set_precision(prec)
+-        else:
+-            prec = prec0
+-        while True:
+-            ok, index, unsat = mw.saturate(max_prime=max_prime, odd_primes_only = odd_primes_only)
+-            reg = mw.regulator()
+-            if ok or not repeat_until_saturated: break
+-            max_prime = arith.next_prime(max_prime + 1000)
+-            prec += 50
+-            mwrank_set_precision(prec)
+-        if prec!=prec0: mwrank_set_precision(prec0)
+-        sat = mw.points()
+-        sat = [Emin(P) for P in sat]
++        mw.process(v) # by default, this does no saturation yet
++        ok, index, unsat = mw.saturate(max_prime=max_prime, min_prime = min_prime)
++        if not ok:
++            print("Failed to saturate failed at the primes {}".format(unsat))
++        sat = [Emin(P) for P in mw.points()]
+         if not minimal:
+             phi_inv = ~phi
+             sat = [phi_inv(P) for P in sat]
+         reg = self.regulator_of_points(sat)
+-        return sat, index, R(reg)
+-
++        return sat, index, reg
+ 
+     def CPS_height_bound(self):
+         r"""



More information about the arch-commits mailing list