A*アルゴリズムの原理

最短経路探索などでよく使われている「A*アルゴリズム」について紹介します。

A*(A-star)経路探索とは

A-starアルゴリズムは、Peter E, Hartらによって提案された経路探索アルゴリズムです。
各頂点nからゴールまでの距離の推定値h^*(n)を知っていた場合に対して最短経路問題を効率的に解くことができます。
このアルゴリズムでは、スタートノードからあるノードnを通ってゴールノードまでたどり着くときの最短経路を考えます。

A*アルゴリズムの処理手順

A-starアルゴリズムの大まかな処理の流れは以下の通りです。

① スタートノードS、ゴールノードG、Openリスト、Closeリストを用意する。
② SをOpenリストに追加する。
・Sの推定コストf^*(S)を以下の計算式で求める。

(1)   \begin{eqnarray*} f^{<em>}(S)=g^</em>(S)+h^{<em>}(S)=0+h^{</em>}(S)=h^{*}(S) \end{eqnarray*}

③ Openリストが空なら探索失敗として終了する。そうでなければ、Openリストから最小のf^*(n)を持つノードを抽出し、これを親ノードnとする。
・親ノードnがゴールノードGと同じ(n=G)なら探索処理を終了して手順⑥へ進む。そうでなければ親ノードnをOpenリストから削除してCloseリストに追加する。
・親ノードnに隣接する移動可能な全てのノードを子ノードmとする。
④ 全ての子ノードmの仮推定コストf'(m)を以下の計算式から求める。

(2)   \begin{eqnarray*} f'(m)=g^<em>(n)+h^</em>(m)+COST(n,m)\\ ($g^<em>(n)=f^</em>(n)-h^*(n)$) \end{eqnarray*}

・状態と仮推定コストf'(m)の値に応じて、各子ノードmに対して(a)~(d)のいずれかの操作を行う。

(a)「子ノードm状態がNone」の場合
f^*(m)=f'(m)とする。
・子ノードmをOpenリストに追加する。
・子ノードmの親をnとして記録する。

(b)「子ノードm状態がOpen」かつ「f'(m)<f^<em>(m)」の場合
f^</em>(m)=f'(m)に置き換える。
・子ノードmの親をnとして記録する。

(c)「子ノードm状態がClose」かつ「f'(m)<f^<em>(m)」の場合
f'(m)<f^</em>(m)ならf^*(m)=f'(m)に置き換える。
・子ノードmをCloseリストから削除してOpenリストに追加する。
・子ノードmの親をnとして記録する。

(d)上記以外の場合は何もしない。

⑤ ③以降を繰り返す。
⑥ 探索終了後、ゴールノードGから記録しておいた親ノードnを順次辿ると最短経路が得られる。

ノードn:親ノード
ノードm:子ノード(親ノードnに隣接している移動可能なノード)
h^<em>(m):親ノードnからゴールノードまでの推定最小コスト(最短距離)
g^</em>(n):スタートノードから親ノードnまでの推定最小コスト(最短距離)
COST(n,m):親ノードnから子ノードmへ移動するときのコスト(距離)
f^<em>(m):スタートノードから子ノードmを経由してゴールノードに到達するまでの推定最小コスト(最短距離)
f'(m)f^</em>(m)の候補値でf'(m)=g^<em>(n)+h^</em>(m)+COST(n,m)で算出
ステータス:ノードの状態(初期状態:None、計算中:Open、計算済:Close)
Openリスト:状態がOpen(計算中)のノードを格納するリスト
Closeリスト:状態がClose(計算済み)のノードを格納するリスト

A-starアルゴリズムの計算例

今回の計算例では、各推定値を以下の値で計算します。

h^<em>(m):子ノードnからゴールノードGまでのマンハッタン距離
g^</em>(n):スタートノードSから親ノードnまでのマンハッタン距離
COST(n,m):1
f'(m)f'(m)=g^<em>(n)+h^</em>(m)+COST(n,m)=g^<em>(n)+h^</em>(m)+1
f^<em>(m):子ノードmが複数ある場合、それぞれのf'(m)の中で最も小さい値
(子ノードmが1の場合はf^</em>(m)=f'(m))

1.スタートノード、 ゴールノード、Openリスト、Closeリストを用意

今回の数値例では、以下のような縦横5マスの地図を対象としてS~Gの最短経路を求めます。
(斜め移動は可能:8方向移動、障:障害物で移動不可)
sr0
元地図から各ノードの「状態と推定コストを記録するマップ」と「親ノードの位置を記録するマップ」を用意します。
「状態と推定コストを記録するマップ」がスタートノードS、 ゴールノードG、Openリスト、Closeリストに相当します。
sr1_1sr1_2

2. スタートノードのOpenリスト追加と推定コスト計算

スタートノードSの状態をNoneからOpenにします。(Openリストに追加)
スタートノードSの親ノードの位置を記録します。(Sに親ノードはないのでNull)
sr2_1
sr2_2
f'(S)を計算します。(Sは1つしかないのでf^<em>(S)=f'(S)となる)

(3)   \begin{eqnarray*} g^</em>(S)&=&0\ h^<em>(S)&=&5\ f^</em>(S)&=&f'(S)=g^<em>(S)+h^</em>(S)+1=0+5+1=6 \end{eqnarray*}

g^<em>(S)はスタート地点なので0となります。
h^</em>(S)は障害物は無視したスタートノード(S)とゴールノード(G)のマンハッタン距離なので5となります。
よって、f^*(S)は6になります。(Sの推定コスト6をマップに記録)
sr3_1
sr2_2

##3. 親ノードと子ノードの決定
マップにはOpen状態のノード(スタートノードS)があります。(=Openリストは空でない)
よって、探索は続行します。
Open状態のノードはスタートノードSしかないため、これを親ノードnに設定します。
n\neq Gなので、探索終了せず親ノードSの状態をCloseにします。(Closeリストに追加)
親ノードSに隣接する移動可能な全てのノードを子ノードmに選びます。
sr4_1
sr3_2

4. 子ノードの探索

全ての子ノードmの仮推定コストf'(m)を計算します。(mは5つあるのでf'(m)も5つ計算)

(4)   \begin{eqnarray*} h^<em>(S)&=&5\ g^</em>(n)&=&g^<em>(S)=f^</em>(S)-h^<em>(S)=6-5=1\ f'(m)&=&g^</em>(n)+h^<em>(m)+1=h^</em>(m)+2 \end{eqnarray*}

上式より子ノードmからゴールノードまでのマンハッタン距離を計算すればf'(m)が求まります。
(例:子ノード(0,0)の場合、m~Gのマンハッタン距離は7なので推定コストは9となります。
5つの子ノードmの状態はNoneなので、f<em>(m)=f'(m)とし ます。(f^</em>(m)の値はマップに記録)
また、5つの子ノードmの状態をOpenにします。(Openリストに追加)
5つの子ノードmの親ノードSをマップに記録します。
sr5_1sr4_2

3. 次の親ノードと子ノードの決定

マップにはOpen状態のノードが5つあります。(=Openリストは空でない)
よって、探索は続行します。
状態がOpenで推定コストf^*(n)が最小なノードを次の親ノードnに設定します。
親ノードの条件を満たすノードは(2,0), (0,0)の2つあります。
どちらを選んでもいいですが、今回はノード(2,0)を親ノードにして計算します。
親ノード(2,0)はGと同じではないので、探索は終了せず親ノード(2,0)の状態をCloseにします。(Closeリストに追加)
親ノード(2,0)に隣接する障害物以外のノードを子ノードに選びます。
3-2

4. 次の子ノードを探索

f'(m)を計算します。(子ノードmは3つあるのでf'(m)を3つ計算する)

(5)   \begin{eqnarray*} h^<em>(S)&=&5\ g^</em>(n)&=&f^<em>(n)-h^</em>(n)=7-5=2\ f'(m)&=&g^<em>(n)+h^</em>(m)+1=h^*(m)+3 \end{eqnarray*}

よって、2つの子ノードmからゴールノードまでのマンハッタン距離を計算すればf'(m)も求まります。
(例:子ノード(1,0)~ゴールノードGのマンハッタン距離は6なのでこのノードの推定コストf'(m)は9(=6+3)となります。

3つの子ノードmのうち、(3,0),(3,1)の状態はNoneなので、f<em>(m)=f'(m)とします。(f^</em>(m)の値はマップに記録)
(3,0),(3,1)の状態をOpenにします。(Openリストに追加)
(3,0),(3,1)の親ノードSをマップに記録します。

残り1つの子ノード(1,0)の状態はOpenで仮推定コストf'(m)は9です。
前回の計算結果よりf^<em>(m)は8なのでf'(m)>f^</em>(m)となります。
よって(1,0)に関しては何も操作を行いません。
sr6_1
sr5_2

5. 探索の繰り返し

以後、「3.次の親ノードnと子ノードnを決定」→「 次の子ノードmを探索」を繰り返していきます。
すると、何回か繰り返すうちに親ノードnがゴールノードmに到達します。(探索終了)
その時のマップは以下のようになります。
sr7_1

sr6_2

6. 親ノードを辿って経路を求める

親ノードを記録したマップを用いて、ゴールノードGから親ノードnを辿っていきます。
(ゴールノード(4,3)の親ノードは(4,2)(4,2)の親ノードは(3,1)・・・)
すると、最終的にスタートノードSまでたどりつきます。これが最短経路の各座標となります。

(4,3)→(4,2)→(3,1)→(2,0)→(1,1)

sr9_1
sr9_2
以上で、A*アルゴリズムの説明は終わりとなります。

コメント