高速に2D描画したかったら何がいいの?

今度は2次元格子上のエージェントを扱いたいので、出来るだけ高速に格子オブジェクトを描画したい。
後の拡張性はとりあえずなくてもよい。今のところWindowsで動かしたい。
使う言語も速い方がよいが、まあC#くらいなら良いかなあと思って、何個か速度を比較してみた。
やっぱり、標準のAPIは遅いし、Siv3Dもあと一歩というところ。
なので、今回はOpenGLを使ってみたいと思う。


指標は、1秒間に3x3の正方形を何個描けるか(Sq/s)で比較した。
環境はVisual Studio Community RC2017。特に平列化は行わず、Releaseビルドにしたもの。
実装の詳細は適当なので割愛する。ガチガチにチューニングすればずっと改善するかも知れないけど、あくまで目安として。

言語 実装 スループット
C# WPF DrawRectangle 384k
C# WPF bitmap直接 12.8M
C++ Siv3D 27.5M
C++ OpenGL 64.0M

仮想環境のlinuxにHDDを追加する

仮想環境のHDDって最低限しか確保しないので、もっと必要な時は追加のディスクを接続したくなる。こうしておけば、仮想環境を更新した場合でも、作業用のHDDファイルを接続し直せばすぐに作業を継続できる。次の手順でHDDを追加する。

  • 仮想マシン設定からHDDを追加する。容量などは適当に設定する。
  • 接続したらfdiskでパーティションを切って、mkfs.ext4なりでフォーマットする。
  • e2label /dev/sdx hoge などとしてラベルを付ける。
  • マウントポイントを/mnt/hoge などに作っておく。
  • /etc/fstabに hoge /mnt/hoge ext4 defaults 0 0 といった行を追加する。
  • sudo mount hoge でマウントする
  • chown /mnt/hoge user:user /mnt/hoge とかする。

これで、従来のパスと同様に使える領域が出来る。マウントするのにroot権限が必要だが、自動でマウントされるので気にならないはず。以前はchownする必要があるところ、マウントオプションにuserを付けるとnoexecが自動設定されることに引っかかって実現できないでいた。


参考はこの辺とかこの辺

2点を通る直線、直線と点の距離

(defun def-line (p1 p2)
  "2点を通る直線を定義する。
   2点 p1(x1 y1) p2(x2 y2) が与えられたとき、ax + by + c = 0 を満たす(a b c)を返す。"
  (let ((x1 (car p1))
    (y1 (cadr p1))
    (x2 (car p2))
    (y2 (cadr p2)))
    (list (- y2 y1) (- x1 x2) (- (* x2 y1) (* x1 y2)))))

(defun line-point-distance (l p)
  "線l(a b c) と点p(x0 y0)の距離を求める。"
  (let ((a (car l))
    (b (cadr l))
    (c (caddr l))
    (x0 (car p))
    (y0 (cadr p)))
    (/ (abs (+ (* a x0) (* b y0) c))
       (sqrt (+ (expt a 2) (expt b 2))))))

強化学習

実際のところ良く分かってないので、半分想像で。


強化学習は、複数の選択肢があるときに、最も利益の高い選択肢を学習する手法である。予め答えを与えなくても学習が進んでいくことが特徴。


ここで、次のようなゲームを考える。A,Bがいて、5つのカードを持つ。1ターンごとに手札を1枚見せ、その得点を得る(手札は捨てない)。カードは10点、20点,30点,40点,50点。合計100点得たら勝ちとする。


もちろん、50点だけ出し続ければ良いのだが、学習していないAIには価値が分からない。


まず、AIは全てのカードを等価値だと仮定する。そこからランダムにカードを出す。そのうち、A,Bどちらかが勝つので、勝った方の真似をする。つまり、勝った方が出したカードを出す確率を少し上げ、他を下げる。


これを続けていくと、最も強いカードを覚えることができる。問題自体は多腕バンディット問題に近いイメージで。

; 得点 選択確率
(defvar hand '((10 20) (20 20) (30 20) (40 20) (50 20)))
; 選択確率は1未満にはならない。

; 手 得点 選択手
(defun make-ins ()
  (list hand 0 nil))
(setq o (make-ins))

(defun action (this)
  (let* ((p (random 100))
     (h (car this))
     (act (car h)))
    (dolist (i h)
      (decf p (cadr i))
      (if (minusp p)
      (return (setq act i))))
    (incf (cadr this) (car act))
    (push act (caddr this))))

(defun win-p (this)
  (<= 100 (cadr this)))

(defun learn (this)
  (dolist (a (caddr this))
    (incf (cadr a)))
  (let ((n (length (caddr this)))
    (m (length (car this))))
    (while (plusp n)
      (let ((p (elt (car this) (random m))))
    (when (< 1 (cadr p))
      (decf (cadr p))
      (decf n))))))

(let ((hand '((10 20) (20 20) (30 20) (40 20) (50 20))))
  (dotimes (i 100)
    (let ((a (make-ins))
      (b (make-ins)))
      (while (not (or (win-p a) (win-p b)))
    (action a)
    (action b))
      (if (win-p a)
      (learn a)
    (learn b))
      (format t "~a~%" hand) ; 現在の選択確率を表示
      hand)))
((10 19) (20 19) (30 20) (40 21) (50 21))
((10 19) (20 19) (30 20) (40 20) (50 22))
((10 19) (20 18) (30 21) (40 20) (50 22))
((10 19) (20 18) (30 22) (40 19) (50 22))
.
.
.
.
((10 1) (20 1) (30 6) (40 1) (50 91))
((10 1) (20 1) (30 5) (40 1) (50 92))
((10 1) (20 1) (30 4) (40 1) (50 93))
((10 1) (20 1) (30 3) (40 1) (50 94))
((10 1) (20 1) (30 2) (40 1) (50 95))

この方法は、勝った方を生かすという、淘汰法に近い行程が入る。そのため、最終的な評価結果だけで学習が行えるのだろう。一方で、これだけ単純な問題でも学習に時間がかかるとか、行動を覚えていないと学習できないという問題がある。選択肢の取り方は人為的なので、問題を構造化する役にも立っていない。複雑な問題へ応用するにはどうしたらよいだろうか。

人工生命の生態シミュレーション

大分前になるが、こういうものを作っていた。


D


これでやりたかったのは、生態系の中で、動作を獲得していく過程のシミュレーションである。
この結果、捕食関係にあまり関係なく、璧に引っかからないようにぐるぐる回るように進化していった。


そりゃ視線から判断できることは2次元だと限られるし、それをうまく利用するほどの思考力も持っていない。
その仕組みの中で十分な適応をしているとは思う。


ここで、物理シミュレーション上で動作を作っていくのは思っていたより難しいな、と感じた。
もちろん、捕食すべき相手が何かとか、壁に当たるとどうなるかとか、相手の方向といった情報を与えてやったり、
相手に近づくためにどうすべきか、壁にぶつからないようにするにはどうしたらよいか、
ということを強えてやればもっとうまく動いてくれるだろう。しかし、それでは当たり前すぎて面白くない。

それで、どうするの?

物理シミュレーション世界は難しすぎる。うちが実現したいのは、動作を含めて進化させ、
生態系っぽい感じを出すことだ。つまり、世界のルールがどうなっていようが構わない。
そこで、もっと単純なルールの中で、進化していくエージェントを考える。


例えば、RPG・・・のより単純な、アリーナ形式のゲームを考える。
各エージェントは訓練をして、アリーナで1対1で戦い、報酬を得る。
多くの報酬を得たエージェントはやがて、子孫を残して引退する。
弱者のエージェントは花開くことなく引退する。


このゲーム上で、構えとか属性とか戦略により、3すくみ的な関係があれば、トレンドによって
強いエージェントが弱くなったり、戦略を適応していかないと生き残れないとか、そういった動きが見られるはずだ。
物理的な動作を考えなくて済む分、より簡単だろう。


これを上記動画と同じカテゴリに含めて良いのかという問題があるが、うちとしては同じ種類に入ると考えている。