Skip to content

Instantly share code, notes, and snippets.

@mforets
Created August 23, 2017 16:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mforets/26d42220946fba8f8e1feb8208783231 to your computer and use it in GitHub Desktop.
Save mforets/26d42220946fba8f8e1feb8208783231 to your computer and use it in GitHub Desktop.
Sagemath interface to Julia interpreter
r"""
Interface to Julia interpreter.
Julia is a high-level, high-performance dynamic programming language for
numerical computing, see the official website <JuliaLang https://julialang.org/>_
for installation and further information.
The commands in this section only work if you have "julia" installed and
available in your PATH. It's not necessary to install any special Sage packages.
EXAMPLES::
sage: julia.eval('2+2') # optional - julia
'4\n'
::
sage: a = julia(10) # optional - julia
sage: a**10 # optional - julia
10000000000
AUTHORS:
- Marcelo Forets (2017-08-20) : initial implementation, strongly based on the
matlab.py interface by W. Stein and D. Joyner.
Tutorial
--------
EXAMPLES::
sage: julia('4+10') # optional - julia
14
sage: julia('5*10 + 6') # optional - julia
56
sage: julia('(6+6)/3') # optional - julia
4.0
sage: julia('9')^2 # optional - julia
81
sage: a = julia(10); b = julia(20); c = julia(30) # optional - julia
sage: avg = (a+b+c)/3; avg # optional - julia
20.0
sage: parent(avg) # optional - julia
Julia
::
sage: my_scalar = julia('3.1415') # optional - julia
sage: my_scalar # optional - julia
3.1415
sage: row_vector = julia('[1 5 7]') # optional - julia
sage: row_vector # optional - julia
1x3 Array{Int64,2}:
1 5 7
sage: column_vector = julia('[1 5 7]') # optional - julia
3-element Array{Int64,1}:
1
5
7
sage: row_vector * column_vector # optional - julia
1-element Array{Int64,1}:
75
sage: column_vector * row_vector # optional - julia
3×3 Array{Int64,2}:
1 5 7
5 25 35
7 35 49
::
sage: row_vector1 = julia('[1 2 3]') # optional - julia
sage: row_vector2 = julia('[3 2 1]') # optional - julia
sage: matrix_from_row_vec = julia('[%s; %s]'%(row_vector1.name(), row_vector2.name())) # optional - julia
sage: matrix_from_row_vec # optional - julia
1 2 3
3 2 1
::
sage: column_vector1 = julia('[1;3]') # optional - julia
sage: column_vector2 = julia('[2;8]') # optional - julia
sage: matrix_from_col_vec = julia('[%s %s]'%(column_vector1.name(), column_vector2.name())) # optional - julia
sage: matrix_from_col_vec # optional - julia
1 2
3 8
::
sage: my_matrix = julia('[8, 12, 19; 7, 3, 2; 12, 4, 23; 8, 1, 1]') # optional - julia
sage: my_matrix # optional - julia
8 12 19
7 3 2
12 4 23
8 1 1
::
sage: combined_matrix = julia('[%s, %s]'%(my_matrix.name(), my_matrix.name())) # optional - julia
sage: combined_matrix # optional - julia
8 12 19 8 12 19
7 3 2 7 3 2
12 4 23 12 4 23
8 1 1 8 1 1
::
sage: tm = julia('0.5:2:10') # optional - julia
sage: tm # optional - julia
0.5000 2.5000 4.5000 6.5000 8.5000
::
sage: my_vector1 = julia('[1,5,7]') # optional - julia
sage: my_vector1(1) # optional - julia
1
sage: my_vector1(2) # optional - julia
5
sage: my_vector1(3) # optional - julia
7
Matrix indexing works as follows::
sage: my_matrix = julia('[8, 12, 19; 7, 3, 2; 12, 4, 23; 8, 1, 1]') # optional - julia
sage: my_matrix(3,2) # optional - julia
4
Setting using parenthesis cannot work (because of how the Python
language works). Use square brackets or the set function::
sage: my_matrix = julia('[8, 12, 19; 7, 3, 2; 12, 4, 23; 8, 1, 1]') # optional - julia
sage: my_matrix.set(2,3, 1999) # optional - julia
sage: my_matrix # optional - julia
8 12 19
7 3 1999
12 4 23
8 1 1
"""
#*****************************************************************************
# Copyright (C) 2017 Marcelo Forets <mforets@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
# http://www.gnu.org/licenses/
#*****************************************************************************
from __future__ import print_function
from __future__ import absolute_import
import os
from .expect import Expect, ExpectElement
from sage.docs.instancedoc import instancedoc
class Julia(Expect):
"""
Interface to the julia interpreter.
EXAMPLES::
sage: a = julia('[1 1 2; 3 5 8; 13 21 33]') # optional - julia
sage: b = julia('[1; 3; 13]') # optional - julia
sage: c = a * b # optional - julia
sage: print(c) # optional - julia
3-element Array{Int64, 1}:
30
122
505
"""
def __init__(self, maxread=None, script_subdirectory=None,
logfile=None, server=None,server_tmpdir=None):
Expect.__init__(self,
name = 'julia',
prompt = 'julia> ',
command = "sage-native-execute julia -q",
server = server,
server_tmpdir = server_tmpdir,
script_subdirectory = script_subdirectory,
restart_on_ctrlc = False,
verbose_start = False,
logfile = logfile,
eval_using_file_cutoff=100)
def __reduce__(self):
return reduce_load_julia, tuple([])
def _read_in_file_command(self, filename):
"""
Returns the command used to read in and execute a file in julia.
EXAMPLES::
sage: julia._read_in_file_command('/tmp/julia_file')
"eval(fileread('/tmp/julia_file'));"
Here is an indirect doctest to check that it does indeed work::
sage: m = identity_matrix(ZZ, 10)
sage: sm = julia.sage2julia_matrix_string(m)
sage: m = julia(sm) # optional - julia
"""
return "eval(fileread('{0}'));".format(filename)
def _quit_string(self):
return 'exit()'
def _install_hints(self):
return """
You must obtain the program Julia in order to use Julia from Sage.
You can read all about julia at <julialang.org http://julialang.org/>_.
"""
def _start(self):
Expect._start(self)
def whos(self):
return self.eval('whos')
def set(self, var, value):
"""
Set the variable var to the given value.
"""
cmd = '{0}={1};'.format(var, value)
out = self.eval(cmd)
if out.find("error") != -1:
raise TypeError("Error executing code in julia\nCODE:\n\t{0}\njulia ERROR:\n\t{1}".format(cmd, out))
def get(self, var):
"""
Get the value of the variable var.
EXAMPLES::
sage: s = julia.eval('a = 2') # optional - julia
sage: julia.get('a') # optional - julia
' 2'
"""
s = self.eval('{0}'.format(var))
return self.strip_answer(s)
def strip_answer(self, s):
r"""
Returns the string s with Julia's answer prompt removed.
EXAMPLES::
sage: s = '\nans =\n\n 2\n'
sage: julia.strip_answer(s)
' 2'
"""
i = s.find('=')
return s[i+1:].strip('\n')
def console(self):
julia_console()
def version(self):
return julia_version()[1:]
def chdir(self, directory):
"""
Change julia's current working directory.
EXAMPLES::
sage: julia.chdir('/') # optional - julia
sage: julia.pwd() # optional - julia
/
"""
self.eval("cd('{0}')".format(directory))
def sage2julia_matrix_string(self, A):
"""
Return a Julia matrix from a Sage matrix.
INPUT:
- ``A`` -- a Sage matrix with entries in the rationals or reals
OUTPUT:
A string that evaluates to an julia matrix.
EXAMPLES::
sage: M33 = MatrixSpace(QQ,3,3)
sage: A = M33([1,2,3,4,5,6,7,8,0])
sage: julia.sage2julia_matrix_string(A) # optional - julia
'[1, 2, 3; 4, 5, 6; 7, 8, 0]'
"""
return str(A.rows()).replace('), (', '; ').replace('(', '').replace(')','')
def _object_class(self):
return JuliaElement
@instancedoc
class JuliaElement(ExpectElement):
def __getitem__(self, n):
raise RuntimeError("Use parenthesis for julia matrices instead.")
def _matrix_(self, R):
r"""
Return Sage matrix from this julia element.
EXAMPLES::
sage: A = julia('[1 2; 3 4]') # optional - julia
sage: matrix(ZZ, A) # optional - julia
[1 2]
[3 4]
sage: A = julia('[1 2; 3 4.5]') # optional - julia
sage: matrix(RR, A) # optional - julia
[1.00000000000000 2.00000000000000]
[3.00000000000000 4.50000000000000]
sage: a = julia('eye(50)') # optional - julia
sage: matrix(RR, a) # optional - julia
50 x 50 dense matrix over Real Field with 53 bits of precision
"""
raise NotImplementedError("julia to matrix is not implemented (yet)")
from sage.matrix.all import matrix
julia = self.parent()
entries = julia.strip_answer(julia.eval("mat2str({0})".format(self.name())))
entries = entries.strip()[1:-1].replace(';', ' ')
entries = [R(_) for _ in entries.split(' ')]
nrows, ncols = map(int, str(self.size()).strip().split())
m = matrix(R, nrows, ncols, entries)
return m
def set(self, i, j, x):
P = self._check_valid()
z = P(x)
P.eval('{0}({1},{2}) = {3}'.format(self.name(), i, j, z.name()))
# An instance
julia = Julia()
def reduce_load_Julia():
return julia
def julia_console():
"""
This requires that the optional julia program be installed and in
your PATH, but no optional Sage packages need be installed.
EXAMPLES::
sage: julia_console() # optional - julia; not tested
< M A T L A B >
Copyright 1984-2006 The MathWorks, Inc.
...
>> 2+3
ans =
5
exit()
Typing quit exits the Julia console and returns you to Sage.
Julia, like Sage, remembers its history from one session to
another.
"""
from sage.repl.rich_output.display_manager import get_display_manager
if not get_display_manager().is_in_terminal():
raise RuntimeError('Can use the console only in the terminal. Try %%julia magics instead.')
os.system('julia')
def julia_version():
"""
Return the version of Julia installed.
EXAMPLES::
sage: julia_version() # random; optional - julia
v"0.6.0"
"""
return str(julia('VERSION')).strip()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment