diff options
Diffstat (limited to 'sagemath-eclib-20210310.patch')
-rw-r--r-- | sagemath-eclib-20210310.patch | 1406 |
1 files changed, 0 insertions, 1406 deletions
diff --git a/sagemath-eclib-20210310.patch b/sagemath-eclib-20210310.patch deleted file mode 100644 index bea233239119..000000000000 --- a/sagemath-eclib-20210310.patch +++ /dev/null @@ -1,1406 +0,0 @@ -diff --git a/src/sage/libs/eclib/__init__.pxd b/src/sage/libs/eclib/__init__.pxd -index 3f99f99..d44d4fb 100644 ---- a/src/sage/libs/eclib/__init__.pxd -+++ b/src/sage/libs/eclib/__init__.pxd -@@ -12,9 +12,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 -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 b50b606..96263cd 100644 ---- a/src/sage/libs/eclib/newforms.pyx -+++ b/src/sage/libs/eclib/newforms.pyx -@@ -140,6 +140,7 @@ cdef class ECModularSymbol: - - - ``nap`` - (int, default 1000): the number of ap of E to use - in determining the normalisation of the modular symbols. -+ Note that eclib will increase this to 100*sqrt(N) if necessary. - - EXAMPLES:: - -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_modular_symbols.py b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py -index a32f64e..30a61e1 100644 ---- a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py -+++ b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py -@@ -298,19 +298,27 @@ class ModularSymbolECLIB(ModularSymbol): - sage: m(0) - 1/5 - -- If ``nap`` is too small, the normalization in eclib may be incorrect. See :trac:`31317`:: -+ If ``nap`` is too small, the normalization in eclib used to be -+ incorrect (see :trac:`31317`), but since ``eclib`` version -+ v20210310 the value of ``nap`` is increased automatically by -+ ``eclib``:: - - sage: from sage.schemes.elliptic_curves.ell_modular_symbols import ModularSymbolECLIB - sage: E = EllipticCurve('1590g1') - sage: m = ModularSymbolECLIB(E, sign=+1, nap=300) - sage: [m(a/5) for a in [1..4]] -- [1001/153, -1001/153, -1001/153, 1001/153] -+ [13/2, -13/2, -13/2, 13/2] - -- Those values are incorrect. The correct values are:: -+ These values are correct, and increasing ``nap`` has no -+ effect. The correct values may verified by the numerical -+ implementation:: - - sage: m = ModularSymbolECLIB(E, sign=+1, nap=400) - sage: [m(a/5) for a in [1..4]] - [13/2, -13/2, -13/2, 13/2] -+ sage: m = E.modular_symbol(implementation='num') -+ sage: [m(a/5) for a in [1..4]] -+ [13/2, -13/2, -13/2, 13/2] - - """ - from sage.libs.eclib.newforms import ECModularSymbol -diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py -index a792afc..5a56389 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() -@@ -1283,22 +1283,21 @@ class EllipticCurve_rational_field(EllipticCurve_number_field): - sage: [Mminus(1/i) for i in [1..11]] - [0, 0, 1/2, 1/2, 0, 0, -1/2, -1/2, 0, 0, 0] - -- With the default 'eclib' implementation, if ``nap`` is too -- small, the normalization may be computed incorrectly. See -- :trac:`31317`:: -+ With older version of eclib, in the default 'eclib' -+ implementation, if ``nap`` is too small, the normalization may -+ be computed incorrectly (see :trac:`31317`). This was fixed -+ in eclib version v20210310, since now eclib increase ``nap`` -+ automatically. The following used to give incorrect results. -+ See :trac:`31443`:: - - sage: E = EllipticCurve('1590g1') - sage: m = E.modular_symbol(nap=300) - sage: [m(a/5) for a in [1..4]] -- [1001/153, -1001/153, -1001/153, 1001/153] -+ [13/2, -13/2, -13/2, 13/2] - -- Those values are incorrect. The correct values may be -- obtained by increasing ``nap``, as verified by the numerical -+ These values are correct, as verified by the numerical - implementation:: - -- sage: m = E.modular_symbol(nap=400) -- sage: [m(a/5) for a in [1..4]] -- [13/2, -13/2, -13/2, 13/2] - sage: m = E.modular_symbol(implementation='num') - sage: [m(a/5) for a in [1..4]] - [13/2, -13/2, -13/2, 13/2] -@@ -2525,7 +2524,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. -@@ -2538,17 +2537,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 -@@ -2559,12 +2565,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:: - -@@ -2577,7 +2603,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]) -@@ -2585,7 +2613,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 -@@ -2634,36 +2662,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""" |