LSD Radix Sortは通常はデータから情報単位(ビット)を抽出しますが、この方法では基数整列のアルゴリズムが見えにくくなるので、今回は大幅に簡略化して配列として処理を行います。
並び変える元データは、8ビットのデータを4列持った配列となります。
DATA_SIZE = 16 BIN_SIZE = 3 W = 4 raw_data = randint(0, BIN_SIZE, DATA_SIZE*W).astype(np.uint8) data = raw_data.reshape((DATA_SIZE, W))
データの数は16として、一時変数tmpで中間処理を保管します。
raw_tmp = np.zeros(DATA_SIZE*W).astype(np.uint8) tmp = raw_tmp.reshape((DATA_SIZE, W))
Nがデータ数、Wが元データのユニット数となります。WはASCIIコードにすると4つの文字を持つ配列を整列する問題となりますが、ここではシンプルに数値の整列を問題とします。
LSDの定義としてデータ配列の右側から整列することになります。この前提ですとW-1, W-2, …, 0というように一つ一つ左に走査・デクリメントしていきます。
従ってアルゴリズムは以下の反復を行います。
for d in reversed(range(W)): //dの列を整列
反復してd列を整列するアルゴリズムが、前述のヒストグラム、Prefix-Sum(up-sweep、down-sweep)、並び替え(Rank)となります。
ヒストグラムはcount変数に保管します。8bitなので、要素数はBIN_SIZE=3に決め打ちできます。
count = np.zeros(BIN_SIZE+1).astype(np.uint32)
ヒストグラムの算出は以下のようにします。
for i in range(0, DATA_SIZE): count[data[i][d] + 1] += 1
Prefix-Sum(up-sweepとdown-sweep)については、シーケンシャルに連続する要素を加算していきます。
for k in range(1, BIN_SIZE): count[k] += count[k-1]
次に「並び替え(Rank)」ですが、元データとその値を、tmpで累積した頻度をマッチしていきます。
for i in range(DATA_SIZE): tmp[count[data[i][d]]] = data[i] count[data[i][d]] += 1
最後に、次のループ処理に移るための準備をします。tmpは添字dの一つに限定して整列したのですが、この整列した結果を元データの配列dataに一旦更新します。
for i in range(DATA_SIZE): data[i] = tmp[i]
tmpは次の反復には新たに整列しなおすので、配列dataは毎回(配列右側から)最も新しい整列を更新していきます。
RadixSortCPUTest.py.
from numpy.random import * # Set the seed to 0 np.random.seed(0) DATA_SIZE = 16 BIN_SIZE = 3 W = 4 raw_data = randint(0, BIN_SIZE, DATA_SIZE*W).astype(np.uint8) data = raw_data.reshape((DATA_SIZE, W)) raw_tmp = np.zeros(DATA_SIZE*W).astype(np.uint8) tmp = raw_tmp.reshape((DATA_SIZE, W)) for d in reversed(range(W)): count = np.zeros(BIN_SIZE+1).astype(np.uint32) for i in range(0, DATA_SIZE): #(1) count[data[i][d] + 1] += 1 for k in range(1, BIN_SIZE): #(2) count[k] += count[k-1] for i in range(DATA_SIZE): #(3) tmp[count[data[i][d]]] = data[i] count[data[i][d]] += 1 for i in range(DATA_SIZE): #(4) data[i] = tmp[i] print(data)
ヒストグラムの計算をします。 | |
ヒストグラムの累積配列を計算(Up-SweepとDown-Sweep)します。 | |
配列を並び変え、tmp配列に一時的に保管します。 | |
tmp配列からa配列に要素をコピーします。 |
上記のサンプルプログラムの出力は以下のようになります。
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/komatsu/PycharmProjects/MyPythonProject/RadixSortCPUTest.py [[0 0 0 2] [0 0 1 1] [0 1 1 1] [0 1 2 2] [0 2 0 0] [0 2 0 1] [1 0 0 0] [1 0 2 1] [1 1 0 2] [1 1 2 2] [1 2 0 2] [1 2 2 0] [2 0 1 2] [2 0 2 1] [2 1 2 1] [2 2 2 2]]
これで整列の確認ができました。
Copyright 2018-2019, by Masaki Komatsu