Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/smc_sagews/smc_sagews/julia.py
Views: 286
1
r"""
2
Pexpect-based interface to Julia
3
4
EXAMPLES::
5
6
TODO
7
8
AUTHORS:
9
-- William Stein (2014-10-26)
10
"""
11
12
##########################################################################
13
#
14
# Copyright (C) 2016, Sagemath Inc.
15
#
16
# Distributed under the terms of the GNU General Public License (GPL)
17
#
18
# http://www.gnu.org/licenses/
19
#
20
##########################################################################
21
22
from __future__ import absolute_import
23
24
import os, pexpect
25
26
import six
27
def is_string(s):
28
return isinstance(s, six.string_types)
29
30
from uuid import uuid4
31
32
33
def uuid():
34
return str(uuid4())
35
36
37
from sage.interfaces.expect import Expect, ExpectElement, ExpectFunction, FunctionElement, gc_disabled
38
from sage.structure.element import RingElement
39
40
PROMPT_LENGTH = 16
41
42
43
class Julia(Expect):
44
def __init__(self,
45
maxread=100000,
46
script_subdirectory=None,
47
logfile=None,
48
server=None,
49
server_tmpdir=None):
50
"""
51
Pexpect-based interface to Julia
52
"""
53
self._prompt = 'julia>'
54
Expect.__init__(self,
55
name='Julia',
56
prompt=self._prompt,
57
command="julia",
58
maxread=maxread,
59
server=server,
60
server_tmpdir=server_tmpdir,
61
script_subdirectory=script_subdirectory,
62
restart_on_ctrlc=False,
63
verbose_start=False,
64
logfile=logfile)
65
66
self.__seq = 0
67
self.__in_seq = 1
68
69
def _start(self):
70
"""
71
"""
72
pexpect_env = dict(os.environ)
73
pexpect_env[
74
'TERM'] = 'vt100' # we *use* the codes. DUH. I should have thought of this 10 years ago...
75
self._expect = pexpect.spawn(self._Expect__command,
76
logfile=self._Expect__logfile,
77
env=pexpect_env)
78
self._expect.delaybeforesend = 0 # not a good idea for a CAS.
79
self._expect.expect("\x1b\[0Kjulia>")
80
81
def eval(self, code, **ignored):
82
"""
83
"""
84
if is_string(code):
85
code = code.encode('utf8')
86
87
START = "\x1b[?2004l\x1b[0m"
88
END = "\x1b[0G\x1b[0K\x1b[0G\x1b[0Kjulia> "
89
if not self._expect:
90
self._start()
91
with gc_disabled():
92
s = self._expect
93
u = uuid()
94
line = code + '\n\n\n\n\n__ans__=ans;println("%s");ans=__ans__;\n' % u
95
s.send(line)
96
s.expect(u)
97
result = s.before
98
self._last_result = result
99
s.expect(u)
100
self._last_result += s.before
101
s.expect(u)
102
self._last_result += s.before
103
i = result.rfind(START)
104
if i == -1:
105
return result
106
result = result[len(START) + i:]
107
i = result.find(END)
108
if i == -1:
109
return result
110
result = result[:i].rstrip()
111
if result.startswith("ERROR:"):
112
julia_error = result.replace("in anonymous at no file", '')
113
raise RuntimeError(julia_error)
114
return result
115
116
def _an_element_impl(self):
117
"""
118
EXAMPLES::
119
120
sage: julia._an_element_impl()
121
0
122
"""
123
return self(0)
124
125
def set(self, var, value):
126
"""
127
Set the variable var to the given value.
128
129
EXAMPLES::
130
131
sage: julia.set('x', '2')
132
sage: julia.get('x')
133
'2'
134
135
TEST:
136
137
It must also be possible to eval the variable by name::
138
139
sage: julia.eval('x')
140
'2'
141
"""
142
cmd = '%s=%s;' % (var, value)
143
out = self.eval(cmd)
144
if '***' in out: #TODO
145
raise TypeError(
146
"Error executing code in Sage\nCODE:\n\t%s\nSAGE ERROR:\n\t%s"
147
% (cmd, out))
148
149
def get(self, var):
150
"""
151
EXAMPLES::
152
153
sage: julia.set('x', '2')
154
sage: julia.get('x')
155
'2'
156
"""
157
out = self.eval(var)
158
return out
159
160
def _repr_(self):
161
return 'Julia Interpreter'
162
163
def __reduce__(self):
164
"""
165
EXAMPLES::
166
167
sage: julia.__reduce__()
168
"""
169
return reduce_load_Julia, tuple([])
170
171
def _quit_string(self):
172
"""
173
EXAMPLES::
174
175
sage: julia._quit_string()
176
'quit()'
177
178
sage: l = Julia()
179
sage: l._start()
180
sage: l.quit()
181
sage: l.is_running()
182
False
183
"""
184
return 'quit()'
185
186
def _read_in_file_command(self, filename):
187
"""
188
EXAMPLES::
189
190
sage: julia._read_in_file_command(tmp_filename()) # TODO
191
"""
192
def trait_names(self):
193
"""
194
EXAMPLES::
195
196
sage: julia.trait_names()
197
['ANY', ..., 'zip']
198
"""
199
s = julia.eval('\t\t')
200
v = []
201
for x in s.split('\x1b[')[:-1]:
202
i = x.find("G")
203
if i != -1:
204
c = x[i + 1:].strip()
205
if c and c.isalnum():
206
v.append(c)
207
v.sort()
208
return v
209
210
def kill(self, var):
211
"""
212
EXAMPLES::
213
214
sage: julia.kill('x')
215
Traceback (most recent call last):
216
...
217
NotImplementedError
218
"""
219
raise NotImplementedError
220
221
def console(self):
222
"""
223
Spawn a new Julia command-line session.
224
225
EXAMPLES::
226
227
sage: julia.console() #not tested
228
...
229
"""
230
julia_console()
231
232
def version(self):
233
"""
234
Returns the version of Julia being used.
235
236
EXAMPLES::
237
238
sage: julia.version()
239
'Version information is given by julia.console().'
240
"""
241
return self.eval("versioninfo()")
242
243
def _object_class(self):
244
"""
245
EXAMPLES::
246
247
sage: julia._object_class()
248
<class 'sage.interfaces.julia.JuliaElement'>
249
"""
250
return JuliaElement
251
252
def _function_class(self):
253
"""
254
EXAMPLES::
255
256
sage: julia._function_class()
257
<class 'sage.interfaces.julia.JuliaFunction'>
258
"""
259
return JuliaFunction
260
261
def _function_element_class(self):
262
"""
263
EXAMPLES::
264
265
sage: julia._function_element_class()
266
<class 'sage.interfaces.julia.JuliaFunctionElement'>
267
"""
268
return JuliaFunctionElement
269
270
def _true_symbol(self):
271
"""
272
EXAMPLES::
273
274
sage: julia._true_symbol()
275
'true'
276
"""
277
return 'true'
278
279
def _false_symbol(self):
280
"""
281
EXAMPLES::
282
283
sage: julia._false_symbol()
284
'false'
285
"""
286
return 'false'
287
288
def _equality_symbol(self):
289
"""
290
"""
291
return "=="
292
293
def help(self, command):
294
"""
295
EXAMPLES::
296
297
298
"""
299
if '"' in command:
300
raise ValueError('quote in command name')
301
return self.eval('help("%s")' % command)
302
303
def function_call(self, function, args=None, kwds=None):
304
"""
305
EXAMPLES::
306
307
sage: julia.function_call('sin', ['2'])
308
0.9092974
309
sage: julia.sin(2)
310
0.9092974
311
"""
312
args, kwds = self._convert_args_kwds(args, kwds)
313
self._check_valid_function_name(function)
314
return self.new("%s(%s)" %
315
(function, ",".join([s.name() for s in args])))
316
317
318
class JuliaElement(ExpectElement):
319
def trait_names(self):
320
# for now... (until I understand types)
321
return self._check_valid().trait_names()
322
323
def __richcmp__(self, other):
324
"""
325
EXAMPLES::
326
327
sage: one = julia(1); two = julia(2)
328
sage: one == one
329
True
330
sage: one != two
331
True
332
sage: one < two
333
True
334
sage: two > one
335
True
336
sage: one < 1
337
False
338
sage: two == 2
339
True
340
341
"""
342
P = self._check_valid()
343
if not hasattr(other, 'parent') or P is not other.parent():
344
other = P(other)
345
346
if P.eval('%s == %s' %
347
(self.name(), other.name())) == P._true_symbol():
348
return 0
349
elif P.eval('%s < %s' %
350
(self.name(), other.name())) == P._true_symbol():
351
return -1
352
else:
353
return 1
354
355
def bool(self):
356
"""
357
EXAMPLES::
358
359
sage: julia(2).bool()
360
True
361
sage: julia(0).bool()
362
False
363
sage: bool(julia(2))
364
True
365
"""
366
P = self._check_valid()
367
return P.eval("bool(%s)" % self.name()) == P._true_symbol()
368
369
def _add_(self, right):
370
"""
371
EXAMPLES::
372
373
sage: a = julia(1); b = julia(2)
374
sage: a + b
375
3
376
"""
377
P = self._check_valid()
378
return P.new('%s + %s' % (self._name, right._name))
379
380
def _sub_(self, right):
381
"""
382
EXAMPLES::
383
384
sage: a = julia(1); b = julia(2)
385
sage: a - b
386
-1
387
"""
388
P = self._check_valid()
389
return P.new('%s - %s' % (self._name, right._name))
390
391
def _mul_(self, right):
392
"""
393
EXAMPLES::
394
395
sage: a = julia(1); b = julia(2)
396
sage: a * b
397
2
398
"""
399
P = self._check_valid()
400
return P.new('%s * %s' % (self._name, right._name))
401
402
def _div_(self, right):
403
"""
404
EXAMPLES::
405
406
sage: a = julia(1); b = julia(2)
407
sage: a / b
408
1/2
409
"""
410
P = self._check_valid()
411
return P.new('%s / %s' % (self._name, right._name))
412
413
def __pow__(self, n):
414
"""
415
EXAMPLES::
416
417
sage: a = julia(3)
418
sage: a^3
419
27
420
"""
421
P = self._check_valid()
422
right = P(n)
423
return P.new('%s ^ %s' % (self._name, right._name))
424
425
426
class JuliaFunctionElement(FunctionElement):
427
def _sage_doc_(self):
428
"""
429
EXAMPLES::
430
431
sage: two = julia(2)
432
sage: two.sin._sage_doc_()
433
'Base.sin(x)\r\n\r\n Compute sine of "x", where "x" is in radians'
434
"""
435
M = self._obj.parent()
436
return M.help(self._name)
437
438
439
class JuliaFunction(ExpectFunction):
440
def _sage_doc_(self):
441
"""
442
EXAMPLES::
443
444
sage: julia.sin._sage_doc_()
445
Traceback (most recent call last):
446
...
447
NotImplementedError
448
"""
449
M = self._parent
450
return M.help(self._name)
451
452
453
def is_JuliaElement(x):
454
"""
455
EXAMPLES::
456
457
sage: from sage.interfaces.julia import is_JuliaElement
458
sage: is_JuliaElement(julia(2))
459
True
460
sage: is_JuliaElement(2)
461
False
462
"""
463
return isinstance(x, JuliaElement)
464
465
466
# An instance
467
julia = Julia()
468
469
470
def reduce_load_Julia():
471
"""
472
EXAMPLES::
473
474
sage: from sage.interfaces.julia import reduce_load_Julia
475
sage: reduce_load_Julia()
476
Julia Interpreter
477
"""
478
return julia
479
480
481
def julia_console():
482
"""
483
Spawn a new Julia command-line session.
484
485
EXAMPLES::
486
487
sage: julia.console() #not tested
488
...
489
"""
490
os.system('julia')
491
492