PythonからJuliaを呼び出したいんだ(Julia v 0.7 および v1.0 で OK)

# 本日は

色々言語を学んでくると言語間の連携に興味が出てきます．
Pythonは便利だから使いたい．でもC,C++がメインで開発されてきた資源を活用したい
といったときはBoostだったりCythonを使って呼び出すわけです（大変ですが・・・）.

同じようにJuliaとPythonの間を繋げたいみたいなときもいつかは出て来るはずです．

[Calling julia functions from python](https://discourse.julialang.org/t/calling-julia-functions-from-python/6885)

によるとPythonからJuliaを呼び出すことはできるようです．やってみませう．

Julia0.７対応に合わせて、以下の内容を2018/9/17日に大幅に修正しました。

# 環境
Macで動作を確認しています.
python は pyenv でバージョンを切り替えています。これらのPythonと対応させるために

- [macOSでpyenvで入れたpythonをPyCallで使うには](https://qiita.com/kjunichi/items/7453814cb902158f9836)
- [HighSierraにしてpyenvからpython入れようとしたら失敗した”The Python ssl extension was not compiled. Missing the OpenSSL lib?”](https://qiita.com/ayihis@github/items/25e752dc5201835bb966)

などに目を通しておくと良さそうです。

## 0.7 の場合

Pythonは（pyenv で導入したminiconda3-3.19.0）3.5.5、Juliaは0.７

```console
$ python
Python 3.5.5 | packaged by conda-forge | (default, Feb 13 2018, 05:40:31) 
[GCC 4.2.1 Compatible Apple LLVM 6.1.0 (clang-602.0.53)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
```

```console
               _
   _       _ _(_)_     |  A fresh approach to technical computing
  (_)     | (_) (_)    |  Documentation: https://docs.julialang.org
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 0.7.0 (2018-08-08 06:46 UTC)
 _/ |\__'_|_|_|\__'_|  |  Official http://julialang.org/ release
|__/                   |  x86_64-apple-darwin14.5.0

julia>versioninfo()
Julia Version 0.7.0
Commit a4cb80f3ed (2018-08-08 06:46 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin14.5.0)
  CPU: Intel(R) Core(TM) M-5Y51 CPU @ 1.10GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.0 (ORCJIT, broadwell)
Environment:
  JULIA_BINDIR = /Applications/Julia-0.7.app/Contents/Resources/julia/bin/
  JULIA_HOME = /Applications/Julia-0.7.app/Contents/Resources/julia/bin/
```

## 1.0 の場合

0.7で試したPythonでもOKでしたが、
pyenvによる次のコマンドで導入したPythonでも試しました。

```shell 
$　CFLAGS="-I$(brew --prefix openssl)/include" LDFLAGS="-L$(brew --prefix openssl)/lib" PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install -v 3.6.3
```

```shell-session
$ python
Python 3.6.3 (default, Sep 28 2018, 17:02:21) 
[GCC 4.2.1 Compatible Clang 5.0.1 (tags/RELEASE_501/final)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
```

```shell-session
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.0.0 (2018-08-08)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> versioninfo()
Julia Version 1.0.0
Commit 5d4eaca0c9 (2018-08-08 20:58 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin14.5.0)
  CPU: Intel(R) Core(TM) M-5Y51 CPU @ 1.10GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.0 (ORCJIT, broadwell)
```

# やってみませう（準備）．

pyjulia は pip を使うことでも導入できます。

```console
$ pip install julia # 今回はこれを使わない。
```

しかし、現在は　Juliaのバージョン、0.７、1.0 対応が進んでいるため直接リポジトリをもってきてインストールした方が良さそうです(Julia1.0の場合はリポジトリから直接インストールしないとダメでした。)。下記のコマンドを実行します。

```
$ git clone https://github.com/JuliaPy/pyjulia.git
$ cd pyjulia
$ pip install .
```

また、 Julia 側の準備としては `PyCall` を使うらしいので、Julia の REPL を使って導入します。Julia ENV["PYTHON"] を呼び出すPythonのパスを指定して PyCall のビルドをする必要があります。ここら辺の準備はPyCallの設定の話になるので　[PyCallのREADME](https://github.com/JuliaPy/PyCall.jl)を参照しましょう。

# 呼び出してみやう

呼び出してみたい Julia の関数を書いてみます。配列の各々の要素を２倍するいたってシンプルなものです。

```julia:test.jl
function twice_array(x::Array{T}) where T <: Number
    return 2x
end
```

呼び出す側の Python のコードは下記のようになります。
include の仕方は

[How to include source written in julia ?](https://github.com/JuliaPy/pyjulia/issues/202) の Issue
 にて教えてもらいました。

```python:calljl.py
import numpy as np


def main():
    from julia import Julia
    julia = Julia()
    julia.eval("@eval Main import Base.MainInclude: include")
    from julia import Main
    Main.include("test.jl")

    arr = np.array([1, 2, 3])
    ret = Main.twice_array(arr)

    print("arr =", arr)
    print("ret =", ret)


if __name__ == '__main__':
    main()

```

実行結果は

```cosole
$ python calljl.py
arr = [1 2 3]
ret = [2 4 6]
```

できましたね。

`from julia import Main` でもってきた `Main`　というオブジェクトにJuliaの変数やら関数のオブジェクトを紐づけることができるようです。例えば、

```math
\sin\left(\frac{\pi}{4}\right) = \frac{\sqrt{2}}{2}
```

などの確認は、

```python
# Python のスクリプトでこれを書く
jlsin = Main.sin
Main.rad45degree = np.pi / 4
print(jlsin(Main.rad45degree), np.sqrt(2) / 2)
```

のようにしてPython上で記述できます。

# トラブルシューティング
## （Pythonのバージョンを切り替えたとき）

`pyenv global <べつのPythonのバージョン>` で用いるPythonを変更した後は

JuliaのREPLでPyCallをビルドし直す必要があります。

```julia
julia> ENV["PYTHON"]="/Users/terasakisatoshi/.pyenv/shims/python"
"/Users/terasakisatoshi/.pyenv/shims/python"

(v1.0) pkg> build PyCall
  Building Conda ─→ `~/.julia/packages/Conda/hsaaN/deps/build.log`
  Building PyCall → `~/.julia/packages/PyCall/rUul9/deps/build.log`
```

(`~/.pyenv/shims/python`だとPyCallのビルドが終わらない・・・）
# 最後に

Julia 0.7, および 1.0 で動作確認できました。
色々うまくいかないことがあれば、GitHubのイシューなどで調べると解決策が見つかるかもしれません。
また、pyjulia ライブラリは 0.1.5　から　 0.2 のバージョンアップが試みられており、Julia 0.6 対応は捨てられるとのことです。

[Release PyJulia 0.2?](https://github.com/JuliaPy/pyjulia/issues/198)