| 1 | r""" |
|---|
| 2 | Cremona's MWRANK Library |
|---|
| 3 | |
|---|
| 4 | This is the SAGE interface to John Cremona's MWRANK C++ library for |
|---|
| 5 | arithmetic on elliptic curves. The classes defined in this module |
|---|
| 6 | give SAGE interpreter-level to access much of the functionality of |
|---|
| 7 | MWRANK. For most purposes it is not necessary to directly use these |
|---|
| 8 | classes; instead, one can create an \class{EllipticCurve} and call |
|---|
| 9 | methods that are implemented using this module. |
|---|
| 10 | |
|---|
| 11 | \note{This interface is a direct library-level interface to mwrank.} |
|---|
| 12 | """ |
|---|
| 13 | |
|---|
| 14 | from sage.structure.sage_object import SageObject |
|---|
| 15 | |
|---|
| 16 | def set_precision(n): |
|---|
| 17 | """ |
|---|
| 18 | Set the global NTL real number precision. This has a massive |
|---|
| 19 | effect on the speed of mwrank calculations. The default is n=15, |
|---|
| 20 | but it might have to be increased if a computation fails. In this |
|---|
| 21 | case, one must recreate the mwrank curve from scratch after |
|---|
| 22 | resetting this precision. |
|---|
| 23 | |
|---|
| 24 | NOTE -- this change is global and affects all of SAGE. |
|---|
| 25 | |
|---|
| 26 | INPUT: |
|---|
| 27 | n -- long |
|---|
| 28 | |
|---|
| 29 | EXAMPLES: |
|---|
| 30 | sage: mwrank_set_precision(20) |
|---|
| 31 | """ |
|---|
| 32 | # don't want to load mwrank every time SAGE starts up, so we do |
|---|
| 33 | # the import here. |
|---|
| 34 | from sage.libs.mwrank.mwrank import set_precision |
|---|
| 35 | set_precision(n) |
|---|
| 36 | |
|---|
| 37 | class mwrank_EllipticCurve(SageObject): |
|---|
| 38 | r""" |
|---|
| 39 | The \class{mwrank_EllipticCurve} class represents an MWRANK |
|---|
| 40 | elliptic curve. |
|---|
| 41 | """ |
|---|
| 42 | def __init__(self, ainvs, verbose=False): |
|---|
| 43 | r""" |
|---|
| 44 | Create the mwrank elliptic curve with invariants |
|---|
| 45 | \code{a_invs}, which is a list of $\leq 5$ \emph{integers} $a_1$, |
|---|
| 46 | $a_2$, $a_3$, $a_4$, and $a_6$. |
|---|
| 47 | |
|---|
| 48 | If strictly less than 5 invariants are given, then the first |
|---|
| 49 | ones are set to 0, so, e.g., \code{[3,4]} means $a_1=a_2=a_3=0$ and |
|---|
| 50 | $a_4=3$, $a_6=4$. |
|---|
| 51 | |
|---|
| 52 | INPUT: |
|---|
| 53 | ainvs -- a list of <= 5 integers |
|---|
| 54 | verbose -- if True, then all Selmer group computations |
|---|
| 55 | will be verbose. (default: False). |
|---|
| 56 | |
|---|
| 57 | EXAMPLES: |
|---|
| 58 | We create the elliptic curve $y^2 + y = x^3 + x^2 - 2x$. |
|---|
| 59 | |
|---|
| 60 | sage: e = mwrank_EllipticCurve([0, 1, 1, -2, 0]) |
|---|
| 61 | sage: e.ainvs() |
|---|
| 62 | [0, 1, 1, -2, 0] |
|---|
| 63 | |
|---|
| 64 | This example illustrates that omitted $a$-invariants default to $0$: |
|---|
| 65 | sage: e = mwrank_EllipticCurve([3, -4]) |
|---|
| 66 | sage: e |
|---|
| 67 | y^2 = x^3 + 3*x - 4 |
|---|
| 68 | sage: e.ainvs() |
|---|
| 69 | [0, 0, 0, 3, -4] |
|---|
| 70 | |
|---|
| 71 | The entries of the input list are coerced to \class{int}. |
|---|
| 72 | This has the effect that for float input, the integer parts of |
|---|
| 73 | the input coefficients are taken. |
|---|
| 74 | sage: e = mwrank_EllipticCurve([3, float(-4.8)]); e |
|---|
| 75 | y^2 = x^3 + 3*x - 4 |
|---|
| 76 | |
|---|
| 77 | When you enter a singular model you get an exception: |
|---|
| 78 | sage: e = mwrank_EllipticCurve([0, 0]) |
|---|
| 79 | Traceback (most recent call last): |
|---|
| 80 | ... |
|---|
| 81 | ArithmeticError: Invariants (= [0, 0, 0, 0, 0]) do not describe an elliptic curve. |
|---|
| 82 | """ |
|---|
| 83 | # import here to save time during startup (mwrank takes a while to init) |
|---|
| 84 | from sage.libs.mwrank.mwrank import _Curvedata |
|---|
| 85 | |
|---|
| 86 | if not isinstance(ainvs, list) and len(ainvs) <= 5: |
|---|
| 87 | raise TypeError, "ainvs must be a list of length at most 5." |
|---|
| 88 | |
|---|
| 89 | # Pad ainvs on the beginning by 0's, so e.g. |
|---|
| 90 | # [a4,a6] works. |
|---|
| 91 | ainvs = [0]*(5-len(ainvs)) + ainvs |
|---|
| 92 | |
|---|
| 93 | # Convert each entry to an int |
|---|
| 94 | try: |
|---|
| 95 | a_int = [int(x) for x in ainvs] |
|---|
| 96 | except (TypeError, ValueError): |
|---|
| 97 | raise TypeError, "ainvs must be a list of integers." |
|---|
| 98 | self.__ainvs = a_int |
|---|
| 99 | self.__curve = _Curvedata(a_int[0], a_int[1], a_int[2], |
|---|
| 100 | a_int[3], a_int[4]) |
|---|
| 101 | |
|---|
| 102 | if verbose: |
|---|
| 103 | self.__verbose = True |
|---|
| 104 | else: |
|---|
| 105 | self.__verbose = False |
|---|
| 106 | |
|---|
| 107 | # place holders |
|---|
| 108 | self.__saturate = -2 # not yet saturated |
|---|
| 109 | |
|---|
| 110 | def __reduce__(self): |
|---|
| 111 | return mwrank_EllipticCurve, (self.__ainvs, self.__verbose) |
|---|
| 112 | |
|---|
| 113 | |
|---|
| 114 | def set_verbose(self, verbose): |
|---|
| 115 | """ |
|---|
| 116 | Set the verbosity of printing of output by the 2-descent and |
|---|
| 117 | other functions. |
|---|
| 118 | INPUT: |
|---|
| 119 | verbosity -- bool; if True print lots of output |
|---|
| 120 | """ |
|---|
| 121 | self.__verbose = verbose |
|---|
| 122 | |
|---|
| 123 | |
|---|
| 124 | def _curve_data(self): |
|---|
| 125 | return self.__curve |
|---|
| 126 | |
|---|
| 127 | def ainvs(self): |
|---|
| 128 | return self.__ainvs |
|---|
| 129 | |
|---|
| 130 | def isogeny_class(self, verbose=False): |
|---|
| 131 | return self.__curve.isogeny_class(verbose) |
|---|
| 132 | |
|---|
| 133 | def __repr__(self): |
|---|
| 134 | a = self.ainvs() |
|---|
| 135 | s = "y^2" |
|---|
| 136 | if a[0] == -1: |
|---|
| 137 | s += "- x*y " |
|---|
| 138 | elif a[0] == 1: |
|---|
| 139 | s += "+ x*y " |
|---|
| 140 | elif a[0] != 0: |
|---|
| 141 | s += "+ %s*x*y "%a[0] |
|---|
| 142 | if a[2] == -1: |
|---|
| 143 | s += " - y" |
|---|
| 144 | elif a[2] == 1: |
|---|
| 145 | s += "+ y" |
|---|
| 146 | elif a[2] != 0: |
|---|
| 147 | s += "+ %s*y"%a[2] |
|---|
| 148 | s += " = x^3 " |
|---|
| 149 | if a[1] == -1: |
|---|
| 150 | s += "- x^2 " |
|---|
| 151 | elif a[1] == 1: |
|---|
| 152 | s += "+ x^2 " |
|---|
| 153 | elif a[1] != 0: |
|---|
| 154 | s += "+ %s*x^2 "%a[1] |
|---|
| 155 | if a[3] == -1: |
|---|
| 156 | s += "- x " |
|---|
| 157 | elif a[3] == 1: |
|---|
| 158 | s += "+ x " |
|---|
| 159 | elif a[3] != 0: |
|---|
| 160 | s += "+ %s*x "%a[3] |
|---|
| 161 | if a[4] == -1: |
|---|
| 162 | s += "-1" |
|---|
| 163 | elif a[4] == 1: |
|---|
| 164 | s += "+1" |
|---|
| 165 | elif a[4] != 0: |
|---|
| 166 | s += "+ %s"%a[4] |
|---|
| 167 | s = s.replace("+ -","- ") |
|---|
| 168 | return s |
|---|
| 169 | |
|---|
| 170 | |
|---|
| 171 | def two_descent(self, |
|---|
| 172 | verbose = True, |
|---|
| 173 | selmer_only = False, |
|---|
| 174 | first_limit = 20, |
|---|
| 175 | second_limit = 8, |
|---|
| 176 | n_aux = -1, |
|---|
| 177 | second_descent = True): |
|---|
| 178 | """ |
|---|
| 179 | Compute 2-descent data for this curve. |
|---|
| 180 | |
|---|
| 181 | INPUT: |
|---|
| 182 | verbose -- (default: True) print what mwrank is doing |
|---|
| 183 | selmer_only -- (default: False) selmer_only switch |
|---|
| 184 | first_limit -- (default: 20) firstlim is bound on |x|+|z| |
|---|
| 185 | second_limit-- (default: 5) secondlim is bound on log max {|x|,|z| }, |
|---|
| 186 | i.e. logarithmic |
|---|
| 187 | n_aux -- (default: -1) n_aux only relevant for general |
|---|
| 188 | 2-descent when 2-torsion trivial; n_aux=-1 causes default |
|---|
| 189 | to be used (depends on method) |
|---|
| 190 | second_descent -- (default: True) second_descent only relevant for |
|---|
| 191 | descent via 2-isogeny |
|---|
| 192 | OUTPUT: |
|---|
| 193 | Nothing -- nothing is returned |
|---|
| 194 | """ |
|---|
| 195 | from sage.libs.mwrank.mwrank import _two_descent # import here to save time |
|---|
| 196 | first_limit = int(first_limit) |
|---|
| 197 | second_limit = int(second_limit) |
|---|
| 198 | n_aux = int(n_aux) |
|---|
| 199 | second_descent = int(second_descent) |
|---|
| 200 | # TODO: Don't allow limits above some value...??? |
|---|
| 201 | # (since otherwise mwrank just sets limit tiny) |
|---|
| 202 | self.__descent = _two_descent() |
|---|
| 203 | self.__descent.do_descent(self.__curve, |
|---|
| 204 | verbose, |
|---|
| 205 | selmer_only, |
|---|
| 206 | first_limit, |
|---|
| 207 | second_limit, |
|---|
| 208 | n_aux, |
|---|
| 209 | second_descent) |
|---|
| 210 | if not self.__two_descent_data().ok(): |
|---|
| 211 | raise RuntimeError, "A 2-descent didn't not complete successfully." |
|---|
| 212 | |
|---|
| 213 | def __two_descent_data(self): |
|---|
| 214 | try: |
|---|
| 215 | return self.__descent |
|---|
| 216 | except AttributeError: |
|---|
| 217 | self.two_descent(self.__verbose) |
|---|
| 218 | return self.__descent |
|---|
| 219 | |
|---|
| 220 | def conductor(self): |
|---|
| 221 | """ |
|---|
| 222 | Return the conductor of this curve, computed using Cremona's |
|---|
| 223 | implementation of Tate's algorithm. |
|---|
| 224 | |
|---|
| 225 | NOTE: This is independent of PARI's. |
|---|
| 226 | """ |
|---|
| 227 | return self.__curve.conductor() |
|---|
| 228 | |
|---|
| 229 | def rank(self): |
|---|
| 230 | """ |
|---|
| 231 | Returns the rank of this curve, computed using 2-descent. |
|---|
| 232 | """ |
|---|
| 233 | return self.__two_descent_data().getrank() |
|---|
| 234 | |
|---|
| 235 | def selmer_rank_bound(self): |
|---|
| 236 | r""" |
|---|
| 237 | Bound on the rank of the curve, computed using the 2-selmer |
|---|
| 238 | group. This is the rank of the curve minus the rank of the |
|---|
| 239 | 2-torsion, minus a number determined by whatever mwrank was |
|---|
| 240 | able to determine related to $\Sha(E)[2]$ (e.g., using a |
|---|
| 241 | second descent or if there is a rational $2$-torsion point, |
|---|
| 242 | then there may be an isogeny to a curve with trivial |
|---|
| 243 | $\Sha(E)$). In many cases, this is the actual rank of the |
|---|
| 244 | curve, but in general it is just $\geq$ the true rank. |
|---|
| 245 | |
|---|
| 246 | EXAMPLES: |
|---|
| 247 | The following is the curve 960D1, which has rank 0, |
|---|
| 248 | but Sha of order 4. |
|---|
| 249 | |
|---|
| 250 | sage: E = mwrank_EllipticCurve([0, -1, 0, -900, -10098]) |
|---|
| 251 | sage: E.selmer_rank_bound() |
|---|
| 252 | 0 |
|---|
| 253 | |
|---|
| 254 | In this case this was resolved using a second descent. |
|---|
| 255 | |
|---|
| 256 | sage: E = mwrank_EllipticCurve([0, -1, 0, -900, -10098]) |
|---|
| 257 | sage: E.two_descent(second_descent = False, verbose=False) |
|---|
| 258 | sage: E.selmer_rank_bound() |
|---|
| 259 | 2 |
|---|
| 260 | |
|---|
| 261 | Above, the \method{selmer_rank_bound} gives 0 instead of 2, |
|---|
| 262 | because it knows Sha is nontrivial. In contrast, for the |
|---|
| 263 | curve 571A, also with rank 0 and $\Sha$ of order 4, we obtain |
|---|
| 264 | a worse bound: |
|---|
| 265 | |
|---|
| 266 | sage: E = mwrank_EllipticCurve([0, -1, 1, -929, -10595]) |
|---|
| 267 | sage: E.selmer_rank_bound() |
|---|
| 268 | 2 |
|---|
| 269 | sage: E.rank() |
|---|
| 270 | 0 |
|---|
| 271 | """ |
|---|
| 272 | return self.__two_descent_data().getselmer() |
|---|
| 273 | |
|---|
| 274 | def regulator(self): |
|---|
| 275 | """ |
|---|
| 276 | Return the regulator of the saturated Mordell-Weil group. |
|---|
| 277 | |
|---|
| 278 | sage: E = mwrank_EllipticCurve([0, 0, 1, -1, 0]) |
|---|
| 279 | sage: E.regulator() |
|---|
| 280 | 0.05111140823996884 |
|---|
| 281 | |
|---|
| 282 | """ |
|---|
| 283 | self.saturate() |
|---|
| 284 | if not self.certain(): |
|---|
| 285 | raise RuntimeError, "Unable to saturate Mordell-Weil group." |
|---|
| 286 | R = self.__two_descent_data().regulator() |
|---|
| 287 | return float(R) |
|---|
| 288 | |
|---|
| 289 | def saturate(self, bound=-1): |
|---|
| 290 | """ |
|---|
| 291 | Compute the saturation of the Mordell-Weil group at all |
|---|
| 292 | primes up to bound. |
|---|
| 293 | |
|---|
| 294 | INPUT: |
|---|
| 295 | bound -- int (default: -1) -1 saturate at *all* primes, |
|---|
| 296 | 0 -- do not saturate |
|---|
| 297 | n -- saturate at least at all primes <= n. |
|---|
| 298 | """ |
|---|
| 299 | bound = int(bound) |
|---|
| 300 | if self.__saturate < bound: |
|---|
| 301 | self.__two_descent_data().saturate(bound) |
|---|
| 302 | self.__saturate = bound |
|---|
| 303 | |
|---|
| 304 | def gens(self): |
|---|
| 305 | """ |
|---|
| 306 | Return a list of the generators for the Mordell-Weil group. |
|---|
| 307 | """ |
|---|
| 308 | self.saturate() |
|---|
| 309 | return eval(self.__two_descent_data().getbasis().replace(":",",")) |
|---|
| 310 | |
|---|
| 311 | def certain(self): |
|---|
| 312 | r""" |
|---|
| 313 | True if the last \method{two_descent} call provably correctly |
|---|
| 314 | computed the rank. If \method{two_descent} hasn't been |
|---|
| 315 | called, then it is first called by \method{certain} |
|---|
| 316 | using the default parameters. |
|---|
| 317 | |
|---|
| 318 | EXAMPLES: |
|---|
| 319 | A $2$-descent does not determine $E(\Q)$ with certainty |
|---|
| 320 | for the curve $y^2 + y = x^3 - x^2 - 120x - 2183$. |
|---|
| 321 | |
|---|
| 322 | sage: E = mwrank_EllipticCurve([0, -1, 1, -120, -2183]) |
|---|
| 323 | sage: E.two_descent(False) |
|---|
| 324 | ... |
|---|
| 325 | sage: E.certain() |
|---|
| 326 | False |
|---|
| 327 | sage: E.rank() |
|---|
| 328 | 0 |
|---|
| 329 | |
|---|
| 330 | The rank of $E$is actually 0 (as one could see by computing |
|---|
| 331 | the L-function), but $\Sha$ has order 4 and the $2$-torsion is |
|---|
| 332 | trivial, so mwrank does not conclusively determine the rank. |
|---|
| 333 | |
|---|
| 334 | sage: E.selmer_rank_bound() |
|---|
| 335 | 2 |
|---|
| 336 | """ |
|---|
| 337 | return bool(self.__two_descent_data().getcertain()) |
|---|
| 338 | |
|---|
| 339 | #def fullmw(self): |
|---|
| 340 | # return self.__two_descent_data().getfullmw() |
|---|
| 341 | |
|---|
| 342 | def CPS_height_bound(self): |
|---|
| 343 | r""" |
|---|
| 344 | Return the Cremona-Prickett-Siksek height bound. This is a |
|---|
| 345 | floating point number $B$ such that if $P$ is a point on the curve, |
|---|
| 346 | then the naive logarithmetic height of $P$ is off from the |
|---|
| 347 | canonical height by at most $B$. |
|---|
| 348 | |
|---|
| 349 | \begin{notice} |
|---|
| 350 | We assume the model is minimal! |
|---|
| 351 | \end{notice} |
|---|
| 352 | """ |
|---|
| 353 | return self.__curve.cps_bound() |
|---|
| 354 | |
|---|
| 355 | def silverman_bound(self): |
|---|
| 356 | r""" |
|---|
| 357 | Return the Silverman height bound. This is a number $B$ such |
|---|
| 358 | that if $P$ is a point on the curve, then the naive |
|---|
| 359 | logarithmetic height of $P$ is off from the canonical height by |
|---|
| 360 | at most $B$. |
|---|
| 361 | |
|---|
| 362 | \begin{notice} |
|---|
| 363 | We assume the model is minimal! |
|---|
| 364 | \end{notice} |
|---|
| 365 | """ |
|---|
| 366 | return self.__curve.silverman_bound() |
|---|
| 367 | |
|---|
| 368 | |
|---|
| 369 | class mwrank_MordellWeil(SageObject): |
|---|
| 370 | r""" |
|---|
| 371 | The \class{mwrank_MordellWeil} class represents a subgroup of a |
|---|
| 372 | Mordell-Weil group. Use this class to saturate a specified list |
|---|
| 373 | of points on an \class{mwrank_EllipticCurve}, or to search for |
|---|
| 374 | points up to some bound. |
|---|
| 375 | """ |
|---|
| 376 | def __init__(self, curve, verbose=True, pp=1, maxr=999): |
|---|
| 377 | r""" |
|---|
| 378 | Create a \class{mwrank_MordellWeil} instance. |
|---|
| 379 | |
|---|
| 380 | INPUT: |
|---|
| 381 | curve -- \class{mwrank_EllipticCurve} instance |
|---|
| 382 | verbose -- bool |
|---|
| 383 | pp -- int |
|---|
| 384 | maxr -- int |
|---|
| 385 | """ |
|---|
| 386 | if not isinstance(curve, mwrank_EllipticCurve): |
|---|
| 387 | raise TypeError, "curve (=%s) must be an mwrank_EllipticCurve"%curve |
|---|
| 388 | self.__curve = curve |
|---|
| 389 | self.__verbose = verbose |
|---|
| 390 | self.__pp = pp |
|---|
| 391 | self.__maxr = maxr |
|---|
| 392 | if verbose: |
|---|
| 393 | verb = 1 |
|---|
| 394 | else: |
|---|
| 395 | verb = 0 |
|---|
| 396 | from sage.libs.mwrank.mwrank import _mw # import here to save time |
|---|
| 397 | self.__mw = _mw(curve._curve_data(), verb, pp, maxr) |
|---|
| 398 | |
|---|
| 399 | def __reduce__(self): |
|---|
| 400 | return mwrank_MordellWeil, (self.__curve, self.__verbose, self.__pp, self.__maxr) |
|---|
| 401 | |
|---|
| 402 | def __repr__(self): |
|---|
| 403 | return "Subgroup of Mordell Weil group: %s"%self.__mw |
|---|
| 404 | |
|---|
| 405 | def process(self, v, sat=0): |
|---|
| 406 | """ |
|---|
| 407 | This function allows one to add points to a mwrank_MordellWeil object. |
|---|
| 408 | |
|---|
| 409 | Process points in the list v, with saturation at primes up to |
|---|
| 410 | sat. If sat = 0 (the default), then saturate at all primes. |
|---|
| 411 | |
|---|
| 412 | INPUT: |
|---|
| 413 | |
|---|
| 414 | v -- a point (3-tuple of ints), or a |
|---|
| 415 | list of 3-tuples of integers, which define points on the curve. |
|---|
| 416 | |
|---|
| 417 | sat -- int, saturate at primes up to sat, or at all primes if sat=0. |
|---|
| 418 | |
|---|
| 419 | """ |
|---|
| 420 | if not isinstance(v, list): |
|---|
| 421 | raise TypeError, "v (=%s) must be a list"%v |
|---|
| 422 | sat = int(sat) |
|---|
| 423 | for P in v: |
|---|
| 424 | if not isinstance(P, (list,tuple)) or len(P) != 3: |
|---|
| 425 | raise TypeError, "v (=%s) must be a list of 3-tuples of ints"%v |
|---|
| 426 | self.__mw.process(P, sat) |
|---|
| 427 | |
|---|
| 428 | def regulator(self): |
|---|
| 429 | """ |
|---|
| 430 | Return the regulator of the points in this subgroup of |
|---|
| 431 | the Mordell-Weil group. |
|---|
| 432 | """ |
|---|
| 433 | return self.__mw.regulator() |
|---|
| 434 | |
|---|
| 435 | def rank(self): |
|---|
| 436 | """ |
|---|
| 437 | Return the rank of this subgroup of the Mordell-Weil group. |
|---|
| 438 | """ |
|---|
| 439 | return self.__mw.getrank() |
|---|
| 440 | |
|---|
| 441 | def saturate(self, max_prime=-1, odd_primes_only=False): |
|---|
| 442 | r""" |
|---|
| 443 | Saturate this subgroup of the Mordell-Weil group. |
|---|
| 444 | |
|---|
| 445 | INPUT: |
|---|
| 446 | max_prime (int) -- (default: 97), saturation is performed |
|---|
| 447 | for all primes up to max_prime |
|---|
| 448 | |
|---|
| 449 | odd_primes_only (bool) -- only do saturation at odd primes |
|---|
| 450 | |
|---|
| 451 | OUTPUT: |
|---|
| 452 | ok (bool) -- True if and only if the saturation |
|---|
| 453 | is provably correct at \emph{all} primes. |
|---|
| 454 | index (int) -- The index of the group generated by |
|---|
| 455 | points in their saturation |
|---|
| 456 | saturation (list) -- list of points that form |
|---|
| 457 | a basis for the saturation |
|---|
| 458 | |
|---|
| 459 | \begin{notice} |
|---|
| 460 | We emphasize that if this function returns True as the first |
|---|
| 461 | return argument, then the points it found are saturated at |
|---|
| 462 | \emph{all} primes, i.e., saturating at the primes up to |
|---|
| 463 | \code{max_prime} are sufficient to saturate at all primes. |
|---|
| 464 | Note that the function might not have needed to saturate at |
|---|
| 465 | all primes up to \code{max_prime}. |
|---|
| 466 | It has worked out what prime you need to saturate up to, |
|---|
| 467 | and that prime is $\leq $ \code{max_prime}. |
|---|
| 468 | |
|---|
| 469 | \end{notice} |
|---|
| 470 | |
|---|
| 471 | \begin{notice} |
|---|
| 472 | Currently (July 2005), this does not remember the result of |
|---|
| 473 | calling search. So calling search up to height 20 then |
|---|
| 474 | calling saturate results in another search up to height 18. |
|---|
| 475 | \end{notice} |
|---|
| 476 | |
|---|
| 477 | |
|---|
| 478 | """ |
|---|
| 479 | ok, index, unsat = self.__mw.saturate(int(max_prime), odd_primes_only) |
|---|
| 480 | return bool(ok), str(index), unsat |
|---|
| 481 | |
|---|
| 482 | def search(self, height_limit=18, verbose=False): |
|---|
| 483 | r""" |
|---|
| 484 | Search for new points, and add them to this subgroup of the |
|---|
| 485 | Mordell-Weil group. |
|---|
| 486 | |
|---|
| 487 | INPUT: |
|---|
| 488 | height_limit -- float (default: 18) search up to |
|---|
| 489 | this logarithmetic height. |
|---|
| 490 | On 32-bit machines, h_lim MUST be < 21.48 else |
|---|
| 491 | exp(h_lim)>2^31 and overflows. |
|---|
| 492 | """ |
|---|
| 493 | # On 64-bit machines, h_lim must be < 43.668, but |
|---|
| 494 | # it's unlikely (in 2005) that you would ever |
|---|
| 495 | # search higher than 21. |
|---|
| 496 | height_limit = float(height_limit) |
|---|
| 497 | if height_limit >= 21.4: |
|---|
| 498 | raise ValueError, "The height limit must be < 21.4." |
|---|
| 499 | |
|---|
| 500 | moduli_option = 0 # Use Stoll's sieving program... see strategies in ratpoints-1.4.c |
|---|
| 501 | |
|---|
| 502 | ## moduli_option -- int (default: 0); if > 0; a flag used to determine |
|---|
| 503 | ## the moduli that are used in sieving |
|---|
| 504 | ## 1 -- first 10 odd primes; the first one you |
|---|
| 505 | ## would think of. |
|---|
| 506 | ## 2 -- three composites; $2^6\cdot 3^4$, ... TODO |
|---|
| 507 | ## (from German mathematician J. Gebel; |
|---|
| 508 | ## personal conversation about SIMATH) |
|---|
| 509 | ## 3 -- nine prime powers; $2^5, \ldots$; |
|---|
| 510 | ## like 1 but includes powers of small primes |
|---|
| 511 | ## TODO: Extract the meaning from mwprocs.cc; line 776 etc. |
|---|
| 512 | |
|---|
| 513 | verbose == bool(verbose) |
|---|
| 514 | self.__mw.search(height_limit, moduli_option, verbose) |
|---|
| 515 | |
|---|
| 516 | def points(self): |
|---|
| 517 | """ |
|---|
| 518 | Return a list of the generating points in this Mordell-Weil |
|---|
| 519 | group. |
|---|
| 520 | """ |
|---|
| 521 | return eval(self.__mw.getbasis().replace(":",",")) |
|---|
| 522 | |
|---|
| 523 | |
|---|