Gray-Scott というのを作ってみた記録

Qiitaへ投稿しようかとも思ったが、わからないことだらけなので、おとなしくブログにしておこうと思った。

  • 行列計算 : Numo::NArray
  • GUI : Ruby/GTK3

Git: https://github.com/kojix2/Gray-Scott

 f = 0.04, k = 0.06 の場合は上のような模様が表示される。

 まず、Gray-Scottとは一体何なのか、私にはさっぱりわかっていない。難しいのでNumpyのサンプルをNumo::NArrayに書き換えているだけである。中身はちっともわかっていない。

 書店でこの本を見つけて、買ってしまった。まだ読んでいないのだが、とりあえず一番最初に出てくるGray-Scott がすごい。ググるとWebGLを使ってヌルヌル動くデモがヒットするのだが、素晴らしくて度肝を抜かれた。自分でも作りたくなった。本のサンプルはPythonやNumpyで書かれているので、スピードや見た目よりもわかりやすさ重視である。素人がNArrayに逐語訳して勉強した気になるには最適である。

 CPUだと遅いのでこの機会にCumo/NArrayを試してみようかしらん、とも思ったが、Ubuntu18.10には公式のCudaが提供されてない。Cuda/Nvidia-driverをインストールするときは、高確率でブラックスクリーンに遭遇して時間を消耗するのでせっかく調子よく動いている手元のパソコンでは試さないことにしておく。

 今はRuby/GTKの勉強中なので、Ruby/Tkを使えば簡単なのにという気持ちもあったが、Ruby/GTKで作ってみることにした。

 GNOMEの画像を扱うっぽいオブジェクトはたくさんあって、どれがどういう関係なのか、きちんと把握できていない。まずCairoというライブラリがある。これはサーフェイスを作って、サーフェイスに書き込んで、PNGやPDFに保存するという仕組みらしい。次にPixbufというのがある。これは行列のような感じで、スケールを変更したり、bmpやpngで保存したりといった基本的な機能だけ持っているようである。GtkImageというのが、Gtkで画像を表示するウィジェットらしい。このほかにGtkDrawingAreaというものがある。これはCairoと組み合わせて使うらしい。動画の再生のサンプルなどでもDrawingAreaと組み合わせて使っている例がある。今回DrawingAreaを使うか、GtkImageを使うか迷ったが、StackOverflowで、DrawingAreaよりもGtkImageの方が軽いと主張しているサイトを見つけたので、GtkImageにNArrayから作ったデータを入れたPixbufを流し込むようにしてみた。一瞬RedArrowという単語が頭をかすめたがそんな難しいものを使う必要はないであろう。GtkImageはマウスのイベントを補足してくれないので、マウスの位置情報などを取得したい場合は、イベントボックスを親に配置する必要があるようである。本当にこのやり方が良いのかはわからない。そのほかにClutterとか、Gstreamerとかもあるが、これらはもっと難しそうである。

 さて、Ruby/Gtk が Ruby/Tk と比較して特に優れているところは、Gladeを見ながらGUIを作れるところだと思う。Gladeは不安定でクラッシュしやすいが、メインウィンドウに表示されているウィジェットをあれこれクリックしなければかなりクラッシュの頻度を下げられるという知見を得た。

 今回Gladeで気になったのは「シグナルハンドラー」の欄の右隣にある「ユーザーデータ」という項目である。これが何を意味するのかわからないが、シグナルが呼ばれたときに、一緒にウィジェットを渡せるという意味ではないかと推測している。しかしRuby/GTKではそのようには動作しなかった。使い方が間違っているのかもしれない。Glade は Microsot Office のように項目が膨大なので、使いこなせるようになるにはかなり時間がかかりそうだ。

 そのほか気になったのは、GLib::Timeout.add の部分だ。GUIのライブラリはメインループを回しているのでループしたいときに処理を待つ必要が出てくる。Ruby/Tkの場合はスレッドとの相性が非常に悪いことで有名で、drubyサーバーのプロセスや、処理専用のプロセスを別に立てて動かすとうまくいく。しかし、Ruby/Gtkで遊んでいる人はあまりいないみたいなので、どうすればいいのかわからない。GLibを勉強して、なるべくGLibの仕組みに乗っかるのがいいのか、やっぱりdrubyサーバーを立てるのか、Ruby本体をもっと勉強すればなんとかなるのか‥。そもそもGLibやRubyの非同期処理を理解することは可能なのか。少なくとも、GLib::Timeout.add で秒数を指定するだけだと、処理が終わらなかった時に、フリーズするみたいだ。

 NArray の演算は inplaceを使った方が2割ぐらい早いらしいので、今回は積極的にinplaceを使ってみた。inplaceという表記は長くて、現実的ではないので、横着だけどエイリアスをつけて_(アンダーバー)に置き換えることにした。Alifeの元本では、laplacianの計算に、rollというメソッドを使っていたが、NArrayではこれは未実装であったので、その部分は逐語訳した。そのほか濃度を彩度に変換した方が見栄えがいいのでインターネット上に公開されているNumpyのコードをありがたく参考にして、HSV→RGBの処理をNArrayで書いた(書き写した)が、この時にマスキングの不具合をみつけた。きちんと計測したわけではないが、HSV→RGB部分の処理はかなり時間がかかっているようで、改善の余地があると思う。

 できあがったものは、WebGLに比べるとだいぶ速度は遅いものの、だいたい期待通り動作するようだった。Ruby/Tk で作ったソフトよりも見栄えがいいのが嬉しい。

 さて、これで何を考えるか、というと、いろいろと思うところはあるのである。f や k の値をいろいろ変えて遊んでみたけれども、いずれのパラメータのときも、生命現象に非常によく似ていて、めちゃくちゃ興味深いと思った。でも慌ててなにか考える前にしばらくは頭の中にぼんやりとどめておくことにする。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です