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.
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
version = "8.5.beta0";
|
||||
version = "8.5.beta1";
|
||||
name = "sage-src-${version}";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "sagemath";
|
||||
repo = "sage";
|
||||
rev = version;
|
||||
sha256 = "0kc8fqwz97dwyf4hxz5yr9sjwh5q0jr7a9g1yrdaz66m5805r859";
|
||||
sha256 = "0pxalw7kw8zdnn51yp3s81c6r5m9a500f9yn14s2883jyag9yiz1";
|
||||
};
|
||||
|
||||
# Patches needed because of particularities of nix or the way this is packaged.
|
||||
|
Loading…
Reference in New Issue
Block a user