読者です 読者をやめる 読者になる 読者になる

りんごがでている

何か役に立つことを書きます

Julia言語の0.5の変更点

9月20日にJulia言語の最新版である0.5がリリースされました。Juliaのメーリングリストに投稿されたアナウンスメントはこちらです: https://groups.google.com/d/msg/julia-users/J2DiH1GnM8o/aO2Ku8o-CgAJ

きっと近いうちに本家のブログで詳しい変更点の紹介があると思いますが、私のブログでも一足先に主要な変更点をご紹介しようと思います。

クロージャの効率化

とりわけ重要な変更点として挙げられるのがJuliaのクロージャが効率化されたことです。 0.4までのJuliaでは、Juliaの関数に関数を渡したりJuliaで関数を返すような関数を作ると、その実効速度が極めて遅いことが問題でした。 これは、すべての関数が Functionという型にまとめられていたせいで、Juliaのコンパイラが特化したコードを吐けないせいでした。 これが0.5では関数は各々自分専用の型を持つように変更されたため、クロージャを使ったコードでも遅くなるということが無くなりました。

関数を受け取る関数の例としてよく上げられるのがmap関数でしょう。 以下の簡単なベンチマークを見てもJulia 0.5では0.4に比べて10倍ほど速度が向上しています。

Julia 0.5.0:

julia> f = x -> 2x
(::#1) (generic function with 1 method)

julia> x = rand(100000);

julia> map(f, x);

julia> @time map(f, x);
  0.000572 seconds (134 allocations: 789.078 KB)

Julia 0.4.6:

julia> f = x -> 2x
(anonymous function)

julia> x = rand(100000);

julia> map(f, x);

jjulia> @time map(f, x);
  0.005628 seconds (200.01 k allocations: 3.815 MB)

クロージャを使うようなプログラムではこれでデザインの幅が広がり、今まで実行効率の観点からできなかったコードが書けるようになります。

ジェネレータ式

ジェネレータ式という新しい式が0.5から加わりました。 これは、イテレータをラップして式にしたようなもので、値を次々生成することができる式です。 簡単な例では、 2x for x in 1:9 のようなものが普通の値として扱えるようになりました。

julia> g = (2x for x in 1:9)
Base.Generator{UnitRange{Int64},##5#6}(#5,1:9)

julia> collect(g)
9-element Array{Int64,1}:
  2
  4
  6
  8
 10
 12
 14
 16
 18

もちろん関数はこのジェネレータを値として受け取ることもできるため、次のような計算もできます。

julia> sum(g)
90

また、ifで値をフィルターすることも可能です。

julia> h = (2x for x in 1:9 if isodd(x))
Base.Generator{Filter{Base.#isodd,UnitRange{Int64}},##7#8}(#7,Filter{Base.#isod
d,UnitRange{Int64}}(isodd,1:9))

julia> collect(h)
5-element Array{Int64,1}:
  2
  6
 10
 14
 18

julia> sum(h)
50

文字列型の統合

Julia 0.4の標準ライブラリに大量にあった文字列型が整理され、0.5では主にString型とSubString型のみになりました。 String型は従来のUTF8String型に当たるもので、ユニコード文字列を表現できます。SubString型は従来からありましたが、これはString型の一部分を切り出す際に使われています。 将来的にはSubString型もString型に統合される予定のようですが、0.5時点では0.4のASCIIStringUTF8StringString型に統合されたと見るのが良さそうです。

Julia 0.5.0:

julia> typeof("foo")
String

julia> typeof("いえい")
String

Julia 0.4.6:

julia> typeof("foo")
ASCIIString

julia> typeof("いえい")
UTF8String

昔の文字列型はLegacyStrings.jlパッケージに移動され、UTF-16などのエンコーディング方式はStringEncodings.jlパッケージで新たにサポートされるようです。

Fused broadcasting構文

Fused broadcasting構文は、Juliaのベクトル計算を効率化する新しい構文の拡張です。 0.4までのJuliaでは、配列に対して何度も関数適用を行うとその都度新しい配列が生成されていました。 新しいJuliaでは、これが構文レベルで融合(fuse)されるようになります。

sin.(cos.(x))という式があったとしましょう。 0.4ではまずcos.(x)が評価され、xの各要素にcos関数を適用した新しい配列が作られます。 続いてその各要素にsin関数が適用され、また新しい配列が作られ、先ほどの配列は将来的にGCにより破棄されます。 0.5では、この式はまず broadcast(x -> sin(cos(x)), x)のような式に変換されます。 これは、xから値を一つずつ取り出してcossinを順に適用するため、一時的な配列の生成が起きず、一気に2つの関数を適用した配列が生成されます。

さらに、x .= ...のような構文もbroadcast!(identity, x, ...)に変換されるので配列への代入がin-placeに行うことができるようになりました。

マルチスレッドのサポート

マルチスレッドを使った計算の並列化が新たにサポートされました。 今のところ、@threadsマクロを使ってfor文の並列化を行うことができます。 例えば、以下のように複数のタスクを並列に処理することができます。

using Base.Threads

function dotasks(tasks)
    @threads for i in 1:endof(tasks)
        dotask(tasks[i])
    end
end

配列などを領域で分割しておけば配列に対する処理の並列化もできますし、私の作ったBGZFStreams.jlではgzipの解凍処理をこのマルチスレッド機能を使って並列化しています。

テストフレームワークの強化

Julia標準のテストフレームワークがより強化され、テストをきれいに構造化できるようになりました。 今までBase.Testから提供されていた機能では複数のテストをまとめる機能がなく、フラットにすべてのテストを書き連ねるしか方法がありませんでした。 しかし0.5からは@testsetマクロが加わり、次のようにテストを構造化することができるようになりました。

@testset "sum" begin
    @test sum([1,2,3]) == 6
    @test sum([1.0, 2.0, 3.0]) == 6.0
end

その他の変更点

0.5では内部的なものも含め多数の変更がなされています。そのすべてはJuliaのリリースノートから参照することができますので、気になる方は是非調べてみて下さい。

JuliaからRを使う

先日のWACODE夏期講習でRCall.jlのデモをしたら、やはりウケが良かったようなので改めて紹介をします。

RCall.jlはJuliaからR言語の機能を呼び出すツールです。データの受け渡しからREPLでのインタラクティブな実行・プロットも簡単にできます。Juliaを使ってみたいけど、Rの豊富な資産を捨てる訳にはいかないといった方にはピッタリのライブラリです。

インストールは、Juliaの標準的な方法通り、julia -e 'Pkg.update(); Pkg.add(“RCall”)’を実行して下さい。これで最新版のRCall.jlがインストールされることになります。尚、次期Juliaのリリース候補v0.5-RC1では現在動かないようですが、リリースブランチでは直っているのでRC2では使えると思います。

簡単な演算で正しくインストールできたかを確認しましょう。JuliaのREPLを起動して、using RCallとしてRCall.jlを読み込み、R”1 + 1”と打ってR言語1 + 1を実行してみます。以下のように計算結果が表示されればOKです。 f:id:bicycle1885:20160809080928p:plain

R”…"という記法は、Juliaの非標準文字列と呼ばれる機能を利用したものです。この文字列の内側ではRのコードとして解釈され、Rの処理系がコードを実行してくれます。ダブルクウォートが含まれる場合はバックスラッシュでエスケープするか、R””” … “””とトリプルクウォートを使うこともできます。

R側の評価値を取り出す場合には、rcopyが使えます。

julia> rcopy(R"1 + 1")
2.0

julia> rcopy(R"1:5")
5-element Array{Int32,1}:
 1
 2
 3
 4
 5

julia> rcopy(R"""list(x=10, y="foo")""")
Dict{Symbol,Any} with 2 entries:
  :y => "foo"
  :x => 10.0

R側へJuliaの値を渡すには$で変数を埋め込みます。

julia> x = 1
1

julia> R"1 + $x"
RCall.RObject{RCall.RealSxp}
[1] 2

JuliaのDataFrames.jlパッケージが提供しているDataFrameなども自動的にRのdata.frameへと変換してくれます。

julia> using RDatasets

julia> iris = dataset("datasets", "iris");

julia> typeof(iris)
DataFrames.DataFrame

julia> R"head($iris)"
RCall.RObject{RCall.VecSxp}
  SepalLength SepalWidth PetalLength PetalWidth Species
1         5.1        3.5         1.4        0.2  setosa
2         4.9        3.0         1.4        0.2  setosa
3         4.7        3.2         1.3        0.2  setosa
4         4.6        3.1         1.5        0.2  setosa
5         5.0        3.6         1.4        0.2  setosa
6         5.4        3.9         1.7        0.4  setosa

プロットも簡単にできます。以下のようにすると、Juliaから渡したデータをRがプロットしてくれます。

julia> R"""pairs($iris[1:4], pch=21, bg=c("red", "green3", "blue")[unclass($iris$Species)])"""
RCall.RObject{RCall.NilSxp}
NULL

f:id:bicycle1885:20160809081146p:plain

いちいちR”…”で囲んだりが面倒なら、RのREPLに入りましょう。JuliaのREPLから$キーを押すと、RのREPLに入れます。Juliaに戻るにはバックスペースです。 f:id:bicycle1885:20160809081141p:plain

ここではRの文法が自由に使えるので、Rユーザーにとってはやりやすいでしょう。もちろん、Julia側からデータを受け取ることもR”…”の時と同じように可能です。

R> library(ggplot2)

R> ggplot($iris, aes(x=SepalLength, y=SepalWidth, color=Species)) + geom_point()

f:id:bicycle1885:20160809081246p:plain

Rのセッションではヘルプなども参照できますし補完も効きます。Juliaは気になるけどRから離れるのはチョット…という方は是非一度試してみてください。

『R言語徹底解説』(共立出版)をいただきました!

先日、出版社の方から新刊の『R言語徹底解説』(共立出版)をいただきました。ありがとうございます。

R言語徹底解説 / Hadley Wickham 著 石田 基広 市川 太祐 高柳 慎一 福島 真太朗 訳 | 共立出版

f:id:bicycle1885:20160211220632j:plain

この本は、R言語界では知らない人のいないHadley Wickham氏の書いた『Advanced R』の翻訳です。翻訳はこれまた日本のR言語界では知らない人のいないであろう石田先生・市川氏・高柳氏・福島氏の4名の手により行われています。本のページ数は500ページ以上もあり、R言語の仕様・プログラミングスタイル・高速化について書かれています。おそらく、Rの言語自体について書かれた日本語の本としては最も詳細な本でしょう。

プログラミング言語マニアとして見ると、R言語プログラミング言語としては非常に特異な言語だと思います。例えばスカラーにあたる型がなく、すべてベクトルとして扱ったり、引数の遅延評価など、他のメジャーな言語から来た人にとってはとても奇妙な振る舞いをします。また、GNU R (R言語の標準的な処理系) は決して高速とは言えず、実用されるプログラミング言語の中では最も遅い言語の部類でしょう。R言語はどういう動きをするのか、どうしてこうした特徴を持つのかについて答えてくれるのが、この『R言語徹底解説』です。

第6章「関数」では、R言語の関数について詳細に説明しています。6.3節の「すべての操作は関数呼び出しである」では、実はR言語でのオブジェクトに対する操作すべてが関数呼び出しであることを説明しています。ここでは、ifによる分岐やforによる反復などを含む本当にすべての操作が、関数呼び出しにより行われることを強調しています。普通のプログラミング言語では、if文の条件部分の評価のみが先に行われて、その値に応じて2つの別々に処理へと分岐します。関数呼び出しでif文を実現しようと思っても、関数に与えた引数が先に評価されるため、普通は実現できません。しかし、Rでは引数の遅延評価を行うことで、次のように実現可能になるわけです。

> i = 1
> `if`(i == 1, print("yes!"), print("no."))
[1] "yes!"

(6.3節から一部抜粋)

また、未定義の変数を関数に渡すこともできます。

> exists("x")
[1] FALSE
> f <- function(x) {}
> f(x)
NULL

このような機能があるおかげで、例えばggplot2ではggplot(diamonds, aes(x=carat, y=price)) + geom_point()のように簡潔に式が書けるわけです。他にも、この章で説明されている仮引数に対する値の束縛・クロージャ・コピー修正セマンティクスなども、奇妙なRという言語を扱う上で重要な知識でしょう。

第16章では、R言語のパフォーマンスの問題について議論されています。よく知られているようにGNU RによるR言語の実装は速くはありません。これは、R言語がデータ処理のやりやすさに特化した動的な言語であるためです。また、GNU Rの開発は、安定性のためにパフォーマンスを改善する変更に対してはかなり保守的なようです。これは開発において何を優先するかの問題で、決して間違った考えではないと思います。それに、多くの場合についてはR言語のコードを改善するだけでもそれなりにパフォーマンスは良くなります。そのため、第16章から18章のR言語でのパフォーマンスチューニングの手法を学べば十分でしょう。どうしても必要な場合にのみC言語C++を使うことになりますが、これらの言語をR言語から使う方法についても以降の章で説明されています。

個人的な使い方の話をすると、私はパフォーマンスが必要な部分はJulia言語を推しているのですが、R言語の安定感を求める人にはJulia言語はまだ時期尚早かもしれません。私の使い方としては、R言語でデータの基本的な処理 (バイオインフォなのでBioconductorなどのパッケージをよく使う) を行って簡単なテキストファイルを作り、それをもとにJulia言語で計算をして、R言語で可視化するというR > Julia > Rの順で使うことが多いです。なるべくJulia言語でできるところを増やしたいのですが、それでもR言語から離れられるほど成熟していません。

R言語徹底解説』はR言語の基礎を確認してストレスなく使うために役立つ本だと思います。R言語の仕様をあまり意識してこなかった人にとっては、全部は読まなくとも前半部分の第9章くらいまで目を通しておくだけでも随分違うと思います。

Juliaのユニットテスト

Julia Advent Calendar 9日目の記事です。なんとか途切れさせないでいきましょう。

Juliaと言えばユニットテストが書きやすい言語として有名です[要出典]。 何故書きやすいのかといえば、もちろんマクロがあるからです。 マクロのおかげで、よく分からないアサーションのコードをたくさん覚えなくて済みます。 この記事では、そのへんの理由や、Juliaでの最近のユニットテストの書き方について説明しようと思います。

Juliaのユニットテストの良いところ

以下のテストコードはsumという関数の動作をテストしている想定です:

julia> using Base.Test

# ok
julia> @test sum([1,2,3]) == 6

# not ok
julia> @test sum([1,2,3]) == 7
ERROR: test failed: 6 == 7
 in expression: sum([1,2,3]) == 7
 in error at /usr/local/julia/v0.4/lib/julia/sys.dylib
 in default_handler at test.jl:30
 in do_test at test.jl:53

# ok
julia> @test isa(sum([1,2,3]), Int)

# not ok
julia> @test isa(sum([1,2,3]), Float64)
ERROR: test failed: isa(sum([1,2,3]),Float64)
 in expression: isa(sum([1,2,3]),Float64)
 in error at /usr/local/julia/v0.4/lib/julia/sys.dylib
 in default_handler at test.jl:30
 in do_test at test.jl:53

ここで使われているのは@testというマクロです。 テストが失敗している方に注目していただきたのですが、エラーメッセージにtest failed: 6 == 7test failed: isa(sum([1,2,3]),Float64)のように、どの条件が失敗したのかが分かりやすく現れています。これは、@testマクロがテストの条件式をとり、その式自体を表示できるためです。特に、==などの二項演算子の場合は、左辺の値 sum([1,2,3]) の結果もエラーメッセージに表示してくれていることに気をつけてください。

マクロのない言語だと、テストするだけでもアサーションの関数が山盛りになってしまいます。 例えば、Pythonunittestだと、assertEqual(first, second, msg=None)assertIsInstance(obj, cls, msg=None)のような、ある条件を判定するアサーション関数がたくさん用意されています。ちょっとコレを全部覚えるのは辛いですし、全部assertTrue(expr, msg=None)を使うとテストがどう失敗したのかが分かりづらくなってしまいます。

モダンなユニットテストの方法

とは言え、@testマクロだけではちょっと機能が不足している面もあるでしょう。現在のリリース版v0.4系に付属しているBase.Testには、関係のあるテストをまとめる機能がありません。そのため、テストがフラットで把握しにくい構造になってしまいます。

次期バージョンのv0.5ではBase.Testが一新され、より構造化しやすくなっています。v0.5では@testsetというマクロが新たに追加され、テストをまとめることができるようになりました。 これは、@testset ["description"] begin ... endのように使い、テストの説明と複数のテストをまとめるブロックを取ることができるようになっています。さらに、テストセットの結果はまとめて報告されます:

julia> using Base.Test

julia> @testset "sum" begin
           @test sum([1,2,3]) == 6
           @test isa(sum([1,2,3]), Int)
           @test sum(1:3) == 6
       end
Test Summary: | Pass  Total
sum           |    3      3
Base.Test.DefaultTestSet("sum",Any[Test Passed
  Expression: sum([1,2,3]) == 6
   Evaluated: 6 == 6,Test Passed
  Expression: isa(sum([1,2,3]),Int),Test Passed
  Expression: sum(1:3) == 6
   Evaluated: 6 == 6],false)

実は、テスト結果のサマリーには色もつくようになりました。

f:id:bicycle1885:20151208184155p:plain

さらに、@testsetは以下のように何段でもネストできます:

@testset "basic functions" begin
    @testset "sum" begin
        @test ...
        @test ...
    end

    @testset "mean" begin
        @test ...
        @test ...
    end

    ...
end

@testsetがブロックとして取れるのはbegin ... endだけでなく、for ... endも取ることができます。 したがって、パラメータaを変えながらテストをしたい場合などは@testset for a in 1:10 ... endとすればよいでしょう。 実はこの機能はちょっと前まで@testloopとして提供されていたのですが、@testsetと統合してはどうかと提案したらすんなり受け入れられて現在はそのようになっています。Juliaってオープンですね(´ε` )

他にも、テストのレポートの仕方を変えるなど様々な拡張が可能になりました。 詳しい仕様は、v0.5のドキュメントを参照してください。

v0.5の便利なユニットテストを今使う

v0.5からは標準で@testsetが使えるようになるわけですが、やっぱり今v0.4で使いたいですね。 そのためには、BaseTestNext.jlを使いましょう。 以下のように書けば、v0.4向けのパッケージでも次世代のBase.Testを使うことができます。

if VERSION >= v"0.5-"
    using Base.Test
else
    using BaseTestNext
    const Test = BaseTestNext
end

Juliaの多分あまり知られてない関数達

Julia Advent Calendar 7日目の記事です。今週ひとりアドベントカレンダーの様相を呈してきているので誰か助けてください。

JuliaのBaseモジュールの関数はたくさんあるため、意外と知られていない関数もあると思います。 ですので、個人的によく使うなぁという関数をピックアップして紹介しようと思います。

開発

versioninfo()

Juliaのバージョンなどを環境を知るのに便利です。 バグ報告などの時はこの情報を必ず添付しましょう。 versioninfo(true)とするともっと詳しく出てきます。

julia> versioninfo()
Julia Version 0.4.1
Commit cbe1bee* (2015-11-08 10:33 UTC)
Platform Info:
  System: Darwin (x86_64-apple-darwin14.5.0)
  CPU: Intel(R) Core(TM) i5-4288U CPU @ 2.60GHz
  WORD_SIZE: 64
  BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell)
  LAPACK: libopenblas64_
  LIBM: libopenlibm
  LLVM: libLLVM-3.3

workspace()

REPLなどで環境をクリアにするのに使います。開発中などに一旦リセットする場合便利でしょう。

julia> x = 100
100

julia> workspace()

julia> x
ERROR: UndefVarError: x not defined

gc_enable()

GCの動作を管理できます。例えば、gc_enable(false)とすれば、GCを止めることができます。 ベンチマークなどのときに便利かもしれません。

数値計算

fld(x, y), cld(x, y)

fld(x, y)x / y して整数へ切り下げ、cld(x, y)x / yして整数へ切り上げる感じです。 浮動小数点数を経由せずに計算するので高速で正確です。

clamp(x, lo, hi)

xをある範囲 [lo, hi] に押し込む関数です。外れ値などを適当にあしらう(?)ときに便利です。

julia> clamp(-10, -1, 2)
-1

julia> clamp(1, -1, 2)
1

julia> clamp(10, -1, 2)
2

関数としては以下の図のような感じです。

f:id:bicycle1885:20151207011650p:plain

quantile(v, ps)

分位数を計算する関数です。何かの計算結果などで、ベクトルの分布を超大雑把に知るのに便利です。

julia> quantile(randn(1000), 0.5)
0.06427123889979461

julia> quantile(randn(1000), linspace(0, 1, 6))
6-element Array{Float64,1}:
 -3.40151
 -0.873353
 -0.265595
  0.215862
  0.776136
  3.97968

文字列

lpad(string, n, p)rpad(string, n, p)

文字stringを固定幅nで出力します。lpadは左側をpで埋め、rpadは右側をpで埋めます。 ちなみにpは省略可能で、省略すると空白文字になります。 アラインメントを取るような出力をするときに便利ですね。

julia> lpad("foo", 6)
"   foo"

julia> lpad("foobar", 6)
"foobar"

chomp(string)

文字列の最後にある改行を削除します。perlにも同名の関数がありますね。 ファイルを一行ずつ読み込んで処理するときに、改行文字を取り除くのに便利です。

for line in eachline(io)
    line = chomp(line)
    ....

その他

cat(dims, A...)

複数の配列A...をある次元dimsで結合します。

julia> cat(1, [1,2,3], [4, 5, 6])
6-element Array{Int64,1}:
 1
 2
 3
 4
 5
 6

julia> cat(2, [1,2,3], [4, 5, 6])
3x2 Array{Int64,2}:
 1  4
 2  5
 3  6

なお、vcat(A....)hcat(A...)もあり、コレらはそれぞれcat(1, A...)cat(2, A...)と同じです。

mark(s)reset(s)

mark(s)でストリームsにマークを付け、reset(s)で前回マークをつけたところまでストリームを巻き戻す事ができます。 ファイルのパースなどで、先読みが必要な場合に便利ですね。ちなみにunmark(s)でマークは消せます。

xdump(x)

オブジェクトxのデータ構造をプリントします。 特に便利なのが式を扱う場合で、マクロを書くときには必須のツールになります。 例えば、import Foo.Bar: baz構文木がどうなってるかを知りたい場合は以下のように知れます。

julia> xdump(:(import Foo.Bar: baz))
Expr
  head: Symbol import
  args: Array(Any,(3,))
    1: Symbol Foo
    2: Symbol Bar
    3: Symbol baz
  typ: Any::DataType  <: Any

now()

文字通り、「今」を返します。「いまッ!」って感じです。

julia> now()
2015-12-07T17:20:31

Japan.R 2015でJuliaの布教してきました

Julia Advent Calendar 6日目の記事です。

昨日のJapan.R 2015のLTでJuliaの布教をしてきました。 5分で55枚のスライドをやり切り、時間ピッタリで無事終えました。

だそうです。

当日の資料はSlideShareにあげてあります:

www.slideshare.net

言いたいことは3点で、

  1. Juliaは速い
  2. コミュニティもパッケージも育ってきている
  3. 最近はJuliaを使っている会社や組織も増えてきた

ということです。 もちろん、これからもJuliaには改善が加えられより良い言語になっていくと思いますが、現時点でもパッケージが作られ、ユーザは増えつつあるようです。 さらに、Juliaの安定版v1.0を作るべく、Julia Computingは$600,000の資金を獲得しています

懇親会では以前からブログ等で知っていた@dhichikaさん、@sinhrksさん、@berobero11さんたちと初めてお会いできて楽しい懇親会になりました。

主催してくださった@gepuroさん、缶コレさん、それに会場を提供してくださったリクルート社さん、本当にありがとうございました。

Joneswareの世界

Julia Advent Calendar 2日目の記事です。

JoneswareというのはJulia界の重要人物のひとりであるdcjonesさんの作ったパッケージをさしています。 実は私のJulia Summer of Codeプロジェクトのメンターになってくれた方で、今年のJuliaConでお会いしたこともあります。

彼の書くプログラムは非常に洗練されていて、その設計やスタイルは非常に学ぶところが多いです。 その上、ハイパフォーマンスなコードばかりで、Juliaで技術計算を始める方は是非参考にしてみると良いと思います。

グラフィックスなど

Gadfly.jl

最初は皆さんご存知のGadfly.jlです。 これはggplot2のような"Grammar of Graphics"のアイディアに則ったプロットのためのパッケージです。 具体例はマニュアルを見ていただけると分かるのですが、簡潔なAPIで目的のプロットを行うことができます。

plot(x=rand(10), y=rand(10), Geom.point, Geom.line)

f:id:bicycle1885:20151201165328p:plain

Compose.jl

Compose.jlベクター画像を作るためのパッケージです。 Gadfly.jlはこのCompose.jlの上に作られています。 Compose.jlそれ自体でかなり有用なパッケージですので、ここでもご紹介しましょう。 Jupyter NotebookIJulia.jlを使うと、実際に以下のプロットを試すことができます。

Compose.jlでは、図形を組み合わせて、ベクター画像を作ります。 たとえば、polygon([(1, 1), (0, 1), (1/2, 0)]は3つの頂点 (1, 1), (0, 1), (1/2, 0) を持つ多角形を作ります。 そして、context()でその図形が置かれる座標系を指定でき、compose()で座標系と図形を組み合わせます: f:id:bicycle1885:20151201171505p:plain

context(x0, y0, width, height)のように座標系を指定できるため、以下のようにcontext(0, 1/2, 1/2, 1/2)とするとy軸方向に1/2ずらした、幅と高さが1/2の座標系となります: f:id:bicycle1885:20151201172045p:plain

複数の図形を組み合わせるのも簡単で、composeの呼び出しをネストするだけです: f:id:bicycle1885:20151201172224p:plain

再帰呼び出しと組み合わせて、シェルピンスキーの三角形のようなフラクタル図形も描けます: f:id:bicycle1885:20151201172341p:plain

fillなどで色などの属性も指定できます: f:id:bicycle1885:20151201172638p:plain

このように複雑な図形を単純な要素の組み合わせで表現できるため、ベクター画像で何かを可視化したい時はこのパッケージを使うと良いでしょう。 Jupyter NotebookではレンダリングのためSVGのバックエンドを使っていますが、Cairo.jlなどを通してPNGなどの画像ファイルを出力することもできます。 また、このパッケージに触発された、3D版のパッケージ Compose3D.jlもあります。

その他

他にもLocal regression (loess) というノンパラメトリックな回帰のパッケージLoess.jlや、YAMLのパーサYAML.jlC言語のようなswitch文を可能にするSwitch.jlも彼のパッケージです。

バイオ関係

Jonesさんはバイオインフォマティクスを研究している博士課程の学生(のはず)なので、バイオ関係のパッケージもいくつも作っています。 ここではそれらのパッケージの紹介をしていきます。

Bio.jl

バイオインフォマティクスのライブラリ、Bio.jlも私にとっては重要です。Jonesさんはこのパッケージの非常に重要な部分を作っています。 このパッケージの紹介はまた今度書きましょう。

JuliaConでのトークは、YouTubeで公開されています。

www.youtube.com

IntervalTrees.jl

IntervalTrees.jlは区間木の実装です。バイオインフォマティクスでは、ゲノムや染色体のある区間を扱いたいことがよくあります。 例えば、ヒトの遺伝子とエキソン領域のアノテーション情報をもとに、見つかった変異がどの遺伝子の何番目のエキソン領域にあるかを知りたい場合などです。

オーバーラップしている区間を取り出すにはintersectを使います:

julia> using IntervalTrees

julia> im = IntervalMap{Int,ASCIIString}()
IntervalTrees.IntervalBTree{Int64,IntervalTrees.IntervalValue{Int64,ASCIIString},64}

julia> im[(1, 100)] = "foo"
"foo"

julia> im[(50, 100)] = "bar"
"bar"

julia> im[(101, 100)] = "baz"
"baz"

julia> collect(intersect(im, (10, 20)))
1-element Array{Any,1}:
 IntervalTrees.IntervalValue{Int64,ASCIIString}
(1,100) => foo

julia> collect(intersect(im, (10, 80)))
2-element Array{Any,1}:
 IntervalTrees.IntervalValue{Int64,ASCIIString}
(1,100) => foo
 IntervalTrees.IntervalValue{Int64,ASCIIString}
(50,100) => bar

このパッケージはBio.jlでもゲノムのアノテーション情報などを保持するのに使われています。

BufferedStreams.jl

BufferedStreams.jlはIOのバッファリングをより積極的に行い、IOを高速化します。 次に述べるLibz.jlやRagelで使われています。

Libz.jl

Libz.jlはzlibへのバインディングですが、速度に非常に重点を置いています。 インターフェースも良い感じで、例えば圧縮されたテキストファイルを一行ずつ扱うには以下のようにできます:

using Libz

let
    filepath = shift!(ARGS)
    open(filepath) do s
        s′ = ZlibInflateInputStream(s)
        for line in eachline(s′)
            @show line
        end
    end
end

Ragel

Ragelは正規言語からパーサを生成するコンパイラです。 と言っても、別に正規文法しか使えないわけではなく、有限オートマトンの状態遷移の間にホスト言語での操作を挟めるため、わりと色々パースできると思います。

このコンパイラ自体はAdrian D. Thurston氏のプロダクトなのですが、そのJulia版サポートを書いたのがJonesさんなわけです。彼はJuliaをRagelに対応させるためにgoto文までJuliaに実装しています。 今のところ、このレポジトリからJulia対応版を使うことができますが、次のRagelのリリースではJuliaが正式にサポートされる予定です。

例えば、FASTA形式のファイルをパースする場合は、以下のように記述することができます:

    action count_line  { state.linenum += 1 }
    action mark        { Ragel.@anchor! }
    action identifier  { Ragel.@copy_from_anchor!(output.name) }
    action description { Ragel.@copy_from_anchor!(output.metadata.description) }
    action letters     { Ragel.@append_from_anchor!(input.seqbuf) }

    newline     = '\r'? '\n'     >count_line;
    hspace      = [ \t\v];
    whitespace  = space | newline;

    identifier  = (any - space)+            >mark  %identifier;
    description = ((any - hspace) [^\r\n]*) >mark  %description;
    letters     = (any - space - '>')+      >mark  %letters;
    sequence    = whitespace* letters? (whitespace+ letters)*;
    fasta_entry = '>' identifier (hspace+ description)? newline sequence whitespace*;

    main := whitespace* (fasta_entry %finish_match)**;

fasta.rl

Ragelを使えば、pure Juliaで高速なパーサを生成することができるため、様々なフォーマットのファイルを扱うバイオインフォマティクスでは大変意義のあるツールです。 正式版が出たら、また解説を書くかもしれません。