Sage interface to Cremona’s eclib
library (also known as mwrank
)#
This is the Sage interface to John Cremona’s eclib
C++ library for
arithmetic on elliptic curves. The classes defined in this module
give Sage interpreter-level access to some of the functionality of
eclib
. For most purposes, it is not necessary to directly use these
classes. Instead, one can create an
EllipticCurve
and call methods that are implemented using this module.
Note
This interface is a direct library-level interface to eclib
,
including the 2-descent program mwrank
.
- class sage.libs.eclib.interface.mwrank_EllipticCurve(ainvs, verbose=False)[source]#
Bases:
SageObject
The
mwrank_EllipticCurve
class represents an elliptic curve using theCurvedata
class fromeclib
, called here an ‘mwrank elliptic curve’.Create the mwrank elliptic curve with invariants
ainvs
, which is a list of 5 or less integers \(a_1\), \(a_2\), \(a_3\), \(a_4\), and \(a_5\).If strictly less than 5 invariants are given, then the first ones are set to 0, so, e.g.,
[3,4]
means \(a_1=a_2=a_3=0\) and \(a_4=3\), \(a_5=4\).INPUT:
ainvs
(list or tuple) – a list of 5 or less integers, the coefficients of a nonsingular Weierstrass equation.verbose
(bool, defaultFalse
) – verbosity flag. IfTrue
, then all Selmer group computations will be verbose.
EXAMPLES:
We create the elliptic curve \(y^2 + y = x^3 + x^2 - 2x\):
sage: e = mwrank_EllipticCurve([0, 1, 1, -2, 0]) sage: e.ainvs() [0, 1, 1, -2, 0]
>>> from sage.all import * >>> e = mwrank_EllipticCurve([Integer(0), Integer(1), Integer(1), -Integer(2), Integer(0)]) >>> e.ainvs() [0, 1, 1, -2, 0]
This example illustrates that omitted \(a\)-invariants default to \(0\):
sage: e = mwrank_EllipticCurve([3, -4]) sage: e y^2 = x^3 + 3 x - 4 sage: e.ainvs() [0, 0, 0, 3, -4]
>>> from sage.all import * >>> e = mwrank_EllipticCurve([Integer(3), -Integer(4)]) >>> e y^2 = x^3 + 3 x - 4 >>> e.ainvs() [0, 0, 0, 3, -4]
The entries of the input list are coerced to
int
. If this is impossible, then an error is raised:sage: e = mwrank_EllipticCurve([3, -4.8]); e Traceback (most recent call last): ... TypeError: ainvs must be a list or tuple of integers.
>>> from sage.all import * >>> e = mwrank_EllipticCurve([Integer(3), -RealNumber('4.8')]); e Traceback (most recent call last): ... TypeError: ainvs must be a list or tuple of integers.
When you enter a singular model you get an exception:
sage: e = mwrank_EllipticCurve([0, 0]) Traceback (most recent call last): ... ArithmeticError: Invariants (= 0,0,0,0,0) do not describe an elliptic curve.
>>> from sage.all import * >>> e = mwrank_EllipticCurve([Integer(0), Integer(0)]) Traceback (most recent call last): ... ArithmeticError: Invariants (= 0,0,0,0,0) do not describe an elliptic curve.
- CPS_height_bound()[source]#
Return the Cremona-Prickett-Siksek height bound. This is a floating point number \(B\) such that if \(P\) is a point on the curve, then the naive logarithmic height \(h(P)\) is less than \(B+\hat{h}(P)\), where \(\hat{h}(P)\) is the canonical height of \(P\).
Warning
We assume the model is minimal!
EXAMPLES:
sage: E = mwrank_EllipticCurve([0, 0, 0, -1002231243161, 0]) sage: E.CPS_height_bound() 14.163198527061496 sage: E = mwrank_EllipticCurve([0,0,1,-7,6]) sage: E.CPS_height_bound() 0.0
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), Integer(0), Integer(0), -Integer(1002231243161), Integer(0)]) >>> E.CPS_height_bound() 14.163198527061496 >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(7),Integer(6)]) >>> E.CPS_height_bound() 0.0
- ainvs()[source]#
Returns the \(a\)-invariants of this mwrank elliptic curve.
EXAMPLES:
sage: E = mwrank_EllipticCurve([0,0,1,-1,0]) sage: E.ainvs() [0, 0, 1, -1, 0]
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(1),Integer(0)]) >>> E.ainvs() [0, 0, 1, -1, 0]
- certain()[source]#
Returns
True
if the lasttwo_descent()
call provably correctly computed the rank. Iftwo_descent()
hasn’t been called, then it is first called bycertain()
using the default parameters.The result is
True
if and only if the results of the methodsrank()
andrank_bound()
are equal.EXAMPLES:
A 2-descent does not determine \(E(\QQ)\) with certainty for the curve \(y^2 + y = x^3 - x^2 - 120x - 2183\):
sage: E = mwrank_EllipticCurve([0, -1, 1, -120, -2183]) sage: E.two_descent(False) ... sage: E.certain() False sage: E.rank() 0
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), -Integer(1), Integer(1), -Integer(120), -Integer(2183)]) >>> E.two_descent(False) ... >>> E.certain() False >>> E.rank() 0
The previous value is only a lower bound; the upper bound is greater:
sage: E.rank_bound() 2
>>> from sage.all import * >>> E.rank_bound() 2
In fact the rank of \(E\) is actually 0 (as one could see by computing the \(L\)-function), but Sha has order 4 and the 2-torsion is trivial, so mwrank cannot conclusively determine the rank in this case.
- conductor()[source]#
Return the conductor of this curve, computed using Cremona’s implementation of Tate’s algorithm.
Note
This is independent of PARI’s.
EXAMPLES:
sage: E = mwrank_EllipticCurve([1, 1, 0, -6958, -224588]) sage: E.conductor() 2310
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(1), Integer(1), Integer(0), -Integer(6958), -Integer(224588)]) >>> E.conductor() 2310
- gens()[source]#
Return a list of the generators for the Mordell-Weil group.
EXAMPLES:
sage: E = mwrank_EllipticCurve([0, 0, 1, -1, 0]) sage: E.gens() [[0, -1, 1]]
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), Integer(0), Integer(1), -Integer(1), Integer(0)]) >>> E.gens() [[0, -1, 1]]
- isogeny_class(verbose=False)[source]#
Returns the isogeny class of this mwrank elliptic curve.
EXAMPLES:
sage: E = mwrank_EllipticCurve([0,-1,1,0,0]) sage: E.isogeny_class() ([[0, -1, 1, 0, 0], [0, -1, 1, -10, -20], [0, -1, 1, -7820, -263580]], [[0, 5, 0], [5, 0, 5], [0, 5, 0]])
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0),-Integer(1),Integer(1),Integer(0),Integer(0)]) >>> E.isogeny_class() ([[0, -1, 1, 0, 0], [0, -1, 1, -10, -20], [0, -1, 1, -7820, -263580]], [[0, 5, 0], [5, 0, 5], [0, 5, 0]])
- rank()[source]#
Returns the rank of this curve, computed using
two_descent()
.In general this may only be a lower bound for the rank; an upper bound may be obtained using the function
rank_bound()
. To test whether the value has been proved to be correct, use the methodcertain()
.EXAMPLES:
sage: E = mwrank_EllipticCurve([0, -1, 0, -900, -10098]) sage: E.rank() 0 sage: E.certain() True
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), -Integer(1), Integer(0), -Integer(900), -Integer(10098)]) >>> E.rank() 0 >>> E.certain() True
sage: E = mwrank_EllipticCurve([0, -1, 1, -929, -10595]) sage: E.rank() 0 sage: E.certain() False
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), -Integer(1), Integer(1), -Integer(929), -Integer(10595)]) >>> E.rank() 0 >>> E.certain() False
- rank_bound()[source]#
Returns an upper bound for the rank of this curve, computed using
two_descent()
.If the curve has no 2-torsion, this is equal to the 2-Selmer rank. If the curve has 2-torsion, the upper bound may be smaller than the bound obtained from the 2-Selmer rank minus the 2-rank of the torsion, since more information is gained from the 2-isogenous curve or curves.
EXAMPLES:
The following is the curve 960D1, which has rank 0, but Sha of order 4:
sage: E = mwrank_EllipticCurve([0, -1, 0, -900, -10098]) sage: E.rank_bound() 0 sage: E.rank() 0
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), -Integer(1), Integer(0), -Integer(900), -Integer(10098)]) >>> E.rank_bound() 0 >>> E.rank() 0
In this case the rank was computed using a second descent, which is able to determine (by considering a 2-isogenous curve) that Sha is nontrivial. If we deliberately stop the second descent, the rank bound is larger:
sage: E = mwrank_EllipticCurve([0, -1, 0, -900, -10098]) sage: E.two_descent(second_descent = False, verbose=False) sage: E.rank_bound() 2
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), -Integer(1), Integer(0), -Integer(900), -Integer(10098)]) >>> E.two_descent(second_descent = False, verbose=False) >>> E.rank_bound() 2
In contrast, for the curve 571A, also with rank 0 and Sha of order 4, we only obtain an upper bound of 2:
sage: E = mwrank_EllipticCurve([0, -1, 1, -929, -10595]) sage: E.rank_bound() 2
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), -Integer(1), Integer(1), -Integer(929), -Integer(10595)]) >>> E.rank_bound() 2
In this case the value returned by
rank()
is only a lower bound in general (though this is correct):sage: E.rank() 0 sage: E.certain() False
>>> from sage.all import * >>> E.rank() 0 >>> E.certain() False
- regulator()[source]#
Return the regulator of the saturated Mordell-Weil group.
EXAMPLES:
sage: E = mwrank_EllipticCurve([0, 0, 1, -1, 0]) sage: E.regulator() 0.05111140823996884
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), Integer(0), Integer(1), -Integer(1), Integer(0)]) >>> E.regulator() 0.05111140823996884
- saturate(bound=-1, lower=2)[source]#
Compute the saturation of the Mordell-Weil group.
INPUT:
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 ofbound
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, further saturation often has no effect:
sage: E = mwrank_EllipticCurve([0, 0, 0, -1002231243161, 0]) sage: E.gens() [[-1001107, -4004428, 1]] sage: E.saturate() sage: E.gens() [[-1001107, -4004428, 1]]
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), Integer(0), Integer(0), -Integer(1002231243161), Integer(0)]) >>> E.gens() [[-1001107, -4004428, 1]] >>> E.saturate() >>> E.gens() [[-1001107, -4004428, 1]]
Check that Issue #18031 is fixed:
sage: E = EllipticCurve([0,-1,1,-266,968]) sage: Q1 = E([-1995,3674,125]) sage: Q2 = E([157,1950,1]) sage: E.saturation([Q1,Q2]) ([(1 : -27 : 1), (157 : 1950 : 1)], 3, 0.801588644684981)
>>> from sage.all import * >>> E = EllipticCurve([Integer(0),-Integer(1),Integer(1),-Integer(266),Integer(968)]) >>> Q1 = E([-Integer(1995),Integer(3674),Integer(125)]) >>> Q2 = E([Integer(157),Integer(1950),Integer(1)]) >>> E.saturation([Q1,Q2]) ([(1 : -27 : 1), (157 : 1950 : 1)], 3, 0.801588644684981)
- selmer_rank()[source]#
Returns the rank of the 2-Selmer group of the curve.
EXAMPLES:
The following is the curve 960D1, which has rank 0, but Sha of order 4. The 2-torsion has rank 2, and the Selmer rank is 3:
sage: E = mwrank_EllipticCurve([0, -1, 0, -900, -10098]) sage: E.selmer_rank() 3
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), -Integer(1), Integer(0), -Integer(900), -Integer(10098)]) >>> E.selmer_rank() 3
Nevertheless, we can obtain a tight upper bound on the rank since a second descent is performed which establishes the 2-rank of Sha:
sage: E.rank_bound() 0
>>> from sage.all import * >>> E.rank_bound() 0
To show that this was resolved using a second descent, we do the computation again but turn off
second_descent
:sage: E = mwrank_EllipticCurve([0, -1, 0, -900, -10098]) sage: E.two_descent(second_descent = False, verbose=False) sage: E.rank_bound() 2
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), -Integer(1), Integer(0), -Integer(900), -Integer(10098)]) >>> E.two_descent(second_descent = False, verbose=False) >>> E.rank_bound() 2
For the curve 571A, also with rank 0 and Sha of order 4, but with no 2-torsion, the Selmer rank is strictly greater than the rank:
sage: E = mwrank_EllipticCurve([0, -1, 1, -929, -10595]) sage: E.selmer_rank() 2 sage: E.rank_bound() 2
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), -Integer(1), Integer(1), -Integer(929), -Integer(10595)]) >>> E.selmer_rank() 2 >>> E.rank_bound() 2
In cases like this with no 2-torsion, the rank upper bound is always equal to the 2-Selmer rank. If we ask for the rank, all we get is a lower bound:
sage: E.rank() 0 sage: E.certain() False
>>> from sage.all import * >>> E.rank() 0 >>> E.certain() False
- set_verbose(verbose)[source]#
Set the verbosity of printing of output by the
two_descent()
and other functions.INPUT:
verbose
(int) – if positive, print lots of output when doing 2-descent.
EXAMPLES:
sage: E = mwrank_EllipticCurve([0, 0, 1, -1, 0]) sage: E.saturate() # no output sage: E.gens() [[0, -1, 1]] sage: E = mwrank_EllipticCurve([0, 0, 1, -1, 0]) sage: E.set_verbose(1) sage: E.saturate() # tol 1e-10 Basic pair: I=48, J=-432 disc=255744 2-adic index bound = 2 By Lemma 5.1(a), 2-adic index = 1 2-adic index = 1 One (I,J) pair Looking for quartics with I = 48, J = -432 Looking for Type 2 quartics: Trying positive a from 1 up to 1 (square a first...) (1,0,-6,4,1) --trivial Trying positive a from 1 up to 1 (...then non-square a) Finished looking for Type 2 quartics. Looking for Type 1 quartics: Trying positive a from 1 up to 2 (square a first...) (1,0,0,4,4) --nontrivial...(x:y:z) = (1 : 1 : 0) Point = [0:0:1] height = 0.0511114082399688402358 Rank of B=im(eps) increases to 1 (The previous point is on the egg) Exiting search for Type 1 quartics after finding one which is globally soluble. Mordell rank contribution from B=im(eps) = 1 Selmer rank contribution from B=im(eps) = 1 Sha rank contribution from B=im(eps) = 0 Mordell rank contribution from A=ker(eps) = 0 Selmer rank contribution from A=ker(eps) = 0 Sha rank contribution from A=ker(eps) = 0 Searching for points (bound = 8)...done: found points which generate a subgroup of rank 1 and regulator 0.0511114082399688402358 Processing points found during 2-descent...done: now regulator = 0.0511114082399688402358 Saturating (with bound = -1)...done: points were already saturated.
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), Integer(0), Integer(1), -Integer(1), Integer(0)]) >>> E.saturate() # no output >>> E.gens() [[0, -1, 1]] >>> E = mwrank_EllipticCurve([Integer(0), Integer(0), Integer(1), -Integer(1), Integer(0)]) >>> E.set_verbose(Integer(1)) >>> E.saturate() # tol 1e-10 Basic pair: I=48, J=-432 disc=255744 2-adic index bound = 2 By Lemma 5.1(a), 2-adic index = 1 2-adic index = 1 One (I,J) pair Looking for quartics with I = 48, J = -432 Looking for Type 2 quartics: Trying positive a from 1 up to 1 (square a first...) (1,0,-6,4,1) --trivial Trying positive a from 1 up to 1 (...then non-square a) Finished looking for Type 2 quartics. Looking for Type 1 quartics: Trying positive a from 1 up to 2 (square a first...) (1,0,0,4,4) --nontrivial...(x:y:z) = (1 : 1 : 0) Point = [0:0:1] height = 0.0511114082399688402358 Rank of B=im(eps) increases to 1 (The previous point is on the egg) Exiting search for Type 1 quartics after finding one which is globally soluble. Mordell rank contribution from B=im(eps) = 1 Selmer rank contribution from B=im(eps) = 1 Sha rank contribution from B=im(eps) = 0 Mordell rank contribution from A=ker(eps) = 0 Selmer rank contribution from A=ker(eps) = 0 Sha rank contribution from A=ker(eps) = 0 Searching for points (bound = 8)...done: found points which generate a subgroup of rank 1 and regulator 0.0511114082399688402358 Processing points found during 2-descent...done: now regulator = 0.0511114082399688402358 Saturating (with bound = -1)...done: points were already saturated.
- silverman_bound()[source]#
Return the Silverman height bound. This is a floating point number \(B\) such that if \(P\) is a point on the curve, then the naive logarithmic height \(h(P)\) is less than \(B+\hat{h}(P)\), where \(\hat{h}(P)\) is the canonical height of \(P\).
Warning
We assume the model is minimal!
EXAMPLES:
sage: E = mwrank_EllipticCurve([0, 0, 0, -1002231243161, 0]) sage: E.silverman_bound() 18.29545210468247 sage: E = mwrank_EllipticCurve([0,0,1,-7,6]) sage: E.silverman_bound() 6.284833369972403
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), Integer(0), Integer(0), -Integer(1002231243161), Integer(0)]) >>> E.silverman_bound() 18.29545210468247 >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(7),Integer(6)]) >>> E.silverman_bound() 6.284833369972403
- two_descent(verbose=True, selmer_only=False, first_limit=20, second_limit=8, n_aux=-1, second_descent=True)[source]#
Compute 2-descent data for this curve.
INPUT:
verbose
(bool, defaultTrue
) – print what mwrank is doing.selmer_only
(bool, defaultFalse
) –selmer_only
switch.first_limit
(int, default 20) – bound on \(|x|+|z|\) in quartic point search.second_limit
(int, default 8) – bound on \(\log \max(|x|,|z|)\), i.e. logarithmic.n_aux
(int, default -1) – (only relevant for general 2-descent when 2-torsion trivial) number of primes used for quartic search.n_aux=-1
causes default (8) to be used. Increase for curves of higher rank.second_descent
(bool, defaultTrue
) – (only relevant for curves with 2-torsion, where mwrank uses descent via 2-isogeny) flag determining whether or not to do second descent. Default strongly recommended.
OUTPUT:
Nothing – nothing is returned.
- class sage.libs.eclib.interface.mwrank_MordellWeil(curve, verbose=True, pp=1, maxr=999)[source]#
Bases:
SageObject
The
mwrank_MordellWeil
class represents a subgroup of a Mordell-Weil group. Use this class to saturate a specified list of points on anmwrank_EllipticCurve
, or to search for points up to some bound.INPUT:
curve
(mwrank_EllipticCurve
) – the underlying elliptic curve.verbose
(bool, defaultFalse
) – verbosity flag (controls amount of output produced in point searches).pp
(int, default 1) – process points flag (if nonzero, the points found are processed, so that at all times only a \(\ZZ\)-basis for the subgroup generated by the points found so far is stored; if zero, no processing is done and all points found are stored).maxr
(int, default 999) – maximum rank (quit point searching once the points found generate a subgroup of this rank; useful if an upper bound for the rank is already known).
EXAMPLES:
sage: E = mwrank_EllipticCurve([1,0,1,4,-6]) sage: EQ = mwrank_MordellWeil(E) sage: EQ Subgroup of Mordell-Weil group: [] sage: EQ.search(2) P1 = [0:1:0] is torsion point, order 1 P1 = [1:-1:1] is torsion point, order 2 P1 = [2:2:1] is torsion point, order 3 P1 = [9:23:1] is torsion point, order 6 sage: E = mwrank_EllipticCurve([0,0,1,-7,6]) sage: EQ = mwrank_MordellWeil(E) sage: EQ.search(2) P1 = [0:1:0] is torsion point, order 1 P1 = [-3:0:1] is generator number 1 ... P4 = [-91:804:343] = -2*P1 + 2*P2 + 1*P3 (mod torsion) sage: EQ Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]]
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(1),Integer(0),Integer(1),Integer(4),-Integer(6)]) >>> EQ = mwrank_MordellWeil(E) >>> EQ Subgroup of Mordell-Weil group: [] >>> EQ.search(Integer(2)) P1 = [0:1:0] is torsion point, order 1 P1 = [1:-1:1] is torsion point, order 2 P1 = [2:2:1] is torsion point, order 3 P1 = [9:23:1] is torsion point, order 6 >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(7),Integer(6)]) >>> EQ = mwrank_MordellWeil(E) >>> EQ.search(Integer(2)) P1 = [0:1:0] is torsion point, order 1 P1 = [-3:0:1] is generator number 1 ... P4 = [-91:804:343] = -2*P1 + 2*P2 + 1*P3 (mod torsion) >>> EQ Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]]
Example to illustrate the verbose parameter:
sage: E = mwrank_EllipticCurve([0,0,1,-7,6]) sage: EQ = mwrank_MordellWeil(E, verbose=False) sage: EQ.search(1) sage: EQ Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]] sage: EQ = mwrank_MordellWeil(E, verbose=True) 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...Saturation index bound (for points of good reduction) = 3 Reducing saturation bound from given value 20 to computed index bound 3 Tamagawa index primes are [ 2 ]... 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...Saturation index bound (for points of good reduction) = 4 Reducing saturation bound from given value 20 to computed index bound 4 Tamagawa index primes are [ 2 ]... 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! 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 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...Saturation index bound (for points of good reduction) = 3 Reducing saturation bound from given value 20 to computed index bound 3 Tamagawa index primes are [ 2 ]... 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) P4 = [1:0:1] = -1*P1 + 0*P2 + 0*P3 (mod torsion) P4 = [2:0:1] = -1*P1 + 1*P2 + 0*P3 (mod torsion) P4 = [18:7:8] = -2*P1 + -1*P2 + -1*P3 (mod torsion) P4 = [3:3:1] = 1*P1 + 0*P2 + 1*P3 (mod torsion) P4 = [4:6:1] = 0*P1 + -1*P2 + -1*P3 (mod torsion) P4 = [36:69:64] = 1*P1 + -2*P2 + 0*P3 (mod torsion) P4 = [68:-25:64] = -2*P1 + -1*P2 + -2*P3 (mod torsion) P4 = [12:35:27] = 1*P1 + -1*P2 + -1*P3 (mod torsion) sage: EQ Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]]
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(7),Integer(6)]) >>> EQ = mwrank_MordellWeil(E, verbose=False) >>> EQ.search(Integer(1)) >>> EQ Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]] >>> EQ = mwrank_MordellWeil(E, verbose=True) >>> EQ.search(Integer(1)) P1 = [0:1:0] is torsion point, order 1 P1 = [-3:0:1] is generator number 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 Tamagawa index primes are [ 2 ]... 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...Saturation index bound (for points of good reduction) = 4 Reducing saturation bound from given value 20 to computed index bound 4 Tamagawa index primes are [ 2 ]... 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! 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 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...Saturation index bound (for points of good reduction) = 3 Reducing saturation bound from given value 20 to computed index bound 3 Tamagawa index primes are [ 2 ]... 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) P4 = [1:0:1] = -1*P1 + 0*P2 + 0*P3 (mod torsion) P4 = [2:0:1] = -1*P1 + 1*P2 + 0*P3 (mod torsion) P4 = [18:7:8] = -2*P1 + -1*P2 + -1*P3 (mod torsion) P4 = [3:3:1] = 1*P1 + 0*P2 + 1*P3 (mod torsion) P4 = [4:6:1] = 0*P1 + -1*P2 + -1*P3 (mod torsion) P4 = [36:69:64] = 1*P1 + -2*P2 + 0*P3 (mod torsion) P4 = [68:-25:64] = -2*P1 + -1*P2 + -2*P3 (mod torsion) P4 = [12:35:27] = 1*P1 + -1*P2 + -1*P3 (mod torsion) >>> EQ Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]]
Example to illustrate the process points (
pp
) parameter:sage: E = mwrank_EllipticCurve([0,0,1,-7,6]) sage: EQ = mwrank_MordellWeil(E, verbose=False, pp=1) sage: EQ.search(1); EQ # generators only Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]] sage: EQ = mwrank_MordellWeil(E, verbose=False, pp=0) sage: EQ.search(1); EQ # all points found Subgroup of Mordell-Weil group: [[-3:0:1], [-2:3:1], [-14:25:8], [-1:3:1], [0:2:1], [2:13:8], [1:0:1], [2:0:1], [18:7:8], [3:3:1], [4:6:1], [36:69:64], [68:-25:64], [12:35:27]]
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(7),Integer(6)]) >>> EQ = mwrank_MordellWeil(E, verbose=False, pp=Integer(1)) >>> EQ.search(Integer(1)); EQ # generators only Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]] >>> EQ = mwrank_MordellWeil(E, verbose=False, pp=Integer(0)) >>> EQ.search(Integer(1)); EQ # all points found Subgroup of Mordell-Weil group: [[-3:0:1], [-2:3:1], [-14:25:8], [-1:3:1], [0:2:1], [2:13:8], [1:0:1], [2:0:1], [18:7:8], [3:3:1], [4:6:1], [36:69:64], [68:-25:64], [12:35:27]]
- points()[source]#
Return a list of the generating points in this Mordell-Weil group.
OUTPUT:
(list) A list of lists of length 3, each holding the primitive integer coordinates \([x,y,z]\) of a generating point.
EXAMPLES:
sage: E = mwrank_EllipticCurve([0,0,1,-7,6]) sage: EQ = mwrank_MordellWeil(E) 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) sage: EQ.points() [[1, -1, 1], [-2, 3, 1], [-14, 25, 8]]
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(7),Integer(6)]) >>> EQ = mwrank_MordellWeil(E) >>> EQ.search(Integer(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) >>> EQ.points() [[1, -1, 1], [-2, 3, 1], [-14, 25, 8]]
- process(v, saturation_bound=0)[source]#
Process points in the list
v
.This function allows one to add points to a
mwrank_MordellWeil
object.INPUT:
v
(list of 3-tuples or lists of ints or Integers) – a list of triples of integers, which define points on the curve.saturation_bound
(int, default 0) – saturate at primes up tosaturation_bound
, or at all primes ifsaturation_bound
is -1; whensaturation_bound
is 0 (the default), do no saturation..
OUTPUT:
None. But note that if the
verbose
flag is set, then there will be some output as a side-effect.EXAMPLES:
sage: E = mwrank_EllipticCurve([0,0,1,-7,6]) sage: E.gens() [[1, -1, 1], [-2, 3, 1], [-14, 25, 8]] sage: EQ = mwrank_MordellWeil(E) sage: EQ.process([[1, -1, 1], [-2, 3, 1], [-14, 25, 8]]) P1 = [1:-1:1] is generator number 1 P2 = [-2:3:1] is generator number 2 P3 = [-14:25:8] is generator number 3
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(7),Integer(6)]) >>> E.gens() [[1, -1, 1], [-2, 3, 1], [-14, 25, 8]] >>> EQ = mwrank_MordellWeil(E) >>> EQ.process([[Integer(1), -Integer(1), Integer(1)], [-Integer(2), Integer(3), Integer(1)], [-Integer(14), Integer(25), Integer(8)]]) P1 = [1:-1:1] is generator number 1 P2 = [-2:3:1] is generator number 2 P3 = [-14:25:8] is generator number 3
sage: EQ.points() [[1, -1, 1], [-2, 3, 1], [-14, 25, 8]]
>>> from sage.all import * >>> EQ.points() [[1, -1, 1], [-2, 3, 1], [-14, 25, 8]]
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]], 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] ] sage: EQ.points() [[-2, 3, 1], [-14, 25, 8], [1, -1, 1]]
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(7),Integer(6)]) >>> EQ = mwrank_MordellWeil(E) >>> EQ.process([[Integer(1547), -Integer(2967), Integer(343)], [Integer(2707496766203306), Integer(864581029138191), Integer(2969715140223272)], [-Integer(13422227300), -Integer(49322830557), Integer(12167000000)]], saturation_bound=Integer(20)) P1 = [1547:-2967:343] is generator number 1 ... Gained index 5, new generators = [ [-2:3:1] [-14:25:8] [1:-1:1] ] >>> EQ.points() [[-2, 3, 1], [-14, 25, 8], [1, -1, 1]]
Here the processing was followed by saturation at primes up to 20. Now we prevent this initial saturation:
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]], 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 sage: EQ.points() [[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]] sage: EQ.regulator() 375.42920288254555 sage: EQ.saturate(2) # points were not 2-saturated 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 Tamagawa index primes are [ 2 ]... 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.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 (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 Tamagawa index primes are [ 2 ]... 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.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 (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 Tamagawa index primes are [ 2 ]... 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.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 (for points of good reduction) = 3 Tamagawa index primes are [ 2 ]... 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 (True, 1, '[ ]')
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(7),Integer(6)]) >>> EQ = mwrank_MordellWeil(E) >>> EQ.process([[Integer(1547), -Integer(2967), Integer(343)], [Integer(2707496766203306), Integer(864581029138191), Integer(2969715140223272)], [-Integer(13422227300), -Integer(49322830557), Integer(12167000000)]], saturation_bound=Integer(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 >>> EQ.points() [[1547, -2967, 343], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]] >>> EQ.regulator() 375.42920288254555 >>> EQ.saturate(Integer(2)) # points were not 2-saturated 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 Tamagawa index primes are [ 2 ]... 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.85730072 (True, 2, '[ ]') >>> EQ.points() [[-2, 3, 1], [2707496766203306, 864581029138191, 2969715140223272], [-13422227300, -49322830557, 12167000000]] >>> EQ.regulator() 93.85730072063639 >>> EQ.saturate(Integer(3)) # points were not 3-saturated 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 Tamagawa index primes are [ 2 ]... 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.42858897 (True, 3, '[ ]') >>> EQ.points() [[-2, 3, 1], [-14, 25, 8], [-13422227300, -49322830557, 12167000000]] >>> EQ.regulator() 10.4285889689596 >>> EQ.saturate(Integer(5)) # points were not 5-saturated 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 Tamagawa index primes are [ 2 ]... 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.4171435588 (True, 5, '[ ]') >>> EQ.points() [[-2, 3, 1], [-14, 25, 8], [1, -1, 1]] >>> EQ.regulator() 0.417143558758384 >>> EQ.saturate() # points are now saturated saturating basis...Saturation index bound (for points of good reduction) = 3 Tamagawa index primes are [ 2 ]... 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 (True, 1, '[ ]')
- rank()[source]#
Return the rank of this subgroup of the Mordell-Weil group.
OUTPUT:
(int) The rank of this subgroup of the Mordell-Weil group.
EXAMPLES:
sage: E = mwrank_EllipticCurve([0,-1,1,0,0]) sage: E.rank() 0
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0),-Integer(1),Integer(1),Integer(0),Integer(0)]) >>> E.rank() 0
A rank 3 example:
sage: E = mwrank_EllipticCurve([0,0,1,-7,6]) sage: EQ = mwrank_MordellWeil(E) sage: EQ.rank() 0 sage: EQ.regulator() 1.0
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(7),Integer(6)]) >>> EQ = mwrank_MordellWeil(E) >>> EQ.rank() 0 >>> EQ.regulator() 1.0
The preceding output is correct, since we have not yet tried to find any points on the curve either by searching or 2-descent:
sage: EQ Subgroup of Mordell-Weil group: []
>>> from sage.all import * >>> EQ Subgroup of Mordell-Weil group: []
Now we do a very small search:
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 ... P4 = [12:35:27] = 1*P1 + -1*P2 + -1*P3 (mod torsion) sage: EQ Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]] sage: EQ.rank() 3 sage: EQ.regulator() 0.417143558758384
>>> from sage.all import * >>> EQ.search(Integer(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 ... P4 = [12:35:27] = 1*P1 + -1*P2 + -1*P3 (mod torsion) >>> EQ Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]] >>> EQ.rank() 3 >>> EQ.regulator() 0.417143558758384
We do in fact now have a full Mordell-Weil basis.
- regulator()[source]#
Return the regulator of the points in this subgroup of the Mordell-Weil group.
Note
eclib
can compute the regulator to arbitrary precision, but the interface currently returns the output as afloat
.OUTPUT:
(float) The regulator of the points in this subgroup.
EXAMPLES:
sage: E = mwrank_EllipticCurve([0,-1,1,0,0]) sage: E.regulator() 1.0 sage: E = mwrank_EllipticCurve([0,0,1,-7,6]) sage: E.regulator() 0.417143558758384
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0),-Integer(1),Integer(1),Integer(0),Integer(0)]) >>> E.regulator() 1.0 >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(7),Integer(6)]) >>> E.regulator() 0.417143558758384
- saturate(max_prime=-1, min_prime=2)[source]#
Saturate this subgroup of the Mordell-Weil group.
INPUT:
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 ofmax_prime
and the computed bound.min_prime
(int, default 2) – only do saturation at primes no less than this. (For example, if the points have been found viatwo_descent()
they should already be 2-saturated so a value of 3 is appropriate.)
OUTPUT:
(3-tuple) (
ok
,index
,unsatlist
) where:ok
(bool) –True
if and only if the saturation was provably successful at all primes attempted. If the default was used formax_prime
, thenTrue
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.
Note
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 cause failures. Since v20210310,eclib
uses exact method based on division polynomials, which should mean that such failures does not happen.Note
We emphasize that if this function returns
True
as the first return argument (ok
), and if the default was used for the parametermax_prime
, then the points in the basis after calling this function are saturated at all primes, i.e., saturating at the primes up tomax_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 ifmax_prime
is larger.EXAMPLES:
sage: E = mwrank_EllipticCurve([0,0,1,-7,6]) sage: EQ = mwrank_MordellWeil(E)
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(7),Integer(6)]) >>> EQ = mwrank_MordellWeil(E)
We initialise with three points which happen to be 2, 3 and 5 times the generators of this rank 3 curve. To prevent 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]], 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 sage: EQ Subgroup of Mordell-Weil group: [[1547:-2967:343], [2707496766203306:864581029138191:2969715140223272], [-13422227300:-49322830557:12167000000]] sage: EQ.regulator() 375.42920288254555
>>> from sage.all import * >>> EQ.process([[Integer(1547), -Integer(2967), Integer(343)], [Integer(2707496766203306), Integer(864581029138191), Integer(2969715140223272)], [-Integer(13422227300), -Integer(49322830557), Integer(12167000000)]], saturation_bound=Integer(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 >>> EQ Subgroup of Mordell-Weil group: [[1547:-2967:343], [2707496766203306:864581029138191:2969715140223272], [-13422227300:-49322830557:12167000000]] >>> EQ.regulator() 375.42920288254555
Now we saturate at \(p=2\), and gain index 2:
sage: EQ.saturate(2) # points were not 2-saturated 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... (True, 2, '[ ]') sage: EQ Subgroup of Mordell-Weil group: [[-2:3:1], [2707496766203306:864581029138191:2969715140223272], [-13422227300:-49322830557:12167000000]] sage: EQ.regulator() 93.85730072063639
>>> from sage.all import * >>> EQ.saturate(Integer(2)) # points were not 2-saturated 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... (True, 2, '[ ]') >>> EQ Subgroup of Mordell-Weil group: [[-2:3:1], [2707496766203306:864581029138191:2969715140223272], [-13422227300:-49322830557:12167000000]] >>> EQ.regulator() 93.85730072063639
Now we saturate at \(p=3\), and gain index 3:
sage: EQ.saturate(3) # points were not 3-saturated 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... (True, 3, '[ ]') sage: EQ Subgroup of Mordell-Weil group: [[-2:3:1], [-14:25:8], [-13422227300:-49322830557:12167000000]] sage: EQ.regulator() 10.4285889689596
>>> from sage.all import * >>> EQ.saturate(Integer(3)) # points were not 3-saturated 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... (True, 3, '[ ]') >>> EQ Subgroup of Mordell-Weil group: [[-2:3:1], [-14:25:8], [-13422227300:-49322830557:12167000000]] >>> EQ.regulator() 10.4285889689596
Now we saturate at \(p=5\), and gain index 5:
sage: EQ.saturate(5) # points were not 5-saturated 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... (True, 5, '[ ]') sage: EQ Subgroup of Mordell-Weil group: [[-2:3:1], [-14:25:8], [1:-1:1]] sage: EQ.regulator() 0.417143558758384
>>> from sage.all import * >>> EQ.saturate(Integer(5)) # points were not 5-saturated 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... (True, 5, '[ ]') >>> EQ Subgroup of Mordell-Weil group: [[-2:3:1], [-14:25:8], [1:-1:1]] >>> EQ.regulator() 0.417143558758384
Finally we finish the saturation. The output here shows that the points are now provably saturated at all primes:
sage: EQ.saturate() # points are now saturated saturating basis...Saturation index bound (for points of good reduction) = 3 Tamagawa index primes are [ 2 ]... 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 (True, 1, '[ ]')
>>> from sage.all import * >>> EQ.saturate() # points are now saturated saturating basis...Saturation index bound (for points of good reduction) = 3 Tamagawa index primes are [ 2 ]... 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 (True, 1, '[ ]')
Of course, the
process()
function would have done all this automatically for us: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]], 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] ] sage: EQ Subgroup of Mordell-Weil group: [[-2:3:1], [-14:25:8], [1:-1:1]] sage: EQ.regulator() 0.417143558758384
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(7),Integer(6)]) >>> EQ = mwrank_MordellWeil(E) >>> EQ.process([[Integer(1547), -Integer(2967), Integer(343)], [Integer(2707496766203306), Integer(864581029138191), Integer(2969715140223272)], [-Integer(13422227300), -Integer(49322830557), Integer(12167000000)]], saturation_bound=Integer(5)) P1 = [1547:-2967:343] is generator number 1 ... Gained index 5, new generators = [ [-2:3:1] [-14:25:8] [1:-1:1] ] >>> EQ Subgroup of Mordell-Weil group: [[-2:3:1], [-14:25:8], [1:-1:1]] >>> EQ.regulator() 0.417143558758384
But we would still need to use the
saturate()
function to verify that full saturation has been done:sage: EQ.saturate() saturating basis...Saturation index bound (for points of good reduction) = 3 Tamagawa index primes are [ 2 ]... 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 (True, 1, '[ ]')
>>> from sage.all import * >>> EQ.saturate() saturating basis...Saturation index bound (for points of good reduction) = 3 Tamagawa index primes are [ 2 ]... 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 (True, 1, '[ ]')
Note the output of the preceding command: it proves that the 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.
- search(height_limit=18, verbose=False)[source]#
Search for new points, and add them to this subgroup of the Mordell-Weil group.
INPUT:
height_limit
(float, default: 18) – search up to this logarithmic height.
Note
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 (\(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.
Note
The search is carried out with a quadratic sieve, using code adapted from a version of Michael Stoll’s
ratpoints
program. It would be preferable to use a newer version ofratpoints
.verbose
(bool, defaultFalse
) – turn verbose operation on or off.
EXAMPLES:
A rank 3 example, where a very small search is sufficient to find a Mordell-Weil basis:
sage: E = mwrank_EllipticCurve([0,0,1,-7,6]) sage: EQ = mwrank_MordellWeil(E) 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) sage: EQ Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]]
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0),Integer(0),Integer(1),-Integer(7),Integer(6)]) >>> EQ = mwrank_MordellWeil(E) >>> EQ.search(Integer(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) >>> EQ Subgroup of Mordell-Weil group: [[1:-1:1], [-2:3:1], [-14:25:8]]
In the next example, a search bound of 12 is needed to find a non-torsion point:
sage: E = mwrank_EllipticCurve([0, -1, 0, -18392, -1186248]) #1056g4 sage: EQ = mwrank_MordellWeil(E) sage: EQ.search(11); EQ P1 = [0:1:0] is torsion point, order 1 P1 = [161:0:1] is torsion point, order 2 Subgroup of Mordell-Weil group: [] sage: EQ.search(12); EQ P1 = [0:1:0] is torsion point, order 1 P1 = [161:0:1] is torsion point, order 2 P1 = [4413270:10381877:27000] is generator number 1 ... Subgroup of Mordell-Weil group: [[4413270:10381877:27000]]
>>> from sage.all import * >>> E = mwrank_EllipticCurve([Integer(0), -Integer(1), Integer(0), -Integer(18392), -Integer(1186248)]) #1056g4 >>> EQ = mwrank_MordellWeil(E) >>> EQ.search(Integer(11)); EQ P1 = [0:1:0] is torsion point, order 1 P1 = [161:0:1] is torsion point, order 2 Subgroup of Mordell-Weil group: [] >>> EQ.search(Integer(12)); EQ P1 = [0:1:0] is torsion point, order 1 P1 = [161:0:1] is torsion point, order 2 P1 = [4413270:10381877:27000] is generator number 1 ... Subgroup of Mordell-Weil group: [[4413270:10381877:27000]]