1 / 23

探索問題のいろいろ

探索問題のいろいろ. 白井英俊. 人食い人と宣教師. 状態の表現 mandc( ボートの位置、 左岸の宣教師と人食い人の 人数 のリスト、   右岸の宣教師と人食い人の 人数 のリスト) 初期状態 : mandc(left, [3,3], [0,0]) 目的状態 : mandc(right,[0,0],[3,3]). 初期・最終状態の表現と プログラムの実行. 縦型探索のプログラムを見てみよう test_dfs(Problem,Moves) :- initial_state(Problem,State),

meghan
Download Presentation

探索問題のいろいろ

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 探索問題のいろいろ 白井英俊

  2. 人食い人と宣教師 • 状態の表現 mandc(ボートの位置、 左岸の宣教師と人食い人の人数のリスト、   右岸の宣教師と人食い人の人数のリスト) 初期状態: mandc(left, [3,3], [0,0]) 目的状態: mandc(right,[0,0],[3,3])

  3. 初期・最終状態の表現とプログラムの実行 縦型探索のプログラムを見てみよう test_dfs(Problem,Moves) :- initial_state(Problem,State), solve_dfs(State,[State],Moves). これは、?- test_dfs(A,B). という実行を要求している。また、初期状態はinitial_state(Problem,State) という表現であることを要求している。だから、

  4. これは何でもよい 初期・最終状態の表現とプログラムの実行(続) 初期状態は、 initial_state(mandc, mandc(left, [3,3], [0,0])) としなければならない また、これにより実行は、 ?- test_dfs(mandc, X). であって、Xには解までの『指し手のリスト」が返される

  5. アルゴリズム:縦型探索 % solve_dfs(状態、過去の状態列、指手列) solve_dfs(State,History,[]) :- final_state(State). % 最終状態なら終了 solve_dfs(State,History,[Move|Moves]) :- move(State,Move), % 次の指し手を選択 update(State,Move,State1), %新状態を求める legal(State1), %新状態は条件遵守している \+ member(State1,History),%未探索の状態 solve_dfs(State1,[State1|History],Moves).

  6. 宣教師と人食い人問題における『指し手表現』宣教師と人食い人問題における『指し手表現』 • 指し手を「狼山羊キャベツ問題」にならって 「 move(状態、積荷)」で表すことにしよう • すると(「農夫だけ移動」というのがないので) • 積荷を選ぶ: move(mandc(left,L,R), Cargo) :- transport(L, Cargo). % 左岸の場合 move(mandc(right,L,R), Cargo) :- transport(R, Cargo). %右岸の場合 • ここで、transport(X,Y)とは、Yから、移送可能な「宣教師と人食い人の人数の組合せ」を返すものとする • Moveの第二引数は、[M,C]というリスト---宣教師の人数Mと人食い人の人数C

  7. 「指し手表現」の続き • 左岸でも右岸でも、積荷の状態を [ M, C ] で表していることに注意。たとえば初期状態: mandc(left, [3,3], [0,0]) と 目的状態mandc(right,[0,0],[3,3])では、 [3, 3] --- 宣教師も人食い人も3人ずついる [0, 0] --- 宣教師も人食い人も0人(いない) ことを表している

  8. 「指し手表現」の完成 • ボートは二人乗りだから、ボートの中の宣教師と人食い人の「可能な」状態は、 の5通りとなるーーー確かめよ。   これを考えると、 transport(Cargo, MC) は次のように書ける: (1) [2, 0] (2) [1, 0] (3) [1,1] (4) [0, 1] (5) [0, 2]

  9. 「指し手表現」の完成 • ボートに乗れる人数の制限 capacity([2,0]). capacity([1,0]). capacity([1,1]). capacity([0,1]). capacity([0,2]). • 運べる組み合わせ transport([M,C],[M1,C1]) :- capacity([M1, C1]), % ボートの人数制限 M >= M1, C >= C1. % 岸の人数からの制限

  10. ここでPrologの組み込み述語の紹介: findall • findall(型, 式, 変数) 「式」がtrueとなるそれぞれの場合に対し、」「型」の例示化のリストと「変数」とを単一化する • 例: findall(k(X), append(X,Y,[a,b,c]), Z). => Z=[ k([ ]), k([a]), k([a,b]), k([a,b,c) ] • 参考: findallの仲間にbagofとsetofがある。違いを調べてみよう。

  11. アルゴリズム:縦型探索 % solve_dfs(状態、過去の状態列、指手列) solve_dfs(State,History,[]) :- final_state(State). % 最終状態なら終了 solve_dfs(State,History,[Move|Moves]) :- move(State,Move), % 次の指し手を選択 update(State,Move,State1), %新状態を求める legal(State1), %新状態は条件遵守している \+ member(State1,History),%未探索の状態 solve_dfs(State1,[State1|History],Moves).

  12. 人食い人と宣教師の問題における『状態更新』人食い人と宣教師の問題における『状態更新』 • 状態更新を (狼山羊キャベツ問題に倣い) update(状態, 積荷, 新状態) で表す update(mandc(B,L,R),Cargo,mandc(B1,L1,R1)) :- update_boat(B, B1), % ボートの位置 update_banks(Cargo,B, L,R,L1,R1). % 積荷の状態

  13. 人食い人と宣教師問題における『状態更新』 ボートの位置の変化: update_boat(left, right). update_boat(right, left). 積荷の変化: update_banks([M,C],left, [ML,CL],[MR,CR],[ML1,CL1],[MR1,CR1]) :- ML1 is ML – M, CL1 is CL – C, MR1 is MR+ M, CR1 is CR+ C. update_banks([M,C],right [ML,CL],[MR,CR],[ML1,CL1],[MR1,CR1]) :- 書いてみよう

  14. updateのチェック transportの時にやったように、update_banksやupdateでも、ちゃんと動いているかをチェックしよう。 ここで、updateはupdate_banksを使っているので、update_banksがちゃんと動いていなければ、updateも動くはずがない! ?-update_banks([1,1],left,[2,2],[1,1],L,R). ?-update_banks([1,1],right,[2,2],[1,1],L,R). が正しい答えを返すかどうかを調べて、必要ならプログラムを直そう。その後、updateも同様に直そう。

  15. アルゴリズム:縦型探索 % solve_dfs(状態、過去の状態列、指手列) solve_dfs(State,History,[]) :- final_state(State). % 最終状態なら終了 solve_dfs(State,History,[Move|Moves]) :- move(State,Move), % 次の指し手を選択 update(State,Move,State1), %新状態を求める legal(State1), %新状態は条件遵守している \+ member(State1,History),%未探索の状態 solve_dfs(State1,[State1|History],Moves).

  16. 宣教師と人食い人問題における『状態の検査』宣教師と人食い人問題における『状態の検査』 • どの岸においても、「宣教師がいる以上は、宣教師の人数>=人食い人の人数」であることを検査 legal(mandc(left,[ML,CL],[MR,CR])) :- legal_sub(ML,CL), legal_sub(MR,CR). % 宣教師の人数と人食い人の人数を比較 legal_sub(0,_):-!. % 宣教師がいない場合はOK legal_sub(M,C) :- 条件を書いてみよう

  17. Legal述語のチェック • legal述語は、問題の制約条件を記述しているので、ここをミスすると、問題が解けていないのに、答え(らしきもの)が出てしまう。 • だから、ここのチェックも欠かせない。 • まず、legal_sub(0,2)、 legal_sub(1,1), legal_sub(1,2) などがどのような答えを返すかをチェックし、必要ならプログラムを直す • 同様に legal(mandc(left,[1,2],[2,1]))などがどのような答えを返すかチェックしよう。

  18. 探索方法を変えてみよう:横型探索 % (状態, 指手の列) を一つの塊とする % :-solve_bfs([(初期状態, [ ] )], [ ], Moves). で起動 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). % 他の道を選ぶ

  19. 横型探索(続) % nextStates(状態,指手,履歴(過去の状態列),他選択肢) % 指手を選び、次状態を求める nextStates(State,Move,History,NextState) :- move(State,Move), update(State,Move,NextState), legal(NextState), \+ member(NextState,History). % register(Agenda,NewHistory,OldHistory) % nextStatesで求めた(次)状態を履歴に登録 register([],X,X). register([(S,_)|R],[S|Y],X) :- register(R,Y,X).

  20. くどいようですが。。。 • 縦型探索でも横型探索でも「過去に調べた状態すべて」を History という引数に記憶し、memberを使ってある状態が『過去に既に調べたものかどうか』を検査している。 • しかし、上の方法は、記憶すべき状態数が多い場合は、あまり効率的とはいえない。 • 前に述べたように、Prologのデータベースを使って、『過去に調べた状態』を記憶したり、検査したりする方法の方が役に立つことが多い。

  21. 宿題(12月中) • 嫉妬深い夫の問題(簡略版)  「ある洪水で、3組の夫婦が水に囲まれてしまった。彼らは、その状態からボートで脱出しなければならないが、ボートには一度に二人しか乗ることができない。どの夫も嫉妬深く、彼自身が一緒にいない限り、ボートでも岸でも妻が他の夫といることを許さない。この3組の夫婦を脱出させる方法を求めよ」 レポートはメールで送信。題目を HW-J3 とすること。 (次の問題を解いて、この代わりとしても良い) • 状態表現として jealous(ボートの位置、左の岸にいる男と女のリスト、右の岸にいる男と女のリスト) を使う。(これ以上の詳しい表現方法は各自工夫すること) 注意:宣教師と人食い人問題と同様に「人数」だけで状態を表すことができるだろうか?そうでないとすればどのように表現したらよいだろうか?

  22. 嫉妬深い夫の問題(5組版) 「ある洪水で、5組の夫婦が水に囲まれてしまった。彼らは、その状態からボートで脱出しなければならないが、ボートには一度に3人しか乗ることができない。どの夫も嫉妬深く、彼自身が一緒にいない限り、ボートでも岸でも妻が他の夫といることを許さない。この5組の夫婦を脱出させる方法を求めよ」 これを解き、適切な解説をつけた報告を12月中に送ってきたものにボーナス点(最大20点) レポートはメールで送信。題目を HW-J5とすること。

  23. 次の問題 • 今までは計算機の力に任せて問題を解いていた:「アルゴリズム」の問題 • 計算機の力任せで解くには難しい問題として、8パズルや15パズルを考えよう。 1 2 3 4 1 2 3 5 6 7 8 4 5 6 9 10 11 12 7 8 13 14 15

More Related