r"""
Pexpect-based interface to Julia
EXAMPLES::
TODO
AUTHORS:
-- William Stein (2014-10-26)
"""
import os, pexpect, random, string
from uuid import uuid4
def uuid():
return str(uuid4())
from sage.interfaces.expect import Expect, ExpectElement, ExpectFunction, FunctionElement, gc_disabled
from sage.structure.element import RingElement
PROMPT_LENGTH = 16
class Julia(Expect):
def __init__(self,
maxread = 100000,
script_subdirectory = None,
logfile = None,
server = None,
server_tmpdir = None):
"""
Pexpect-based interface to Julia
"""
self._prompt = 'julia>'
Expect.__init__(self,
name = 'Julia',
prompt = self._prompt,
command = "julia",
maxread = maxread,
server = server,
server_tmpdir = server_tmpdir,
script_subdirectory = script_subdirectory,
restart_on_ctrlc = False,
verbose_start = False,
logfile = logfile)
self.__seq = 0
self.__in_seq = 1
def _start(self):
"""
"""
pexpect_env = dict(os.environ)
pexpect_env['TERM'] = 'vt100'
self._expect = pexpect.spawn(self._Expect__command, logfile=self._Expect__logfile, env=pexpect_env)
self._expect.delaybeforesend = 0
self._expect.expect("\x1b\[0Kjulia>")
def eval(self, code, **ignored):
"""
"""
if isinstance(code, unicode):
code = code.encode('utf8')
START = "\x1b[?2004l\x1b[0m"
END = "\x1b[0G\x1b[0K\x1b[0G\x1b[0Kjulia> "
if not self._expect:
self._start()
with gc_disabled():
s = self._expect
u = uuid()
line = code+'\n\n\n\n\n__ans__=ans;println("%s");ans=__ans__;\n'%u
s.send(line)
s.expect(u)
result = s.before
self._last_result = result
s.expect(u)
self._last_result += s.before
s.expect(u)
self._last_result += s.before
i = result.rfind(START)
if i == -1:
return result
result = result[len(START)+i:]
i = result.find(END)
if i == -1:
return result
result = result[:i].rstrip()
if result.startswith("ERROR:"):
julia_error = result.replace("in anonymous at no file",'')
raise RuntimeError(julia_error)
return result
def _an_element_impl(self):
"""
EXAMPLES::
sage: julia._an_element_impl()
0
"""
return self(0)
def set(self, var, value):
"""
Set the variable var to the given value.
EXAMPLES::
sage: julia.set('x', '2')
sage: julia.get('x')
'2'
TEST:
It must also be possible to eval the variable by name::
sage: julia.eval('x')
'2'
"""
cmd = '%s=%s;'%(var, value)
out = self.eval(cmd)
if '***' in out:
raise TypeError("Error executing code in Sage\nCODE:\n\t%s\nSAGE ERROR:\n\t%s"%(cmd, out))
def get(self, var):
"""
EXAMPLES::
sage: julia.set('x', '2')
sage: julia.get('x')
'2'
"""
out = self.eval(var)
return out
def _repr_(self):
return 'Julia Interpreter'
def __reduce__(self):
"""
EXAMPLES::
sage: julia.__reduce__()
"""
return reduce_load_Julia, tuple([])
def _function_class(self):
"""
EXAMPLES::
sage: julia._function_class()
<class 'sage.interfaces.julia.JuliaFunction'>
"""
return JuliaFunction
def _quit_string(self):
"""
EXAMPLES::
sage: julia._quit_string()
'quit()'
sage: l = Julia()
sage: l._start()
sage: l.quit()
sage: l.is_running()
False
"""
return 'quit()'
def _read_in_file_command(self, filename):
"""
EXAMPLES::
sage: julia._read_in_file_command(tmp_filename()) # TODO
"""
def trait_names(self):
"""
EXAMPLES::
sage: julia.trait_names()
['ANY', ..., 'zip']
"""
s = julia.eval('\t\t')
v = []
for x in s.split('\x1b[')[:-1]:
i = x.find("G")
if i != -1:
c = x[i+1:].strip()
if c and c.isalnum():
v.append(c)
v.sort()
return v
def kill(self, var):
"""
EXAMPLES::
sage: julia.kill('x')
Traceback (most recent call last):
...
NotImplementedError
"""
raise NotImplementedError
def console(self):
"""
Spawn a new Julia command-line session.
EXAMPLES::
sage: julia.console() #not tested
...
"""
julia_console()
def version(self):
"""
Returns the version of Julia being used.
EXAMPLES::
sage: julia.version()
'Version information is given by julia.console().'
"""
return self.eval("versioninfo()")
def _object_class(self):
"""
EXAMPLES::
sage: julia._object_class()
<class 'sage.interfaces.julia.JuliaElement'>
"""
return JuliaElement
def _function_class(self):
"""
EXAMPLES::
sage: julia._function_class()
<class 'sage.interfaces.julia.JuliaFunction'>
"""
return JuliaFunction
def _function_element_class(self):
"""
EXAMPLES::
sage: julia._function_element_class()
<class 'sage.interfaces.julia.JuliaFunctionElement'>
"""
return JuliaFunctionElement
def _true_symbol(self):
"""
EXAMPLES::
sage: julia._true_symbol()
'true'
"""
return 'true'
def _false_symbol(self):
"""
EXAMPLES::
sage: julia._false_symbol()
'false'
"""
return 'false'
def _equality_symbol(self):
"""
"""
return "=="
def help(self, command):
"""
EXAMPLES::
"""
if '"' in command:
raise ValueError('quote in command name')
return self.eval('help("%s")'%command)
def function_call(self, function, args=None, kwds=None):
"""
EXAMPLES::
sage: julia.function_call('sin', ['2'])
0.9092974
sage: julia.sin(2)
0.9092974
"""
args, kwds = self._convert_args_kwds(args, kwds)
self._check_valid_function_name(function)
return self.new("%s(%s)"%(function, ",".join([s.name() for s in args])))
class JuliaElement(ExpectElement):
def trait_names(self):
return self._check_valid().trait_names()
def __cmp__(self, other):
"""
EXAMPLES::
sage: one = julia(1); two = julia(2)
sage: one == one
True
sage: one != two
True
sage: one < two
True
sage: two > one
True
sage: one < 1
False
sage: two == 2
True
"""
P = self._check_valid()
if not hasattr(other, 'parent') or P is not other.parent():
other = P(other)
if P.eval('%s == %s'%(self.name(), other.name())) == P._true_symbol():
return 0
elif P.eval('%s < %s'%(self.name(), other.name())) == P._true_symbol():
return -1
else:
return 1
def bool(self):
"""
EXAMPLES::
sage: julia(2).bool()
True
sage: julia(0).bool()
False
sage: bool(julia(2))
True
"""
P = self._check_valid()
return P.eval("bool(%s)"%self.name()) == P._true_symbol()
def _add_(self, right):
"""
EXAMPLES::
sage: a = julia(1); b = julia(2)
sage: a + b
3
"""
P = self._check_valid()
return P.new('%s + %s'%(self._name, right._name))
def _sub_(self, right):
"""
EXAMPLES::
sage: a = julia(1); b = julia(2)
sage: a - b
-1
"""
P = self._check_valid()
return P.new('%s - %s'%(self._name, right._name))
def _mul_(self, right):
"""
EXAMPLES::
sage: a = julia(1); b = julia(2)
sage: a * b
2
"""
P = self._check_valid()
return P.new('%s * %s'%(self._name, right._name))
def _div_(self, right):
"""
EXAMPLES::
sage: a = julia(1); b = julia(2)
sage: a / b
1/2
"""
P = self._check_valid()
return P.new('%s / %s'%(self._name, right._name))
def __pow__(self, n):
"""
EXAMPLES::
sage: a = julia(3)
sage: a^3
27
"""
P = self._check_valid()
right = P(n)
return P.new('%s ^ %s'%(self._name, right._name))
class JuliaFunctionElement(FunctionElement):
def _sage_doc_(self):
"""
EXAMPLES::
sage: two = julia(2)
sage: two.sin._sage_doc_()
'Base.sin(x)\r\n\r\n Compute sine of "x", where "x" is in radians'
"""
M = self._obj.parent()
return M.help(self._name)
class JuliaFunction(ExpectFunction):
def _sage_doc_(self):
"""
EXAMPLES::
sage: julia.sin._sage_doc_()
Traceback (most recent call last):
...
NotImplementedError
"""
M = self._parent
return M.help(self._name)
def is_JuliaElement(x):
"""
EXAMPLES::
sage: from sage.interfaces.julia import is_JuliaElement
sage: is_JuliaElement(julia(2))
True
sage: is_JuliaElement(2)
False
"""
return isinstance(x, JuliaElement)
julia = Julia()
def reduce_load_Julia():
"""
EXAMPLES::
sage: from sage.interfaces.julia import reduce_load_Julia
sage: reduce_load_Julia()
Julia Interpreter
"""
return julia
import os
def julia_console():
"""
Spawn a new Julia command-line session.
EXAMPLES::
sage: julia.console() #not tested
...
"""
os.system('julia')