240 likes | 808 Views
A* アルゴリズムと8パズル. 2010年度情報知能学科 白井英俊. 6. 4. 7. 8. 5. 1. 2. 3. 3. 2. 1. 4. 5. 6. 7. 8. 8パズル. 以下のように8つのタイルと一つのスペースがあり、それぞれに数が書いてある。 タイルを上下左右にすべらせ、最終状態にする。ただし、枠からはみ出してはいけない。. 最終(目的)状態. 初期状態. 最初の数手. 6. 4. 7. 8. 5. 3. 2. 1. 8パズルの 難しさ. 「8パズルの偶奇性」参照. 8. 状態数が多いかなり難しい問題
E N D
A*アルゴリズムと8パズル 2010年度情報知能学科 白井英俊
6 4 7 8 5 1 2 3 3 2 1 4 5 6 7 8 8パズル • 以下のように8つのタイルと一つのスペースがあり、それぞれに数が書いてある。 • タイルを上下左右にすべらせ、最終状態にする。ただし、枠からはみ出してはいけない。 最終(目的)状態 初期状態
最初の数手 6 4 7 8 5 3 2 1
8パズルの難しさ 「8パズルの偶奇性」参照 8 状態数が多いかなり難しい問題 8パズルを、スペースのタイルを「0」と考えれば、0, 1, 2, 3, 4, 5, 6, 7, 8という9つのタイルの並べ方一つ一つがそれぞれ別な「状態」に対応する 9! (= 362,880) 通り もっとも、このうちの半分は最終状態に到達できないため、実際には9!÷2 =181,440通り。それでも多い! しかし15パズルの 16 !÷2 =1.05*1013よりははるかに小さい
8パズルのデータ表現 • この問題のデータ表現は難しくない スペースを 「0」で表すとする 初期状態: state(6,4,7,8,5,0,3,2,1) 最終(目的状態):state(1,2,3,4,5,6,7,8,0) 中段(左、中、右) 下段(左、中、右) 上段(左、中、右)
指し手(move) move(state(0,A,B,C,D,E,F,G,H),state(A,0,B,C,D,E,F,G,H)). move(state(0,A,B,C,D,E,F,G,H),state(C,A,B,0,D,E,F,G,H)). move(state(A,0,B,C,D,E,F,G,H),state(0,A,B,C,D,E,F,G,H)). move(state(A,0,B,C,D,E,F,G,H),state(A,B,0,C,D,E,F,G,H)). move(state(A,0,B,C,D,E,F,G,H),state(A,D,B,C,0,E,F,G,H)). move(state(A,B,0,C,D,E,F,G,H),state(A,0,B,C,D,E,F,G,H)). move(state(A,B,0,C,D,E,F,G,H),state(A,B,E,C,D,0,F,G,H)). move(state(A,B,C,0,D,E,F,G,H),state(0,B,C,A,D,E,F,G,H)). move(state(A,B,C,0,D,E,F,G,H),state(A,B,C,F,D,E,0,G,H)). move(state(A,B,C,0,D,E,F,G,H),state(A,B,C,D,0,E,F,G,H)). move(state(A,B,C,D,0,E,F,G,H),state(A,B,C,0,D,E,F,G,H)). move(state(A,B,C,D,0,E,F,G,H),state(A,B,C,D,E,0,F,G,H)). move(state(A,B,C,D,0,E,F,G,H),state(A,0,C,D,B,E,F,G,H)). move(state(A,B,C,D,0,E,F,G,H),state(A,B,C,D,G,E,F,0,H)). などなど (もちろん、あまり賢い方法ではない---盤面が与えられたら可能な指し手を返すプログラムも書ける)
updateとlegal • これらはほとんど何もしない update(_,State,State). legal(_). でよい • なぜなら、move で可能な状態がすべて記述されている
しかし。。。 • 縦型探索はもちろん、横型探索でも、 insufficient_memory (記憶領域が不足) というエラーメッセージが表示されて、解を求めることができない • これは、(もちろん)データ表現の問題ではなく、探索アルゴリズムの問題である
横型探索の復習 横型探索:次に探索すべき状態はキューの先頭のもの solve_bfs([(State,Moves)|_],History,Moves) :- final_state(State). % 最終状態なら終了 solve_bfs([(State,Moves)|RestAgenda],History,Result) :- findall((NextState,[Move|Moves]),% 可能な指手を収集 nextStates(State,Move,History,NextState),Bag), register (Bag,NewHistory,History), % 履歴の更新 append(RestAgenda,Bag,NewAgenda), % enqueue solve_bfs(NewAgenda,NewHistory,Result). solve_bfs([_|Rest],History,Result) :- % 行き止まりの場合 solve_bfs(Rest,History,Result). % 他の道を選ぶ
A*アルゴリズム • 『横型探索』において、次に探索すべき状態の選び方を工夫する • 評価関数 fの値の最小の状態(s)を選んで次に探索する対象とする f(s) = g(s) + h(s) ここで、g(s)は、sまでのコスト(sに至る指し手の数) h(s) は、状態sから目的状態までの「コスト(指し手の数)の見積もり」(注意:実際の個数より多くてはダメ) このようにすれば、最小のパスが得られることが保証される
A*アルゴリズムの概略 % (状態、評価値、指し手列)を一つの単位として記憶し、 % 評価値に基づいてソートしておく solve_astar([(State,F,Moves)|_],Moves) :- final_state(State). solve_astar([(State,_,Moves)|RestAgenda],Result) :- length(Moves,L), G is L+1, %状態Stateまでのコスト findall((Move,F,[Move|Moves]),% 次の状態候補たち nextStates(State,Move,F,G),Bag), % をBagに入れる register(Bag), %次状態候補を探索済みとして登録 sort(Bag,List), % 得られた状態候補をソート merge(RestAgenda,List,Sorted), % それまでの候補と併せる solve_astar(Sorted,Result). solve_astar([_|Rest],Result) :- solve_astar(Rest,Result).
状態の評価値 次に探索すべき状態を、「縦型探索」や「横型探索」のように無作為に選ぶのではなく、評価値(2枚前のスライドの関数fの値)によって決定する 評価値(f)は、その状態までのコスト(g)と、その状態から目的状態までのコストの見積もり(h)の和として考える 目的状態までのコストの正確な計算は困難なので、ヒューリスティックスが必要ー8パズルではマンハッタン距離が有名
nextStatesとregister, registered nextStates(State,NextState,F,G) :- move(State,NextState), % 可能な「次の」状態 \+ registered(NextState), % 探索済でない dist(NextState,H), % Manhattan距離 F isG+H. % 探索した状態を(Prologのデータベースに)「登録」 register([]):-!. register([(A,_,_)|B]):-assert(memo(A)), register(B). % 状態が既に「登録されている」かどうかの検査 registered(A) :-memo(A),!.
8パズルにおけるマンハッタン距離 • 「1」のタイルを例にマンハッタン距離を求める 6 4 7 8 5 1 3 2 「1」のマンハッタン距離= 1 2 3 4
6 4 7 8 5 3 2 1 マンハッタン距離の計算 問題: 盤面を入力とし、その盤面のすべてのタイル のマンハッタン距離を計算し、その合計を求める述語 dist(State,Cost) を書こう。 これが、その盤面(State)に対する 「目的状態までのコストの見積もり」(Cost)を与える 例題:左の盤面に対し 21 を返す
8パズルの偶奇性 1 2 3 4 5 6 8 7 • 盤面によっては、どうやっても解けないものがある(下図がその例) 参考:http//www.geocities.jp/m_hiroi/puzzle/parity.html
8パズルの偶奇性(続) • 考え方:スペースに注目。8パズルの動きはスペースをどう動かすかで決まる。 スペースを左右に移動 スペースを上下に移動 1 2 3 1 2 3 4 5 6 4 5 8 6 7 7 8 タイルの順番に変動はない タイルの順番の狂いは2個(偶数)
8パズルの偶奇性(続) 別な配置で検証 スペースを左右に移動 スペースを上下に移動 1 2 3 1 2 3 4 5 4 5 6 7 8 6 7 8 タイルの順番に変動はない タイルの順番の狂いは偶数
8パズルの偶奇性(続) 検証:水平移動でも垂直移動でも、順番の狂いは偶数 1 2 3 4 5 6 7 8 問題1. 8パズルの盤面が与えられたとき、それが解けるか どうかを判定するプログラムを書く。 (ヒント:順序が入れ替わっている個数を調べればよい) 問題2.15パズルは、スペースの位置によって順番の交代の 数が異なる。それを考慮した判定プログラムを書く。
課題 • 8パズルを解くプログラムを書く (ウェブページにあるastar.plがヒント) • いろいろな評価関数を工夫し、それらを試してみよう • 評価関数と探索状態数や計算時間との関係を考察する • 提出:2011年1月中(12月中に経過報告)
参考:記憶領域を節約する方法 • IDA* (Iterative Deepening A*) 反復深化A*アルゴリズム 評価値に基づいて、反復する • SMA* (Simplified Memory-bounded A*) 単純化メモリ限定A* 待ち行列の大きさを一定にし、ノードを「忘れる」ことによって、メモリを節約する