ライフゲーム続き

改善点

速度向上
インデックスのテーブル と 行列はベクトルであること を利用して outer を消した。そのおかげで apply の回数が 縦セル×横セル から 縦セル になった.。
状態の継続
前回は f() を実行するたびに初期状態から始まっていたが、2回目以降の f() は前回の終了状態から継続するようにした。
自動リセット
おなじ状態を繰り返すようになったら、ランダムなセルを「生」にして変化がおきるようにした。
> summaryRprof(tmp)
life_game2 <- function(x=40, y=40, a=2) {
	m  <- matrix(sample(c(rep(0,9),1),x*y,TRUE), y, x)
	om <- matrix(0, y * x, a)
	
	#インデックスの行列作成
	make_idx <- function(v) {
		rbind(
			c(tail(v, 1), head(v,-1)),
			v,
			c(tail(v,-1), head(v, 1)) )
	}

	xidx <- make_idx(1:x)
	yidx <- make_idx(1:y)
	
	nextstep <- function(m) {
		livings <- t(sapply( 1:y, function(i){
			# y×x の行列から 3×3x の行列を作って、9×x の行列にしたあと列ごとの和をとる
			row_livings <- colSums( matrix(m[yidx[,i], as.vector(xidx)],ncol=x) )
		}))
		ifelse(livings==3, 1, ifelse(livings==4, m, 0))
	}

	function(n=100) {
		for (i in 1:n) {
			# 過去 a 回と比較して、どれかと同じならランダムにセルを生にする
			if (any(apply(om == as.vector(m), 2, all))) {
				m <<- ( m+matrix( sample(c(rep(0,16),1),x*y,TRUE),y ) ) %% 2
			}
			# 過去 a 回の状態を保存
			om <<- cbind(as.vector(m), om[,seq(a)])
			m <<- nextstep(m)
			image(m)
		}
	}
}
f <- life_game2()
f()
f()

スピードは約2倍になった。

> system.time(life_game()())
ユーザ   システム       経過  
6.75       3.26      10.57 
> system.time(life_game2()())
ユーザ   システム       経過  
  2.41       2.97       5.75 

apply を呼ぶ回数を x×y 回から y 回 に減らしたから、もっと速くなると思ったけど、意外と速くならないな。

もう少し速くできないか、と思ってプロファイラーで調べてみると、

> summaryRprof()
$by.self
               self.time self.pct total.time total.pct
			   image.default       3.28     63.3       4.24      81.9
			   axis                0.46      8.9       0.50       9.7
			   colSums             0.26      5.0       0.64      12.4
			   plot.new            0.24      4.6       0.24       4.6

描画の image で 80% 以上時間を使っていた、これ以上の最適化は意味なさそうなのでこれで終わり。