julia

前回debianをdist-upgradeしたものだから、色々と点検してたんだ。 そしたら、javaが8の世界を脱して11の世界になってた。

debian:~$ java -version
openjdk version "11.0.3" 2019-04-16
OpenJDK Runtime Environment (build 11.0.3+7-post-Debian-5)
OpenJDK Server VM (build 11.0.3+7-post-Debian-5, mixed mode, sharing)

頼んだ覚えが無いのに更新されてるって事はLibreOfficeからの要請だったのかな? replが使えるそうなので、試してみた。

debian:~$ jshell
|  Welcome to JShell -- Version 11.0.3
|  For an introduction type: /help intro

jshell> System.out.println("Hello World");
Hello World

jshell> int a = 123;
a ==> 123

jshell> a;
a ==> 123

jshell> /exit
|  Goodbye

これで、ちょいと実験しといてOKとなったらコンパイルしてから使うって方針のCommonLisp並みにやっとなったな。(使わんけど)

julia

debianが新しくなったので、記念にjuliaを入れてみる。 何でも、jitで部分コンパイルされて、実行スピードが向上するのが売りらしい。対抗馬は、RとかPythonらしい。後出しじゃんけんだからswiftみたいに、色々研究出来た訳ね。 Juliaの速さを体感する

2016年にもやってたけど、あの頃はまだ安定期間に入っていなくて、ちょいと悩ましい感じだった。(ああ、普通にjuliaなんて検索すると、本当に悩ましいのが出てくるので、lang juliaを指定の事)

The Julia Programming Language

32/64Bit用に用意されてた。もうじき1.2がやってきそうな雰囲気だけど、安定版と言う事で、1.1.1を入れた。 昔からづっと付き合いのある人は、その集大成の長期保証版を使うのが良いとか。

Julia入門のための参考資料まとめ

Plots/GR: グラフ package のおすすめ そう、グラフぐらい書けなくちゃ、octaveにも対抗出来ないしね。

Julia By Example

Search Package by Name

csv file

それから、EXCELでも使えると言う、csvファイルを容易に扱える事も重要。jsonとかxmlは外しても、これは必須事項ですな。

JuliaでCSV / DataFrameを扱う方法

julia> using CSV

julia> bld = CSV.read("current.csv", header=false)
5439×4 DataFrames.DataFrame
│ Row  │ Column1  │ Column2 │ Column3 │ Column4 │
│      │ Int64    │ Int64   │ Int64   │ Int64   │
├──────┼──────────┼─────────┼─────────┼─────────┤
│ 1    │ 12010104 │ 118     │ 73      │ 57      │
  :
│ 5439 │ 19063021 │ 108     │ 57      │ 63      │

pythonからの集客を目指して、julia応援隊からの提案だな。でも、重そうな装備だな。

標準備え付けの方が、身軽かな。Delimited Files最後の所にあるリンクでソースが見られる。これが何よりの勉強材料。

julia> using DelimitedFiles
julia> bld = readdlm("current.csv", ',', Int, '\n');
julia> size(bld)
(5457, 4)
julia> bld[1,:]
4-element Array{Int32,1}:
 12010104
      118
       73
       57

repl

tar玉を取って来て、適当な所に展開。後はPATHを通すだけ。(黒い画面が大好き人間向け) こちらはGUIな人向けかな。 JuliaとJupyterのすすめ

debian:AA$ julia
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.1.1 (2019-05-16)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

shell> cat /etc/debian_version   ## press ; to shellmode
10.0

julia> include("path/to/script-name.jl")

julia> apropos("pretty-print")
Base.repr
Base.repr

(v1.1) pkg> status
    Status `~/.julia/environments/v1.1/Project.toml`
  [336ed68f] CSV v0.5.9
  [28b8d3ca] GR v0.40.0
  [91a5bcdd] Plots v0.25.3

for emacs

emacs使いは、julia-modeが有る事を期待。無ければ、もぐりの言語です。やる価値無しと思っていたら、ちゃんと有った。 julia-mode,julia-replを入れ、下記の設定をinit.elにする。

(require 'julia-repl)
(add-hook 'julia-mode-hook 'julia-repl-mode)

キーバインドは、下記のように少な目に覚える。ってか、指を訓練する。

C-c C-z               ;; run julia
C-c C-b               ;; exec script
C-c C-c               ;; exec a line
C-c C-d               ;; document

my first julia

octaveでやった、dictを使ったME差のプログラムがめちゃくちゃ遅かったので、juliaではどうかとやってみる。

# my first julia

using DelimitedFiles

function ampm(bld)
    ymdh = bld[:,1]; hi = bld[:,2]
    am = []; pm = []
    for i in eachindex(ymdh)
        ymd = div(ymdh[i] , 100)
        if (ymdh[i] % 100) < 12
            push!(am, ymd, hi[i])
        else
            push!(pm, ymd, hi[i])
        end
    end
    reshape(am,2,:)', reshape(pm,2,:)'
end

function regkv(dh)
    tt = []
    for i in eachindex(dh[:,1])
        push!(tt, (dh[i,1], dh[i,2]))
    end
    Dict(tt)
end

function main()
    bld = readdlm("current.csv", ',', Int, '\n');
    am, pm = ampm(bld)
    da = regkv(am)
    dp = regkv(pm)
    res = zeros(Int,2,2)
    for k in intersect(keys(da),keys(dp))
        av = div(da[k] + dp[k], 2)
        dl = da[k] - dp[k]
        if (av >  135 && dl > 15)   res[1,2] +=1; end
        if (av <= 135 && dl > 15)   res[1,1] +=1; end
        if (av >  135 && dl<= 15)   res[2,2] +=1; end
        if (av <= 135 && dl<= 15)   res[2,1] +=1; end
    end
    res
end

res = main()
println(repr("text/plain", res))
println("Total = ",sum(res))

さらっと書けたかと言うとそうでもなくて、試行錯誤しましたよ。取り合えず実行時間の測定をば。

[ham@cent ~]$ time julia test.jl
2×2 Array{Int64,2}:
  857   3
 1780  68
Total = 2708

real    0m4.017s
user    0m2.514s
sys     0m1.653s
[ham@cent ~]$ time julia test.jl
2×2 Array{Int64,2}:
  857   3
 1780  68
Total = 2708

real    0m2.057s
user    0m1.995s
sys     0m0.397s

初回はjulia自身がOSのキャッシュに載っていないので、時間がかかるんだな。2度目からは速くなる。と言っても、2秒じゃねぇ。awkのやつは、爆速だったぞ。

まてまて、juliaはreplが充実してる。と言う事は、一度juliaを立ち上げたら、そこで生活しなさいって事だな。スクリプトをこねくり回して、あーでもない、こーでもないとやる環境なんだな。さすがMIT発だけある。現代風のLisp環境か。

julia> @timev main()
  0.009622 seconds (109.07 k allocations: 3.792 MiB)
elapsed time (ns): 9622027
bytes allocated:   3976464
pool allocs:       109005
non-pool GC allocs:36
malloc() calls:    32
2×2 Array{Int64,2}:
  857   3
 1780  68

これがその証拠。これなら十分に速いと言っていいだろう。頭に@が付くやつはマクロだしね。 timevで出てくるやつも、あれにそっくりだな。そう言えば、juliaの根幹部分にpico-schemeだったかが埋め込まれていたな。

自分でコンパイルすると、そのschemeも取り出せるのかな? 暇な時にソースを見てみよう。

で、このコードを作り上げる時、関数を書いてそれをテストし、正しかったら次に繋げて行くって方針でやってた。ボトムアップ方式ね。

そうして、関数を呼び出すコードが、スクリプトの最後の方に溜まってこれで佳しとなった時に、溜まったコードを function main()で一括りにしたんだ。(mainの外側に、結果の表示コードが置いてあるけど、それはご愛嬌です。)

Dict

辞書を作りたかったんだけど、動的に作る方法をサッと見つけられなかった。そこで、helpしてみた。

help?> Dict
search: Dict IdDict WeakKeyDict AbstractDict redirect_stdin redirect_stdout
  :
  Examples
  ≡≡≡≡≡≡≡≡≡≡

  julia> Dict([("A", 1), ("B", 2)])
  Dict{String,Int64} with 2 entries:
    "B" => 2
    "A" => 1

  Alternatively, a sequence of pair arguments may be passed.

  julia> Dict("A"=>1, "B"=>2)
  Dict{String,Int64} with 2 entries:
    "B" => 2
    "A" => 1

ネットを検索しても、例2の例ばかり。Dictって余り人気が無いのでしょうか? とにかく、タプルの配列を食わせれば良い事が分かった。

そんなこんなで、上記の様なコードが生まれた訳だけど、eachindexを使ってループを回しているのが、いかにも遅いぞって信号を発してるようで、気分が悪い。

kとvに相当するものをindex経由じゃなくて、ずばっと取り出せないか?

  julia> a = ["a", "b", "c"];

  julia> for (index, value) in enumerate(a)
             println("$index $value")
         end
  1 a
  2 b
  3 c

これじゃ、意味無いしね。juliaが衣を被ったLispって事を思い出して、まとめてくれる関数を脳内サーチ。

julia> a = [1 2 3]
1×3 Array{Int32,2}:
 1  2  3

julia> b = [5 6 7]
1×3 Array{Int32,2}:
 5  6  7

julia> Dict(zip(a,b))
Dict{Int32,Int32} with 3 entries:
  3 => 7
  2 => 6
  1 => 5

ぴったりぽい。

function regkvt(dh)
    Dict(zip(dh[:,1],dh[:,2]))
end

コードにしたら、こんなにすっきりした。juliaは、マトリックスのアクセスは列方向優先で行われるそうなので、スピードアップを期待。

julia> @timev regkvt(am)
  0.000493 seconds (9.79 k allocations: 287.781 KiB)
elapsed time (ns): 492823
bytes allocated:   294688
pool allocs:       9778
non-pool GC allocs:5
malloc() calls:    4
Dict{Any,Any} with 2721 entries:
  170921 => 142

こちらは、既存の長ったらしいやつ。

ulia> @timev regkv(am)
  0.001337 seconds (16.37 k allocations: 561.609 KiB)
elapsed time (ns): 1337348
bytes allocated:   575088
pool allocs:       16353
non-pool GC allocs:10
malloc() calls:    3
Dict{Int64,Int64} with 2721 entries:
  170921 => 142
   :

1.3msかかっていたのが、0.5msに高速化した。メモリー使用量も大幅に減っている。

Profile

Profiling

統計的なプロファイラーが装備されてるとか。スクリプトを実行して、1msの間隔でバックトレースし、どこを実行してたか集積する。短い実行時間だとかすりもしないので、何回も実行すれば、そのうちに当たるでしょって方針。よって、スクリプトに手を入れる必要は無い。

julia> @profile (for i=1:1000; regkvt(am); end)

julia> Profile.print()
13   ./dict.jl:305; ht_keyindex2!(::Dict{Any,Any}, ::I...
4    ./dict.jl:318; ht_keyindex2!(::Dict{Any,Any}, ::I...
  :
               2 ./array.jl:729; getindex
           2  ./sysimg.jl:18; getproperty
          3   ./tuple.jl:24; iterate

julia> Profile.print(format=:flat)
 Count File                        Line Function
  1193 ./REPL[5]                      1 macro expansion
   338 ./abstractarray.jl           927 getindex
    :
  1193 ...b/v1.1/REPL/src/REPL.jl   117 macro expansion
  1193 /tmp/AA/test.jl               28 regkvt(::LinearAlgebra.Adjoint{Any,A...
     2 .../julia/lib/julia/sys.so    -1 hashindex(::Int32, ::Int32)
     8 .../julia/lib/julia/sys.so    -1 isequal(::Int32, ::Int32)

走らせた後、2種類の方法で、結果を眺められる。

ProfileView.jl

もっとかっこよく眺めたいなら、GUI版も用意されてるぞ。

Benchmark

BenchmarkTools.jl

大体、@timev とかで用事が足りると思うけど、論文を発表したい時とかに使うのかな?

Debugger

Debugger.jl

以前にjuliaした時は、無かったような。遂にこういう物もリリースされるようになったのね。 感慨深い。って、言う程使っていないだろに!

JuliaのDebugger

目ざとい人が居て、日本語解説をされてた。これが役にたつのは何時だろう?

btがサポートされてるようだから、結構役にたつかな。それはそうと、schemeのRnRSでは必須とされている、traceって無いものだろうか? >MITの偉い方。