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] += 1Prefix-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