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