sage: 8.5.beta0 -> 8.5.beta1
This commit is contained in:
parent
6138f5d5eb
commit
8e7da1b8a4
763
pkgs/applications/science/math/sage/patches/r-rpy.patch
Normal file
763
pkgs/applications/science/math/sage/patches/r-rpy.patch
Normal file
@ -0,0 +1,763 @@
|
|||||||
|
diff --git a/src/sage/doctest/test.py b/src/sage/doctest/test.py
|
||||||
|
index 2f4f74cfc2..c6c1bf9194 100644
|
||||||
|
--- a/src/sage/doctest/test.py
|
||||||
|
+++ b/src/sage/doctest/test.py
|
||||||
|
@@ -500,12 +500,13 @@ Test ``atexit`` support in the doctesting framework::
|
||||||
|
....: pass
|
||||||
|
|
||||||
|
Test the ``--memlimit`` option and ``# optional - memlimit``
|
||||||
|
-(but only on Linux)::
|
||||||
|
+(but only on Linux). If this test fails, the memory needed to
|
||||||
|
+run it may have increased. Try increasing the limit. ::
|
||||||
|
|
||||||
|
sage: from platform import system
|
||||||
|
sage: ok = True
|
||||||
|
sage: if system() == "Linux":
|
||||||
|
- ....: P = subprocess.Popen(["sage", "-t", "--warn-long", "0", "--memlimit=2000", "memlimit.rst"], stdout=subprocess.PIPE, **kwds)
|
||||||
|
+ ....: P = subprocess.Popen(["sage", "-t", "--warn-long", "0", "--memlimit=2100", "memlimit.rst"], stdout=subprocess.PIPE, **kwds)
|
||||||
|
....: out, err = P.communicate()
|
||||||
|
....: ok = ("MemoryError: failed to allocate" in out)
|
||||||
|
sage: ok or out
|
||||||
|
diff --git a/src/sage/interfaces/expect.py b/src/sage/interfaces/expect.py
|
||||||
|
index 51a37496c2..ba982f25f7 100644
|
||||||
|
--- a/src/sage/interfaces/expect.py
|
||||||
|
+++ b/src/sage/interfaces/expect.py
|
||||||
|
@@ -1122,10 +1122,15 @@ If this all works, you can then make calls like:
|
||||||
|
|
||||||
|
EXAMPLES:
|
||||||
|
|
||||||
|
- We test all of this using the R interface. First we put
|
||||||
|
+ We test all of this using the Singular interface. First we put
|
||||||
|
10 + 15 in the input stream::
|
||||||
|
|
||||||
|
- sage: r._sendstr('abc <- 10 +15;\n')
|
||||||
|
+ sage: singular._sendstr('def abc = 10 + 15;\n')
|
||||||
|
+
|
||||||
|
+ Then we tell singular to print 10, which is an arbitrary number
|
||||||
|
+ different from the expected result 35.
|
||||||
|
+
|
||||||
|
+ sage: singular._sendstr('10;\n')
|
||||||
|
|
||||||
|
Here an exception is raised because 25 hasn't appeared yet in the
|
||||||
|
output stream. The key thing is that this doesn't lock, but instead
|
||||||
|
@@ -1135,7 +1140,7 @@ If this all works, you can then make calls like:
|
||||||
|
|
||||||
|
sage: t = walltime()
|
||||||
|
sage: try:
|
||||||
|
- ....: r._expect_expr('25', timeout=0.5)
|
||||||
|
+ ....: singular._expect_expr('25', timeout=0.5)
|
||||||
|
....: except Exception:
|
||||||
|
....: print('Did not get expression')
|
||||||
|
Did not get expression
|
||||||
|
@@ -1145,24 +1150,24 @@ If this all works, you can then make calls like:
|
||||||
|
sage: w = walltime(t); w > 0.4 and w < 10
|
||||||
|
True
|
||||||
|
|
||||||
|
- We tell R to print abc, which equals 25.
|
||||||
|
+ We tell Singular to print abc, which equals 25.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
- sage: r._sendstr('abc;\n')
|
||||||
|
+ sage: singular._sendstr('abc;\n')
|
||||||
|
|
||||||
|
Now 25 is in the output stream, so we can wait for it.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
- sage: r._expect_expr('25')
|
||||||
|
+ sage: singular._expect_expr('25')
|
||||||
|
|
||||||
|
- This gives us everything before the 25.
|
||||||
|
+ This gives us everything before the 25, including the 10 we printed earlier.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
- sage: r._expect.before.decode('ascii')
|
||||||
|
- u'...abc;\r\n[1] '
|
||||||
|
+ sage: singular._expect.before.decode('ascii')
|
||||||
|
+ u'...10\r\n> '
|
||||||
|
|
||||||
|
We test interrupting ``_expect_expr`` using the GP interface,
|
||||||
|
see :trac:`6661`. Unfortunately, this test doesn't work reliably using
|
||||||
|
@@ -1203,14 +1208,7 @@ If this all works, you can then make calls like:
|
||||||
|
|
||||||
|
- ``string`` -- a string
|
||||||
|
|
||||||
|
- EXAMPLES: We illustrate this function using the R interface::
|
||||||
|
-
|
||||||
|
- sage: r._synchronize()
|
||||||
|
- sage: r._sendstr('a <- 10;\n')
|
||||||
|
- sage: r.eval('a')
|
||||||
|
- '[1] 10'
|
||||||
|
-
|
||||||
|
- We illustrate using the singular interface::
|
||||||
|
+ EXAMPLES: We illustrate this function using the Singular interface::
|
||||||
|
|
||||||
|
sage: singular._synchronize()
|
||||||
|
sage: singular._sendstr('int i = 5;')
|
||||||
|
@@ -1260,7 +1258,7 @@ If this all works, you can then make calls like:
|
||||||
|
|
||||||
|
EXAMPLES: We observe nothing, just as it should be::
|
||||||
|
|
||||||
|
- sage: r._synchronize()
|
||||||
|
+ sage: singular._synchronize()
|
||||||
|
|
||||||
|
TESTS:
|
||||||
|
|
||||||
|
diff --git a/src/sage/interfaces/gp.py b/src/sage/interfaces/gp.py
|
||||||
|
index 86f401571a..f3c6120ddc 100644
|
||||||
|
--- a/src/sage/interfaces/gp.py
|
||||||
|
+++ b/src/sage/interfaces/gp.py
|
||||||
|
@@ -254,6 +254,7 @@ class Gp(ExtraTabCompletion, Expect):
|
||||||
|
self._eval_line('default(help, "gphelp -detex");')
|
||||||
|
# logfile disabled since Expect already logs
|
||||||
|
self._eval_line('default(log,0);')
|
||||||
|
+ self._eval_line("default(nbthreads,1);")
|
||||||
|
# set random seed
|
||||||
|
self.set_seed(self._seed)
|
||||||
|
|
||||||
|
diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py
|
||||||
|
index 5c75459903..06974a2324 100644
|
||||||
|
--- a/src/sage/interfaces/r.py
|
||||||
|
+++ b/src/sage/interfaces/r.py
|
||||||
|
@@ -268,17 +268,17 @@ from __future__ import print_function, absolute_import
|
||||||
|
from six.moves import range
|
||||||
|
import six
|
||||||
|
|
||||||
|
-from .expect import Expect, ExpectElement, ExpectFunction, FunctionElement
|
||||||
|
+from .interface import Interface, InterfaceElement, InterfaceFunction, InterfaceFunctionElement
|
||||||
|
from sage.env import DOT_SAGE
|
||||||
|
import re
|
||||||
|
-import sage.rings.integer
|
||||||
|
from sage.structure.element import parent
|
||||||
|
from sage.interfaces.tab_completion import ExtraTabCompletion
|
||||||
|
from sage.docs.instancedoc import instancedoc
|
||||||
|
+from rpy2 import robjects
|
||||||
|
+from rpy2.robjects import packages
|
||||||
|
+from rpy2.robjects.conversion import localconverter
|
||||||
|
|
||||||
|
COMMANDS_CACHE = '%s/r_commandlist.sobj'%DOT_SAGE
|
||||||
|
-PROMPT = '__SAGE__R__PROMPT__> '
|
||||||
|
-prompt_re = re.compile("^>", re.M)
|
||||||
|
|
||||||
|
#there is a mirror network, but lets take #1 for now
|
||||||
|
RRepositoryURL = "http://cran.r-project.org/"
|
||||||
|
@@ -288,12 +288,156 @@ RFilteredPackages = ['.GlobalEnv']
|
||||||
|
# but package:base should cover this. i think.
|
||||||
|
RBaseCommands = ['c', "NULL", "NA", "True", "False", "Inf", "NaN"]
|
||||||
|
|
||||||
|
-class R(ExtraTabCompletion, Expect):
|
||||||
|
+def _setup_r_to_sage_converter():
|
||||||
|
+ """
|
||||||
|
+ Set up a the converter used to convert from rpy2's
|
||||||
|
+ representation of R objects to the one sage expects.
|
||||||
|
+
|
||||||
|
+ EXAMPLES::
|
||||||
|
+
|
||||||
|
+ Test
|
||||||
|
+
|
||||||
|
+ Simple numeric values are represented as vectors in R. So `1` would actually
|
||||||
|
+ be an array of length 1. We convert all vectors of length 1 to simple values,
|
||||||
|
+ whether or not they "originally" were simple values or not:
|
||||||
|
+
|
||||||
|
+ sage: r([42]).sage()
|
||||||
|
+ 42
|
||||||
|
+
|
||||||
|
+ sage: r(42).sage()
|
||||||
|
+ 42
|
||||||
|
+
|
||||||
|
+ sage: r('c("foo")').sage()
|
||||||
|
+ 'foo'
|
||||||
|
+
|
||||||
|
+ Arrays of length greater than one are treated normally:
|
||||||
|
+
|
||||||
|
+ sage: r([42, 43]).sage()
|
||||||
|
+ [42, 43]
|
||||||
|
+
|
||||||
|
+ We also convert all numeric values to integers if that is possible without
|
||||||
|
+ loss of precision:
|
||||||
|
+
|
||||||
|
+ sage: type(r([1.0]).sage()) == int
|
||||||
|
+ True
|
||||||
|
+
|
||||||
|
+ sage: r([1.0, 42.5]).sage()
|
||||||
|
+ [1, 42.5]
|
||||||
|
+
|
||||||
|
+ Matrices are converted to sage matrices:
|
||||||
|
+
|
||||||
|
+ sage: r('matrix(c(2,4,3,1,5,7), nrow=2, ncol=3)').sage()
|
||||||
|
+ [2 3 5]
|
||||||
|
+ [4 1 7]
|
||||||
|
+
|
||||||
|
+ More complex r structures are represented by dictionaries:
|
||||||
|
+
|
||||||
|
+ sage: r.summary(1).sage()
|
||||||
|
+ {'DATA': [1, 1, 1, 1, 1, 1],
|
||||||
|
+ '_Names': ['Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.'],
|
||||||
|
+ '_r_class': ['summaryDefault', 'table']}
|
||||||
|
+
|
||||||
|
+ sage: r.options(width="60").sage()
|
||||||
|
+ {'DATA': {'width': 60}, '_Names': 'width'}
|
||||||
|
+
|
||||||
|
+ The conversion can handle "not a number", infintiy, imaginary values and
|
||||||
|
+ missing values:
|
||||||
|
+
|
||||||
|
+ sage: r(-17).sqrt().sage()
|
||||||
|
+ nan
|
||||||
|
+ sage: r('-17+0i').sqrt().sage()
|
||||||
|
+ 4.123105625617661j
|
||||||
|
+ sage: r('NA').sage()
|
||||||
|
+ NA
|
||||||
|
+ sage: inf = r('Inf'); inf.sage()
|
||||||
|
+ inf
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ Character Vectors are represented by regular python arrays:
|
||||||
|
+
|
||||||
|
+ sage: labs = r.paste('c("X","Y")', '1:10', sep='""'); labs.sage()
|
||||||
|
+ ['X1', 'Y2', 'X3', 'Y4', 'X5', 'Y6', 'X7', 'Y8', 'X9', 'Y10']
|
||||||
|
+ """
|
||||||
|
+ from rpy2.rinterface import SexpVector, ListSexpVector, FloatSexpVector
|
||||||
|
+ from rpy2.robjects.conversion import Converter
|
||||||
|
+
|
||||||
|
+ # convert rpy2's representation of r objects to the one sage expects (as defined by the old
|
||||||
|
+ # expect interface)
|
||||||
|
+ cv = Converter('r to sage converter')
|
||||||
|
+
|
||||||
|
+ # fallback
|
||||||
|
+ cv.ri2py.register(object, lambda obj: obj)
|
||||||
|
+
|
||||||
|
+ def float_to_int_if_possible(f):
|
||||||
|
+ # preserve the behaviour of the old r parser, e.g. return 1 instead of 1.0
|
||||||
|
+ return int(f) if isinstance(f, int) or f.is_integer() else round(f, 16) # TODO investigate the rounding
|
||||||
|
+ cv.ri2py.register(float, float_to_int_if_possible)
|
||||||
|
+
|
||||||
|
+ def list_to_singleton_if_possible(l):
|
||||||
|
+ if len(l) == 1:
|
||||||
|
+ return l[0]
|
||||||
|
+ else:
|
||||||
|
+ return l
|
||||||
|
+
|
||||||
|
+ def _vector(vec):
|
||||||
|
+ attrs = vec.list_attrs()
|
||||||
|
+ # Recursive calls have to be made explicitly
|
||||||
|
+ # https://bitbucket.org/rpy2/rpy2/issues/363/custom-converters-are-not-applied
|
||||||
|
+ data = list_to_singleton_if_possible([ cv.ri2py(val) for val in vec ])
|
||||||
|
+ rclass = list(vec.do_slot('class')) if 'class' in attrs else vec.rclass
|
||||||
|
+
|
||||||
|
+ if 'names' in attrs:
|
||||||
|
+ # seperate names and values, call ri2py recursively to convert elements
|
||||||
|
+ names = list_to_singleton_if_possible(list(vec.do_slot('names')))
|
||||||
|
+ return {
|
||||||
|
+ 'DATA': data,
|
||||||
|
+ '_Names': names,
|
||||||
|
+ '_r_class': rclass,
|
||||||
|
+ }
|
||||||
|
+ else:
|
||||||
|
+ # if no names are present, convert to a normal list or a single value
|
||||||
|
+ return data
|
||||||
|
+ cv.ri2py.register(SexpVector, _vector)
|
||||||
|
+
|
||||||
|
+ def _matrix(mat):
|
||||||
|
+ if 'dim' in mat.list_attrs():
|
||||||
|
+ try:
|
||||||
|
+ from sage.matrix.constructor import matrix
|
||||||
|
+ dimensions = mat.do_slot("dim")
|
||||||
|
+ # TODO: higher dimensions? happens often in statistics
|
||||||
|
+ if len(dimensions) != 2:
|
||||||
|
+ raise TypeError
|
||||||
|
+ (nrow, ncol) = dimensions
|
||||||
|
+ #since R does it the other way round, we assign
|
||||||
|
+ #transposed and then transpose the matrix :)
|
||||||
|
+ m = matrix(ncol, nrow, [cv.ri2py(i) for i in mat])
|
||||||
|
+ return m.transpose()
|
||||||
|
+ except TypeError:
|
||||||
|
+ pass
|
||||||
|
+ else:
|
||||||
|
+ return _vector(mat)
|
||||||
|
+ cv.ri2py.register(FloatSexpVector, _matrix)
|
||||||
|
+
|
||||||
|
+ def _list_vector(vec):
|
||||||
|
+ # we have a R list (vector of arbitrary elements)
|
||||||
|
+ attrs = vec.list_attrs()
|
||||||
|
+ names = vec.do_slot('names')
|
||||||
|
+ values = [ cv.ri2py(val) for val in vec ]
|
||||||
|
+ rclass = list(vec.do_slot('class')) if 'class' in attrs else vec.rclass
|
||||||
|
+ data = zip(names, values)
|
||||||
|
+ return {
|
||||||
|
+ 'DATA': dict(data),
|
||||||
|
+ '_Names': cv.ri2py(names),
|
||||||
|
+ # '_r_class': rclass, # FIXME why not?
|
||||||
|
+ };
|
||||||
|
+ cv.ri2py.register(ListSexpVector, _list_vector)
|
||||||
|
+
|
||||||
|
+ return cv
|
||||||
|
+
|
||||||
|
+class R(ExtraTabCompletion, Interface):
|
||||||
|
def __init__(self,
|
||||||
|
- maxread=None, script_subdirectory=None,
|
||||||
|
- server_tmpdir = None,
|
||||||
|
+ maxread=None,
|
||||||
|
logfile=None,
|
||||||
|
- server=None,
|
||||||
|
init_list_length=1024,
|
||||||
|
seed=None):
|
||||||
|
"""
|
||||||
|
@@ -319,46 +463,19 @@ class R(ExtraTabCompletion, Expect):
|
||||||
|
sage: r == loads(dumps(r))
|
||||||
|
True
|
||||||
|
"""
|
||||||
|
- Expect.__init__(self,
|
||||||
|
|
||||||
|
- # The capitalized version of this is used for printing.
|
||||||
|
- name = 'r',
|
||||||
|
+ Interface.__init__(
|
||||||
|
+ self,
|
||||||
|
+ name = 'r', # The capitalized version of this is used for printing.
|
||||||
|
+ )
|
||||||
|
|
||||||
|
- # This is regexp of the input prompt. If you can change
|
||||||
|
- # it to be very obfuscated that would be better. Even
|
||||||
|
- # better is to use sequence numbers.
|
||||||
|
- # options(prompt=\"<prompt> \")
|
||||||
|
- prompt = '> ', #default, later comes the change
|
||||||
|
+ # It would be better to make this an attribute of `R`, but that leads to problems since
|
||||||
|
+ # we override `__getattr__`.
|
||||||
|
+ global _r_to_sage_converter
|
||||||
|
+ _r_to_sage_converter = _setup_r_to_sage_converter()
|
||||||
|
|
||||||
|
- # This is the command that starts up your program
|
||||||
|
- # See #25806 for the --no-readline switch which fixes hangs for some
|
||||||
|
- command = "R --no-readline --vanilla --quiet",
|
||||||
|
-
|
||||||
|
- server=server,
|
||||||
|
- server_tmpdir=server_tmpdir,
|
||||||
|
-
|
||||||
|
- script_subdirectory = script_subdirectory,
|
||||||
|
-
|
||||||
|
- # If this is true, then whenever the user presses Control-C to
|
||||||
|
- # interrupt a calculation, the whole interface is restarted.
|
||||||
|
- restart_on_ctrlc = False,
|
||||||
|
-
|
||||||
|
- # If true, print out a message when starting
|
||||||
|
- # up the command when you first send a command
|
||||||
|
- # to this interface.
|
||||||
|
- verbose_start = False,
|
||||||
|
-
|
||||||
|
- logfile=logfile,
|
||||||
|
-
|
||||||
|
- # If an input is longer than this number of characters, then
|
||||||
|
- # try to switch to outputting to a file.
|
||||||
|
- eval_using_file_cutoff=1024)
|
||||||
|
-
|
||||||
|
- self.__seq = 0
|
||||||
|
- self.__var_store_len = 0
|
||||||
|
- self.__init_list_length = init_list_length
|
||||||
|
- self._prompt_wait = [self._prompt]
|
||||||
|
self._seed = seed
|
||||||
|
+ self._start()
|
||||||
|
|
||||||
|
def set_seed(self, seed=None):
|
||||||
|
"""
|
||||||
|
@@ -391,14 +508,10 @@ class R(ExtraTabCompletion, Expect):
|
||||||
|
sage: r = R()
|
||||||
|
sage: r._start()
|
||||||
|
"""
|
||||||
|
- Expect._start(self)
|
||||||
|
-
|
||||||
|
# width is line width, what's a good value? maximum is 10000!
|
||||||
|
# pager needed to replace help view from less to printout
|
||||||
|
# option device= is for plotting, is set to x11, NULL would be better?
|
||||||
|
- self._change_prompt(PROMPT)
|
||||||
|
- self.eval('options(prompt=\"%s\",continue=\"%s\", width=100,pager="cat",device="png")'%(PROMPT, PROMPT))
|
||||||
|
- self.expect().expect(PROMPT)
|
||||||
|
+ self.eval('options(width=100,pager="cat",device="png")')
|
||||||
|
self.eval('options(repos="%s")'%RRepositoryURL)
|
||||||
|
self.eval('options(CRAN="%s")'%RRepositoryURL)
|
||||||
|
|
||||||
|
@@ -669,22 +782,17 @@ class R(ExtraTabCompletion, Expect):
|
||||||
|
...
|
||||||
|
ImportError: ...
|
||||||
|
"""
|
||||||
|
- ret = self.eval('require("%s")' % library_name)
|
||||||
|
- if six.PY2:
|
||||||
|
- try:
|
||||||
|
- ret = ret.decode('utf-8')
|
||||||
|
- except UnicodeDecodeError:
|
||||||
|
- ret = ret.decode('latin-1')
|
||||||
|
- # try hard to parse the message string in a locale-independent way
|
||||||
|
- if ' library(' in ret: # locale-independent key-word
|
||||||
|
- raise ImportError("%s"%ret)
|
||||||
|
+ if robjects.packages.isinstalled(library_name):
|
||||||
|
+ robjects.packages.importr(library_name)
|
||||||
|
else:
|
||||||
|
- try:
|
||||||
|
- # We need to rebuild keywords!
|
||||||
|
- del self.__tab_completion
|
||||||
|
- except AttributeError:
|
||||||
|
- pass
|
||||||
|
- self._tab_completion(verbose=False, use_disk_cache=False)
|
||||||
|
+ raise ImportError("R library {} not installed".format(library_name))
|
||||||
|
+
|
||||||
|
+ try:
|
||||||
|
+ # We need to rebuild keywords!
|
||||||
|
+ del self.__tab_completion
|
||||||
|
+ except AttributeError:
|
||||||
|
+ pass
|
||||||
|
+ self._tab_completion(verbose=False, use_disk_cache=False)
|
||||||
|
|
||||||
|
require = library #overwrites require
|
||||||
|
|
||||||
|
@@ -789,17 +897,24 @@ class R(ExtraTabCompletion, Expect):
|
||||||
|
EXAMPLES::
|
||||||
|
|
||||||
|
sage: r.help('c')
|
||||||
|
- c package:base R Documentation
|
||||||
|
+ title
|
||||||
|
+ -----
|
||||||
|
+ <BLANKLINE>
|
||||||
|
+ Combine Values into a Vector or List
|
||||||
|
+ <BLANKLINE>
|
||||||
|
+ name
|
||||||
|
+ ----
|
||||||
|
+ <BLANKLINE>
|
||||||
|
+ c
|
||||||
|
...
|
||||||
|
-
|
||||||
|
- .. note::
|
||||||
|
-
|
||||||
|
- This is similar to typing r.command?.
|
||||||
|
"""
|
||||||
|
- s = self.eval('help("%s")'%command).strip() # ?cmd is only an unsafe shortcut
|
||||||
|
+ s = robjects.help.pages(command)[0].to_docstring()
|
||||||
|
+
|
||||||
|
+ # TODO what is this for?
|
||||||
|
import sage.plot.plot
|
||||||
|
if sage.plot.plot.EMBEDDED_MODE:
|
||||||
|
s = s.replace('_\x08','')
|
||||||
|
+
|
||||||
|
return HelpExpression(s)
|
||||||
|
|
||||||
|
def _assign_symbol(self):
|
||||||
|
@@ -914,9 +1029,19 @@ class R(ExtraTabCompletion, Expect):
|
||||||
|
'[1] 5'
|
||||||
|
"""
|
||||||
|
cmd = '%s <- %s'%(var,value)
|
||||||
|
- out = self.eval(cmd)
|
||||||
|
- if out.find("error") != -1:
|
||||||
|
- raise TypeError("Error executing code in R\nCODE:\n\t%s\nR ERROR:\n\t%s"%(cmd, out))
|
||||||
|
+ # FIXME this is how it behaved before since the output was only compared to 'error'
|
||||||
|
+ # while the actual error message started with an upper-case 'Error'.
|
||||||
|
+ # The doctests rely on this when doing `loads(dumps(r('"abc"')))` which will load
|
||||||
|
+ # simply `"abc"` which will then again be set as `sage0 <- abc` (notice the missing
|
||||||
|
+ # quotes). The test will pass anyway because the identifier is reused for some reason.
|
||||||
|
+ # That means `sage0` will already be "abc" from the first `r('"abc"')` call.
|
||||||
|
+ from rpy2.rinterface import RRuntimeWarning, RRuntimeError
|
||||||
|
+ import warnings
|
||||||
|
+ warnings.filterwarnings("ignore", category = RRuntimeWarning)
|
||||||
|
+ try:
|
||||||
|
+ out = self.eval(cmd)
|
||||||
|
+ except RRuntimeError:
|
||||||
|
+ pass
|
||||||
|
|
||||||
|
def get(self, var):
|
||||||
|
"""
|
||||||
|
@@ -934,9 +1059,20 @@ class R(ExtraTabCompletion, Expect):
|
||||||
|
sage: r.get('a')
|
||||||
|
'[1] 2'
|
||||||
|
"""
|
||||||
|
- s = self.eval('%s'%var)
|
||||||
|
- #return self._remove_indices_re.sub("", s).strip()
|
||||||
|
- return s
|
||||||
|
+ # FIXME again, this is how it behaved before. The doctest `L.hom(r, base_morphism=phi)`
|
||||||
|
+ # in sage/rings/function_field/function_field.py relies on this. It somehow ends up
|
||||||
|
+ # requesting a non-existant r object resulting in
|
||||||
|
+ # `RRuntimeError: Error in (function (expr, envir = parent.frame(), enclos = if (is.list(envir) || :
|
||||||
|
+ # object 'sage2' not found`
|
||||||
|
+ # I haven't figured out how or why it does that.
|
||||||
|
+ from rpy2.rinterface import RRuntimeWarning, RRuntimeError
|
||||||
|
+ import warnings
|
||||||
|
+ warnings.filterwarnings("ignore", category = RRuntimeWarning)
|
||||||
|
+ try:
|
||||||
|
+ s = self.eval('%s'%var)
|
||||||
|
+ return s
|
||||||
|
+ except RRuntimeError:
|
||||||
|
+ return ''
|
||||||
|
|
||||||
|
def na(self):
|
||||||
|
"""
|
||||||
|
@@ -966,7 +1102,12 @@ class R(ExtraTabCompletion, Expect):
|
||||||
|
|
||||||
|
sage: dummy = r._tab_completion(use_disk_cache=False) #clean doctest
|
||||||
|
sage: r.completions('tes')
|
||||||
|
- ['testInheritedMethods', 'testPlatformEquivalence', 'testVirtual']
|
||||||
|
+ ['testInheritedMethods',
|
||||||
|
+ 'testInstalledBasic',
|
||||||
|
+ 'testInstalledPackage',
|
||||||
|
+ 'testInstalledPackages',
|
||||||
|
+ 'testPlatformEquivalence',
|
||||||
|
+ 'testVirtual']
|
||||||
|
"""
|
||||||
|
return [name for name in self._tab_completion() if name[:len(s)] == s]
|
||||||
|
|
||||||
|
@@ -986,8 +1127,7 @@ class R(ExtraTabCompletion, Expect):
|
||||||
|
"""
|
||||||
|
v = RBaseCommands
|
||||||
|
|
||||||
|
- ll = self.eval('dput(search())') # loaded libs
|
||||||
|
- ll = self.convert_r_list(ll)
|
||||||
|
+ ll = self('search()')._sage_() # loaded libs
|
||||||
|
|
||||||
|
for lib in ll:
|
||||||
|
if lib in RFilteredPackages:
|
||||||
|
@@ -996,9 +1136,7 @@ class R(ExtraTabCompletion, Expect):
|
||||||
|
if lib.find("package:") != 0:
|
||||||
|
continue #only packages
|
||||||
|
|
||||||
|
- raw = self.eval('dput(objects("%s"))'%lib)
|
||||||
|
- raw = self.convert_r_list(raw)
|
||||||
|
- raw = [x.replace(".","_") for x in raw]
|
||||||
|
+ raw = self('objects("%s")'%lib)._sage_()
|
||||||
|
|
||||||
|
#TODO are there others? many of them are shortcuts or
|
||||||
|
#should be done on another level, like selections in lists
|
||||||
|
@@ -1123,24 +1261,6 @@ class R(ExtraTabCompletion, Expect):
|
||||||
|
RFunction(self, 'plot')(*args, **kwds)
|
||||||
|
return RFunction(self, 'dev.off')()
|
||||||
|
|
||||||
|
- def _strip_prompt(self, code):
|
||||||
|
- """
|
||||||
|
- Remove the standard R prompt from the beginning of lines in code.
|
||||||
|
-
|
||||||
|
- INPUT:
|
||||||
|
-
|
||||||
|
- - code -- a string
|
||||||
|
-
|
||||||
|
- OUTPUT: a string
|
||||||
|
-
|
||||||
|
- EXAMPLES::
|
||||||
|
-
|
||||||
|
- sage: s = '> a <- 2\n> b <- 3'
|
||||||
|
- sage: r._strip_prompt(s)
|
||||||
|
- ' a <- 2\n b <- 3'
|
||||||
|
- """
|
||||||
|
- return prompt_re.sub("", code)
|
||||||
|
-
|
||||||
|
def eval(self, code, globals=None, locals=None, synchronize=True, *args, **kwds):
|
||||||
|
"""
|
||||||
|
Evaluates a command inside the R interpreter and returns the output
|
||||||
|
@@ -1151,9 +1271,8 @@ class R(ExtraTabCompletion, Expect):
|
||||||
|
sage: r.eval('1+1')
|
||||||
|
'[1] 2'
|
||||||
|
"""
|
||||||
|
- # TODO split code at ";" outside of quotes and send them as individual
|
||||||
|
- # lines without ";".
|
||||||
|
- return Expect.eval(self, code, synchronize=synchronize, *args, **kwds)
|
||||||
|
+ return str(robjects.r(code)).rstrip()
|
||||||
|
+
|
||||||
|
|
||||||
|
def _r_to_sage_name(self, s):
|
||||||
|
"""
|
||||||
|
@@ -1255,16 +1374,8 @@ class R(ExtraTabCompletion, Expect):
|
||||||
|
self.execute('setwd(%r)' % dir)
|
||||||
|
|
||||||
|
|
||||||
|
-# patterns for _sage_()
|
||||||
|
-rel_re_param = re.compile(r'\s([\w\.]+)\s=')
|
||||||
|
-rel_re_range = re.compile(r'([\d]+):([\d]+)')
|
||||||
|
-rel_re_integer = re.compile(r'([^\d])([\d]+)L')
|
||||||
|
-rel_re_terms = re.compile(r'terms\s*=\s*(.*?),')
|
||||||
|
-rel_re_call = re.compile(r'call\s*=\s*(.*?)\),')
|
||||||
|
-
|
||||||
|
-
|
||||||
|
@instancedoc
|
||||||
|
-class RElement(ExtraTabCompletion, ExpectElement):
|
||||||
|
+class RElement(ExtraTabCompletion, InterfaceElement):
|
||||||
|
|
||||||
|
def _tab_completion(self):
|
||||||
|
"""
|
||||||
|
@@ -1315,7 +1426,7 @@ class RElement(ExtraTabCompletion, ExpectElement):
|
||||||
|
sage: len(x)
|
||||||
|
5
|
||||||
|
"""
|
||||||
|
- return int(self.parent().eval('dput(length(%s))'%self.name())[:-1] )
|
||||||
|
+ return self.parent()('length(%s)'%self.name())._sage_()
|
||||||
|
|
||||||
|
def __getattr__(self, attrname):
|
||||||
|
"""
|
||||||
|
@@ -1777,95 +1888,9 @@ class RElement(ExtraTabCompletion, ExpectElement):
|
||||||
|
self._check_valid()
|
||||||
|
P = self.parent()
|
||||||
|
|
||||||
|
- # This is the core of the trick: using dput
|
||||||
|
- # dput prints out the internal structure of R's data elements
|
||||||
|
- # options via .deparseOpts(control=...)
|
||||||
|
- # TODO: dput also works with a file, if things get huge!
|
||||||
|
- # [[However, using a file for output often isn't necessary
|
||||||
|
- # since pipe buffering works pretty well for output.
|
||||||
|
- # That said, benchmark this. -- William Stein]]
|
||||||
|
- exp = P.eval('dput(%s)'%self.name())
|
||||||
|
-
|
||||||
|
- # Preprocess expression
|
||||||
|
- # example what this could be:
|
||||||
|
- # structure(list(statistic = structure(0.233549683248457, .Names = "t"),
|
||||||
|
- # parameter = structure(5.58461538461538, .Names = "df"), p.value = 0.823657802106985,
|
||||||
|
- # conf.int = structure(c(-2.41722062247400, 2.91722062247400
|
||||||
|
- # ), conf.level = 0.95), estimate = structure(c(2.75, 2.5), .Names = c("mean of x",
|
||||||
|
- # "mean of y")), null.value = structure(0, .Names = "difference in means"),
|
||||||
|
- # alternative = "two.sided", method = "Welch Two Sample t-test",
|
||||||
|
- # data.name = "c(1, 2, 3, 5) and c(1, 2, 3, 4)"), .Names = c("statistic",
|
||||||
|
- # "parameter", "p.value", "conf.int", "estimate", "null.value",
|
||||||
|
- # "alternative", "method", "data.name"), class = "htest")
|
||||||
|
-
|
||||||
|
- # R's structure (from help):
|
||||||
|
- # structure(.Data, ...)
|
||||||
|
- # .Data: an object which will have various attributes attached to it.
|
||||||
|
- # ...: attributes, specified in 'tag=value' form, which will be
|
||||||
|
- # attached to data.
|
||||||
|
- #For historical reasons (these names are used when deparsing),
|
||||||
|
- # attributes '".Dim"', '".Dimnames"', '".Names"', '".Tsp"' and
|
||||||
|
- # '".Label"' are renamed to '"dim"', '"dimnames"', '"names"',
|
||||||
|
- # '"tsp"' and '"levels"'.
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
- # we want this in a single line
|
||||||
|
- exp.replace('\n','')
|
||||||
|
- exp = "".join(exp.split("\n"))
|
||||||
|
-
|
||||||
|
- # python compatible parameters
|
||||||
|
- exp = rel_re_param.sub(self._subs_dots, exp)
|
||||||
|
-
|
||||||
|
- # Rename class since it is a Python keyword
|
||||||
|
- exp = re.sub(' class = ', ' _r_class = ',exp)
|
||||||
|
-
|
||||||
|
- # Change 'structure' to '_r_structure'
|
||||||
|
- # TODO: check that we are outside of quotes ""
|
||||||
|
- exp = re.sub(r' structure\(', ' _r_structure(', exp)
|
||||||
|
- exp = re.sub(r'^structure\(', '_r_structure(', exp) # special case
|
||||||
|
-
|
||||||
|
- # Change 'list' to '_r_list'
|
||||||
|
- exp = re.sub(r' list\(', ' _r_list(', exp)
|
||||||
|
- exp = re.sub(r'\(list\(', '(_r_list(', exp)
|
||||||
|
-
|
||||||
|
- # Change 'a:b' to 'range(a,b+1)'
|
||||||
|
- exp = rel_re_range.sub(self._subs_range, exp)
|
||||||
|
-
|
||||||
|
- # Change 'dL' to 'Integer(d)'
|
||||||
|
- exp = rel_re_integer.sub(self._subs_integer, exp)
|
||||||
|
-
|
||||||
|
- # Wrap the right hand side of terms = ... in quotes since it
|
||||||
|
- # has a ~ in it.
|
||||||
|
- exp = rel_re_terms.sub(r'terms = "\1",', exp)
|
||||||
|
-
|
||||||
|
-
|
||||||
|
- # Change call = ..., to call = "...",
|
||||||
|
- exp = rel_re_call.sub(r'call = "\1",', exp)
|
||||||
|
-
|
||||||
|
- # seems to work for
|
||||||
|
- # rr = r.summary(r.princomp(r.matrix(r.c(1,2,3,4,3,4,1,2,2),4)))
|
||||||
|
- # rr._sage_()
|
||||||
|
- # but the call expression get's evaluated. why?!? TODO
|
||||||
|
-
|
||||||
|
-
|
||||||
|
- # translation:
|
||||||
|
- # c is an ordered list
|
||||||
|
- # list is a dictionary (where _Names give the entries names.
|
||||||
|
- # map entries in names to (value, name) in each entry?
|
||||||
|
- # structure is .. see above .. structure(DATA,**kw)
|
||||||
|
- # TODO: thinking of just replacing c( with ( to get a long tuple?
|
||||||
|
-
|
||||||
|
-
|
||||||
|
- exp = self._convert_nested_r_list(exp)
|
||||||
|
-
|
||||||
|
- # Set up the globals
|
||||||
|
- globs = {'NA':None, 'NULL':None, 'FALSE':False, 'TRUE':True,
|
||||||
|
- '_r_list':self._r_list, '_r_structure':self._r_structure,
|
||||||
|
- 'Integer':sage.rings.integer.Integer,
|
||||||
|
- 'character':str}
|
||||||
|
-
|
||||||
|
- return eval(exp, globs, globs)
|
||||||
|
+ with localconverter(_r_to_sage_converter) as cv:
|
||||||
|
+ parsed = robjects.r(self.name())
|
||||||
|
+ return parsed
|
||||||
|
|
||||||
|
|
||||||
|
def _latex_(self):
|
||||||
|
@@ -1893,7 +1918,7 @@ class RElement(ExtraTabCompletion, ExpectElement):
|
||||||
|
|
||||||
|
|
||||||
|
@instancedoc
|
||||||
|
-class RFunctionElement(FunctionElement):
|
||||||
|
+class RFunctionElement(InterfaceFunctionElement):
|
||||||
|
def __reduce__(self):
|
||||||
|
"""
|
||||||
|
EXAMPLES::
|
||||||
|
@@ -1917,9 +1942,16 @@ class RFunctionElement(FunctionElement):
|
||||||
|
sage: a = r([1,2,3])
|
||||||
|
sage: length = a.length
|
||||||
|
sage: print(length.__doc__)
|
||||||
|
- length package:base R Documentation
|
||||||
|
- ...
|
||||||
|
+ title
|
||||||
|
+ -----
|
||||||
|
+ <BLANKLINE>
|
||||||
|
+ Length of an Object
|
||||||
|
+ <BLANKLINE>
|
||||||
|
+ name
|
||||||
|
+ ----
|
||||||
|
<BLANKLINE>
|
||||||
|
+ length
|
||||||
|
+ ...
|
||||||
|
"""
|
||||||
|
M = self._obj.parent()
|
||||||
|
return M.help(self._name)
|
||||||
|
@@ -1951,7 +1983,7 @@ class RFunctionElement(FunctionElement):
|
||||||
|
|
||||||
|
|
||||||
|
@instancedoc
|
||||||
|
-class RFunction(ExpectFunction):
|
||||||
|
+class RFunction(InterfaceFunction):
|
||||||
|
def __init__(self, parent, name, r_name=None):
|
||||||
|
"""
|
||||||
|
A Function in the R interface.
|
||||||
|
@@ -2007,9 +2039,16 @@ class RFunction(ExpectFunction):
|
||||||
|
|
||||||
|
sage: length = r.length
|
||||||
|
sage: print(length.__doc__)
|
||||||
|
- length package:base R Documentation
|
||||||
|
- ...
|
||||||
|
+ title
|
||||||
|
+ -----
|
||||||
|
+ <BLANKLINE>
|
||||||
|
+ Length of an Object
|
||||||
|
<BLANKLINE>
|
||||||
|
+ name
|
||||||
|
+ ----
|
||||||
|
+ <BLANKLINE>
|
||||||
|
+ length
|
||||||
|
+ ...
|
||||||
|
"""
|
||||||
|
M = self._parent
|
||||||
|
return M.help(self._name)
|
||||||
|
diff --git a/src/sage/stats/r.py b/src/sage/stats/r.py
|
||||||
|
index cd2002559b..8a2f243901 100644
|
||||||
|
--- a/src/sage/stats/r.py
|
||||||
|
+++ b/src/sage/stats/r.py
|
||||||
|
@@ -39,12 +39,12 @@ def ttest(x,y,conf_level = 0.95, **kw):
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
- sage: a, b = ttest([1,2,3,4,5],[1,2,3,3.5,5.121]); a
|
||||||
|
- 0.941026372027427
|
||||||
|
+ sage: a, b = ttest([1,2,3,4,5],[1,2,3,3.5,5.121]); a # abs tol 1e-12
|
||||||
|
+ 0.9410263720274274
|
||||||
|
"""
|
||||||
|
if len(x) != len(y):
|
||||||
|
raise AttributeError("vectors x and y must be of same length")
|
||||||
|
|
||||||
|
test = myR.t_test(x,y,conf_level = conf_level, **kw)._sage_()
|
||||||
|
- t = test.get('DATA').get('p_value')
|
||||||
|
+ t = test.get('DATA').get('p.value')
|
||||||
|
return t, test
|
@ -9,14 +9,14 @@
|
|||||||
# all get the same sources with the same patches applied.
|
# all get the same sources with the same patches applied.
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
stdenv.mkDerivation rec {
|
||||||
version = "8.5.beta0";
|
version = "8.5.beta1";
|
||||||
name = "sage-src-${version}";
|
name = "sage-src-${version}";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
owner = "sagemath";
|
owner = "sagemath";
|
||||||
repo = "sage";
|
repo = "sage";
|
||||||
rev = version;
|
rev = version;
|
||||||
sha256 = "0kc8fqwz97dwyf4hxz5yr9sjwh5q0jr7a9g1yrdaz66m5805r859";
|
sha256 = "0pxalw7kw8zdnn51yp3s81c6r5m9a500f9yn14s2883jyag9yiz1";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Patches needed because of particularities of nix or the way this is packaged.
|
# Patches needed because of particularities of nix or the way this is packaged.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user