r"""
Interface to mwrank
"""
import os, weakref
from expect import Expect
instances={}
def Mwrank(options="", server=None, server_tmpdir=None):
"""
Create and return an mwrank interpreter, with given options.
INPUT:
- ``options`` - string; passed when starting mwrank.
The format is::
-h help prints this info and quits
-q quiet turns OFF banner display and prompt
-v n verbosity sets verbosity to n (default=1)
-o PARI/GP output turns ON extra PARI/GP short output (default is OFF)
-p n precision sets precision to n decimals (default=15)
-b n quartic bound bound on quartic point search (default=10)
-x n n aux number of aux primes used for sieving (default=6)
-l list turns ON listing of points (default ON unless v=0)
-s selmer_only if set, computes Selmer rank only (default: not set)
-d skip_2nd_descent if set, skips the second descent for curves with 2-torsion (default: not set)
-S n sat_bd upper bound on saturation primes (default=100, -1 for automatic)
.. warning:
Do not use the option "-q" which turns off the prompt.
EXAMPLES::
sage: M = Mwrank('-v 0 -l')
sage: print M('0 0 1 -1 0')
Curve [0,0,1,-1,0] : Rank = 1
Generator 1 is [0:-1:1]; height 0.0511114082399688
Regulator = 0.0511114082399688
"""
global instances
try:
X = instances[options]()
if X:
return X
except KeyError:
pass
X = Mwrank_class(options, server=server,server_tmpdir=server_tmpdir)
instances[options] = weakref.ref(X)
return X
import re
AINVS_LIST_RE = re.compile(r'\[[+-]?(\d+)(,[+-]?\d+){4}]')
AINVS_PLAIN_RE = re.compile(r'^(\s*)([+-]?(\d+)(\s+)){4}([+-]?(\d+))(\s*)$')
def validate_mwrank_input(s):
r"""
Returns a string suitable for mwrank input, or raises an error.
INPUT:
- `s` -- one of the following:
- a list or tuple of 5 integers [a1,a2,a3,a4,a6] or (a1,a2,a3,a4,a6)
- a string of the form '[a1,a2,a3,a4,a6]' or 'a1 a2 a3 a4 a6' where a1, a2, a3, a4, a6 are integers
OUTPUT:
For valid input, a string of the form '[a1,a2,a3,a4,a6]'. For invalid input a ValueError is raised.
EXAMPLES:
A list or tuple of 5 integers::
sage: from sage.interfaces.mwrank import validate_mwrank_input
sage: validate_mwrank_input([1,2,3,4,5])
'[1, 2, 3, 4, 5]'
sage: validate_mwrank_input((-1,2,-3,4,-55))
'[-1, 2, -3, 4, -55]'
sage: validate_mwrank_input([1,2,3,4])
Traceback (most recent call last):
...
ValueError: [1, 2, 3, 4] is not valid input to mwrank (should have 5 entries)
sage: validate_mwrank_input([1,2,3,4,i])
Traceback (most recent call last):
...
ValueError: [1, 2, 3, 4, I] is not valid input to mwrank (entries should be integers)
A string of the form '[a1,a2,a3,a4,a6]' with any whitespace and integers ai::
sage: validate_mwrank_input('0 -1 1 -7 6')
'[0,-1,1,-7,6]'
sage: validate_mwrank_input("[0,-1,1,0,0]\n")
'[0,-1,1,0,0]'
sage: validate_mwrank_input('0\t -1\t 1\t 0\t 0\n')
'[0,-1,1,0,0]'
sage: validate_mwrank_input('0 -1 1 -7 ')
Traceback (most recent call last):
...
ValueError: 0 -1 1 -7 is not valid input to mwrank
"""
if isinstance(s,(list,tuple)):
from sage.rings.all import ZZ
if len(s)!=5:
raise ValueError, "%s is not valid input to mwrank (should have 5 entries)" % s
try:
ai = [ZZ(a) for a in s]
return str(ai)
except (TypeError,ValueError):
raise ValueError, "%s is not valid input to mwrank (entries should be integers)" % s
if isinstance(s,str):
if AINVS_PLAIN_RE.match(s):
ai = s.split()
return "["+",".join(ai)+"]"
ss = s.replace(' ','').replace('\n','').replace('\t','')
if AINVS_LIST_RE.match(ss):
return ss
raise ValueError, "%s is not valid input to mwrank" % s
class Mwrank_class(Expect):
"""
Interface to the Mwrank interpreter.
"""
def __init__(self, options="", server=None,server_tmpdir=None):
"""
INPUT:
- ``options`` - string; passed when starting mwrank.
The format is::
-h help prints this info and quits
-q quiet turns OFF banner display and prompt
-v n verbosity sets verbosity to n (default=1)
-o PARI/GP output turns ON extra PARI/GP short output (default is OFF)
-p n precision sets precision to n decimals (default=15)
-b n quartic bound bound on quartic point search (default=10)
-x n n aux number of aux primes used for sieving (default=6)
-l list turns ON listing of points (default ON unless v=0)
-s selmer_only if set, computes Selmer rank only (default: not set)
-d skip_2nd_descent if set, skips the second descent for curves with 2-torsion (default: not set)
-S n sat_bd upper bound on saturation primes (default=100, -1 for automatic)
.. warning:
Do not use the option "-q" which turns off the prompt.
.. note::
Normally instances of this class would be created by
calling the global function :meth:`Mwrank`.
EXAMPLES::
sage: from sage.interfaces.mwrank import Mwrank_class
sage: M = Mwrank_class('-v 0 -l')
sage: M('0 -1 1 0 0')
'Curve [0,-1,1,0,0] :\tRank = 0\n\n\nRegulator = 1\n'
sage: from sage.interfaces.mwrank import Mwrank_class
sage: TestSuite(Mwrank_class).run()
"""
Expect.__init__(self,
name = 'mwrank',
prompt = 'Enter curve: ',
command = "mwrank %s"%options,
server = server,
server_tmpdir = server_tmpdir,
maxread = 10000,
restart_on_ctrlc = True,
verbose_start = False)
def __getattr__(self, attrname):
"""
Standard function to return an attribute.
EXAMPLES::
sage: mwrank.zzz
Traceback (most recent call last):
...
AttributeError
"""
raise AttributeError
def __reduce__(self):
"""
EXAMPLES::
sage: mwrank.__reduce__()
(<function _reduce_load_mwrank at 0x...>, ())
"""
return _reduce_load_mwrank, tuple([])
def __call__(self, cmd):
"""
Interface to eval method.
INPUT:
- ``cmd`` A string, or Sage object which when converted to a
string gives valid input to ``mwrank``. The conversion is
done by :meth:`validate_mwrank_input`.
EXAMPLES:
The input can be five integers separated by whitespace::
sage: mwrank('0 -1 1 0 0')
'Curve [0,-1,1,0,0] :\tBasic pair: I=16, J=-304\n...'
Or a list or tuple of exactly five integers::
sage: s = mwrank([0,-1,1,0,0])
sage: "Rank = 0" in s and "been determined unconditionally" in s
True
TESTS:
Invalid input raises an ValueError (see #10108); this includes
syntactically valid input which defines a singular curve::
sage: mwrank(10)
Traceback (most recent call last):
...
ValueError: Invalid input: 10 is not valid input to mwrank
sage: mwrank('0 0 0 0 0')
Traceback (most recent call last):
...
ValueError: Invalid input ([0,0,0,0,0]) to mwrank (singular curve)
sage: mwrank('0 0 0 -3 2')
Traceback (most recent call last):
...
ValueError: Invalid input ([0,0,0,-3,2]) to mwrank (singular curve)
"""
try:
s = validate_mwrank_input(cmd)
except ValueError as err:
raise ValueError, "Invalid input: %s" % err
try:
return self.eval(s)
except ValueError as err:
raise ValueError, err
except RuntimeError:
raise ValueError, cmd
def eval(self, s, **kwds):
"""
Return mwrank's output for the given input.
INPUT:
- ``s`` (str) - a Sage object which when converted to a string
gives valid input to ``mwrank``. The conversion is done by
:meth:`validate_mwrank_input`. Possible formats are:
- a string representing exactly five integers separated by
whitespace, for example '1 2 3 4 5'
- a string representing exactly five integers separated by
commas, preceded by '[' and followed by ']' (with
arbitrary whitespace), for example '[1 2 3 4 5]'
- a list or tuple of exactly 5 integers.
.. note::
If a RuntimeError exception is raised, then the mwrank
interface is restarted and the command is retried once.
EXAMPLES::
sage: mwrank.eval('12 3 4 5 6')
'Curve [12,3,4,5,6] :...'
sage: mwrank.eval('[12, 3, 4, 5, 6]')
'Curve [12,3,4,5,6] :...'
sage: mwrank.eval([12, 3, 4, 5, 6])
'Curve [12,3,4,5,6] :...'
sage: mwrank.eval((12, 3, 4, 5, 6))
'Curve [12,3,4,5,6] :...'
"""
if self._expect is not None and not self._expect.isalive():
self._start()
try:
ss = validate_mwrank_input(s)
return Expect.eval(self, ss, **kwds)
except ValueError as err:
raise ValueError, 'Invalid input: %s' % err
except RuntimeError:
raise ValueError, 'Invalid input (%s) to mwrank (singular curve)' % s
def console(self):
"""
Start the mwrank console.
EXAMPLE::
sage: mwrank.console() # not tested: expects console input
Program mwrank: ...
"""
mwrank_console()
def quit(self, verbose=False):
"""
Quit the mwrank process using kill -9 (so exit doesn't dump core, etc.).
INPUT:
- ``verbose`` -- ignored
EXAMPLES::
sage: m = Mwrank()
sage: e = m('1 2 3 4 5')
sage: m.quit()
"""
if self._expect is None: return
try:
os.kill(self._expect.pid, 9)
except OSError:
pass
self._expect = None
mwrank = Mwrank()
def _reduce_load_mwrank():
"""
Return the standard mwrank instance
EXAMPLES::
sage: from sage.interfaces.mwrank import _reduce_load_mwrank
sage: _reduce_load_mwrank()
Mwrank
"""
return mwrank
import os
def mwrank_console():
"""
Start the mwrank console.
EXAMPLE::
sage: mwrank_console() # not tested: expects console input
Program mwrank: ...
"""
os.system('mwrank')