ライフゲーム / Python / numpy.convolve() でムーア近傍の和を求める

scipy.signal.convolve2d()は使わずにnumpy.convolve()でムーア近傍の和を求めてみる。numpy.convolve()は1次元にしか使えないので次のように計算する。

import numpy as np
from scipy.signal import convolve2d

def moore(mat):
    # 現世代排列を取り込んで、念のためndarrayにしておく。
    mat = np.asarray(mat, dtype=np.uint8)
    numOfRows, numOfCol = mat.shape
    
    # 現世代排列よりも一回り大きい空排列を作って、
    matFat = np.empty(np.asarray(mat.shape)+2, dtype=np.uint8)

    # その空排列を利用して現世代排列の上下左右をコピーし合う。
    matFat[1:numOfRows+1,1:numOfCol+1] = mat
    matFat[0]    , matFat[-1]     = matFat[-2]    , matFat[1]
    matFat[:,[0]], matFat[:,[-1]] = matFat[:,[-2]], matFat[:,[1]]
    origin = matFat.copy()

    numOfRows, numOfCols = matFat.shape
    matFat = matFat.reshape(matFat.size)               # トーラス排列を1行排列に変更して、
    matFat = np.convolve(matFat, [1,1,1], mode="same") # 自分と両隣との和を求めて、
    matFat = matFat.reshape(numOfRows, numOfCols)      # また元の形状の排列に戻して、
    matFat = matFat.T                                  # 今度は自分と上下との和を求めたいので、排列を転置して、
    matFat = matFat.reshape(matFat.size)               # また1行排列に変更して、
    matFat = np.convolve(matFat, [1,1,1], mode="same") # 自分と両隣との和(元の排列で言えば自分と上下との和)を求めて、
    matFat = matFat.reshape(numOfCols, numOfRows)      # またもとの形状の排列に戻して、
    matFat = matFat.T
    return (matFat - origin)[1:-1, 1:-1] # (ここまでの計算では周囲8セルと自分との和を計算したことになるので)自分自身を引いて最外周を削って返す。
    

#################################################
a = np.random.randint(0, 2, [7, 10])
a1 = convolve2d(a, [[1,1,1],
                    [1,0,1],
                    [1,1,1]], mode="same", boundary="wrap")
a2 = moore(a)

print(a)
print(a1)
print(a2)
print(np.equal(a1, a2))

実行結果:
上から
「現世代排列」
「scipy.signal.convolve2d()によるムーア近傍の和」
「numpy.convolve()によるムーア近傍の和」
「両者の全セルの比較」
f:id:ti-nspire:20181023084128p:plain:w400