Edited at

[2019年2月版] Juliaが1.1になっていたので触ってみるか


Julia 1.1 リリース

発表された当時はまたいいとこ取りの新しいの出てきたな〜ぐらいにしか思っておらず、すっかり忘れていたわけですが気づけば1.0もリリースされておりまして、さらに先日、1.1がリリースされたとのニュースを目にしたのでおおっと!と思い出したわけでございます。

すぐさま本家サイトに飛んで情報を仕入れてきました。


さっそく install

対象環境は Mac (macOS High Sierra)です。

以下のサイトからMac用のバイナリをダウンロードしてまいります。

例によって アプリケーションフォルダにJulia-1-1.appをドラッグ&ドロップすればインストール完了です。

FinderにてアプリケーションからJulia-1.1.appをダブルクリックすればREPL用のターミナルが立ち上がります。

$ exec '/Applications/Julia-1.1.app/Contents/Resources/julia/bin/julia'

_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.1.0 (2019-01-21)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
julia>

はい、JuliaのREPL環境が起動しました。


Juliaの計算式

Juliaが変態的なのはなんといっても計算式です。それだけじゃないけど言語仕様がてんこ盛りすぎて紹介しきれないのでとりあえず式の書き方からご紹介します。

julia> 1+1

2

julia> x=5
5

julia> 4x
20

julia> y=4
4

julia> xy
ERROR: UndefVarError: xy not defined

julia> x*y
20

数値と変数の乗算で*みたいな演算子がいらないってところがミソですね。4x+1みたいに学校で習った通りに書けます。

流石に変数と変数の暗黙の乗算はダメです。数値リテラルだけに暗黙の乗算メソッドが定義されてる、と頭にいい聞かせて無理やり納得しましょう。

さらに特徴的な演算は続きます。

算演算子/の逆、\演算子が登場です。

julia> 4 / 5

0.8

julia> 4 \ 5
1.25

julia> 5 \ 4
0.8

除単純に「右 割る 左」→「左 割る 右」なのですが、確かに算数の割り算÷は「左 割る 右」でプログラマーを長く続けてると"右 分の 左"が当たり前じゃん、と思ってしまいますが、初心の頃は「プログラムって"左 割る 右"じゃなくて"右 割る 左"って書かなきゃいけないんだ!」って思ったような思わないような・・・新鮮だったなぁ。。。

(今でもちょっと考えると"4割る5と5分の4て一緒じゃん?なにが違うの?"って思っちゃいますが、ほら!暗黙で左右入れ替えてるでしょ?っていう〜。訓練の賜物なんだけどね。。。)

さらに配列のeach展開してくれる.演算子。

julia> a = [1,2,3]

3-element Array{Int64,1}:
1
2
3

julia> b = [1,0,1]
3-element Array{Int64,1}:
1
0
1

julia> a.*b
3-element Array{Int64,1}:
1
0
3

簡単に配列の合成ができてしまいます。。。

あとは超重要なNaNが数値として==で比較するのとオブジェクト?として比較するiseqaul関数で分けられているので安心。

julia> NaN == NaN

false

julia> isequal(NaN, NaN)
true

julia> isequal(-0.0, 0.0)
false



  • isequalは値ではなくオブジェクトのハッシュ値を計算して比較するらしいので、-0.00.0.の区別もします。

そして比較演算子の連結。

julia> -0.0 == 0.0 == 0 < 1

true



  • 0 < f(a) < (b) < 1のような関数の戻り値も当然、連結して比較できます。
    これは便利。

Macでoption+^と押すとが出せるんだね!

julia> 1≠2

true

はい、!=と同じです。

続いてoption+vが出せます。

julia> .√b

3-element Array{Float64,1}:
1.0
0.0
1.0

配列の各要素の平方根求めてますが・・・だんだん、理解が追いつかなくなってきたな。。。w

というか√配列だけで呼ぶと以下のエラーが出ます。

julia> √b

ERROR: MethodError: no method matching sqrt(::Array{Int64,1})
Closest candidates are:
sqrt(::Float16) at math.jl:1018
sqrt(::Complex{Float16}) at math.jl:1019
sqrt(::Missing) at math.jl:1070
...
Stacktrace:
[1] top-level scope at none:0

なるほどsqrt関数の引数はやっぱりFlaot16を受け取るからbだけだとsqrt(Array)になっちゃってダメなんですね!で、.演算子のeachbを展開するからsqrt(Float16)に渡せる、ということですか。あんまりわかりません!w

(.が前置でも後置でも動くのが気持ち悪いw)

お次はrational number、有理数です。要は分子と分母が整数の分数です。

julia> 2 // 3

2//3

julia> 6//8
3//4

julia> g = 90
90

julia> g//5
18//1

自動で約数にしてくれます。

虚数も余裕です。


julia> 1+2im
1 + 2im

julia> 5(1 + 4im)
5 + 20im

julia> r=4; i=3; q=r+i*im
4 + 3im

julia> real(q)
4

julia> imag(q)
3

julia> conj(q)
4 - 3im

julia> abs(q)
5.0

julia> angle(q)
0.6435011087932844

julia> sqrt(-1)
ERROR: DomainError with -1.0:
sqrt will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).
Stacktrace:
[1] throw_complex_domainerror(::Symbol, ::Float64) at ./math.jl:31
[2] sqrt at ./math.jl:492 [inlined]
[3] sqrt(::Int64) at ./math.jl:518
[4] top-level scope at none:0

julia> sqrt(-1 + 0im)
0.0 + 1.0im

俺があんまり余裕じゃないけど。。。sqrt(-1)でエラーで、sqrt(-1 + 0im)でちゃんと計算してくれるのはさすがです。

配列、行列はプログラマーとしての理解を超えていますw

julia> a = [ 1 -1-im

1+im im]
2×2 Array{Complex{Int64},2}:
1+0im -1-1im
1+1im 0+1im

julia> a[1]
1 + 0im

julia> a[1:4]
4-element Array{Complex{Int64},1}:
1 + 0im
1 + 1im
-1 - 1im
0 + 1im

julia> a'
2×2 LinearAlgebra.Adjoint{Complex{Int64},Array{Complex{Int64},2}}:
1+0im 1-1im
-1+1im 0-1im

julia> b = rand(10,10)
10×10 Array{Float64,2}:
0.276978 0.323021 0.169132 0.195895 0.889746 0.926098 0.425271
0.798352 0.240408 0.68136 0.167325 0.442709 0.119885 0.353514
0.806736 0.847521 0.274664 0.927191 0.519732 0.20163 0.843687
0.909628 0.280718 0.262527 0.927031 0.79751 0.852825 0.717645
0.859211 0.167855 0.574454 0.929672 0.745732 0.483358 0.820543
0.808946 0.323306 0.953342 0.987195 0.0455295 0.0437875 0.0437014
0.965098 0.219585 0.403237 0.8617 0.966326 0.894821 0.365612
0.310564 0.231156 0.539079 0.289952 0.95213 0.626799 0.412521
0.622888 0.883617 0.219356 0.970493 0.315544 0.913933 0.911824
0.326981 0.645471 0.148864 0.246486 0.278956 0.53009 0.740881

要注意なのは配列のインデクスが"1"ベースであるということです。大抵のプログラミング言語は"0"ベースのインデクスですがJuliaは"1"ベースです。

随伴行列ってなんですかね・・・?すいません、実はこっち系全然疎いのですw


REPLの終わり方

REPLから抜けるには以下のようにexitメソッドを呼びます。

julia> exit()


パスを通す。

アプリケーションフォルダにコピーしただけなので当然このままではjuliaコマンドが他から呼べません。

パスを通します。

$ vi ~/.bash_profile   # -> export PATH=/Applications/Julia-1.1.app/Contents/Resources/julia/bin:$PATH を追加。

$ source ~/.bash_profile

appのバージョンはダウンロードしたバージョンに合わせてください。


Jupyter で動かしてみる

こちらを参考にしつつ以下の手順で Jupyter 用の Julia kernel IJuliaをインストールしました。

Anacondaは導入済みとします。

julia> using Pkg

julia> Pkg.add("IJulia")

インストールが終わったらnotebookメソッドで起動します。

julia> using IJulia

julia> notebook()
install Jupyter via Conda, y/n? [y]: y
[ Info: Downloading miniconda installer ...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 43.3M 100 43.3M 0 0 2799k 0 0:00:15 0:00:15 --:--:-- 3538k
[ Info: Installing miniconda ...

あっ。。。おもわずyしちゃったけど、Jupyterはinstallしなくてよかったんじゃないかな〜!?

・・・とりあえず起動したのでよしとします。。

jupyterが起動したのを確認したらcontrol+cでnotebookのサーバーを停止し、anacondaのnotebookもしくはjupyterlabを起動し、JuliaのアイコンがNotebookとConsoleに追加されているのを確認します。


VSCode のプラグイン

VS CodeのプラグインはそのものズバリのJuliaプラグインがあったのでインストールいたしました。

例によって hello worldを出力してみます。ついでに引数も表示させてみます。


sample.jl

println("hello world")

for x in ARGS
println(x)
end


ターミナルを開きsample.jlを実行します。

$ julia sample.jl 0 aa bbb ccc

hello world
0
aa
bbb
ccc

素敵!

続きはJupyterでグラフなどを出してみたいと思います。