AI編程范式 第4章 GPS:The General Problem Solver(三)

4.12 新的問題來了:猴子和香蕉問題

為了顯示我們的GPS真的是通用的,需要在不同的問題中檢驗。我們來看一看一個經典的AI問題,最初是由Saul Amarel在1968年提出的。想象下面的場景:一只饑餓的猴子正站在一個房間的門口,在房子的正中間房頂上,用繩子吊著一串香蕉,剛剛好高度是猴子夠不著的。在門附近有一把椅子,足夠輕便,猴子推得動,也足夠高度,猴子可以站在上面拿到香蕉。為了讓事情再復雜些,假設猴子手里拿著一個玩具球,而且規定一次只能在手里持一件東西。
在嘗試表現這樣的場景的時候,我們可以靈活選擇把什么放到當前狀態,把什么放進操作符。假設我們如此定義操作符:

(defparameter *banana-ops*
?(list
? ?(op ‘climb-on-chair
? ? ?:preconds ‘(chair-at-middle-room at-middle-room on-floor)
? ? ?:add-list ‘(at-bananas on-chair)
? ? ?:del-list ‘(at-middle-room on-floor))
? ?(op ‘push-chair-from-door-to-middle-room
? ? ?:preconds ‘(chair-at-door at-door)
? ? ?:add-list ‘(chair-at-middle-room at-middle-room)
? ? ?:del-list ‘(chair-at-door at-door))
? ?(op ‘walk-from-door-to-middle-room
? ? ?:preconds ‘(at-door on-floor)
? ? ?:add-list ‘(at-middle-room)
? ? ?:del-list ‘(at-door))
? ?(op ‘grasp-bananas
? ? ?:preconds ‘(at-bananas empty-handed)
? ? ?:add-list ‘(has-banans)
? ? ?:del-list ‘(empty-handed))
? ?(op ‘drop-ball
? ? ?:preconds ‘(has-ball)
? ? ?:add-list ‘(empty-handed)
? ? ?:del-list ‘(has-ball))
? ?(op ‘eat-banans
? ? ?:preconds ‘(has-bananas)
? ? ?:add-list ‘(empty-handed not-hungry)
? ? ?:del-list ‘(has-bananas hungry))))

使用這些運算符,可以展現的問題就是讓猴子不再饑餓,給定的初始狀態,在門口,站在地板上,拿著球,饑餓,在門口有把椅子。GPS可以找到一個這個問題的解決方案:

> (use *banana-ops*) => 6
?> (GPS '(at-door on-floor has-ball hungry chair-at-door)
'(not-hungry) )
((START)
(EXECUTING PUSH-CHAIR-FROM-DOOR-TO-MIDDLE-ROOM)
(EXECUTING CLIMB-ON-CHAIR)
(EXECUTING DROP-BALL)
(EXECUTING GRASP-BANANAS)
(EXECUTING EAT-BANANAS))

這里沒有對原來的GPS程序作出任何的改動,僅僅是使用了一個新的操作符集合。

4.13 迷宮搜索問題

現在我們來看看另一個經典問題,迷宮搜索。我們假定有一個迷宮,如下圖所示:


Maze.JPG

定義一些函數來幫助構建針對問題的操作符,比直接定義一大串操作符要容易得多。下面的代碼定義了一般的迷宮操作符集合,以及這個特定迷宮:

(defun make-maze-ops (pair)
? “Make maze ops in both directions”
? (list (make-maze-op (first pair) (second pair))
? ? (make-maze-op (second pair) (first pair))))

(defun make-maze-op (here there)
?“Make an operator to move between two places”
?(op ‘(move from ,here to ,there)
? ?:preconds ’((at ,here))
? ? ?:add-list ‘((at ,there))
? ?:del-list ’((at ,here))))

(defparameter *maze-ops*
?(mappend #’make-maze-ops
? ?‘((1 2) (2 3) (3 4) (4 9) (9 14) (9 8) (8 7) (7 12) (12 13)
? ?(12 11) (11 6) (11 16) (16 17) (17 22) (21 22) (22 23)
? ?(23 18) (23 24) (24 19) (19 20) (20 15) (15 10) (10 5) (20 25))))

現在我們可以使用操作符的列表來解決這個迷宮的一些問題。我們也可以通過給定的連接的列表來創建另一個迷宮。注意沒有證據表明迷宮的形式必須是55一層的,他僅僅是一種連接具象化的表示方式。
> (use *maze-ops*) => 48
> (gps '((at 1)) '((at 25)))
((START)
(EXECUTING (MOVE FROM 1 TO 2))
(EXECUTING (MOVE FROM 2 TO 3))
(EXECUTING (MOVE FROM 3 TO 4))
(EXECUTING (MOVE FROM 4 TO 9))
(EXECUTING (MOVE FROM 9 TO 8))
(EXECUTING (MOVE FROM 8 TO 7))
(EXECUTING (MOVE FROM 7 TO 12))
(EXECUTING (MOVE FROM 12 TO 11))
(EXECUTING (MOVE FROM 11 TO 16))
(EXECUTING (MOVE FROM 16 TO 17))
(EXECUTING (MOVE FROM 17 TO 22))
(EXECUTING (MOVE FROM 22 TO 23))
(EXECUTING (MOVE FROM 23 TO 24))
(EXECUTING (MOVE FROM 24 TO 19))
(EXECUTING (MOVE FROM 19 TO 20))
(EXECUTING (MOVE FROM 20 TO 25))
(AT 25))

迷宮問題指出了一個隱秘的小bug。我們要GPS返回的是一系列執行的操作的列表。然而,因為考慮到目標達成也可以沒有任何操作,所以,在GPS返回值中加上了(START)。這些例子包含了START和EXECUTING形式,但是也包含了一系列的(AT n)。這就是bug。如果我們回過頭看看函數GPS,就會發現他的結果是根據achieve-all返回的狀態刪除所有的原子得來的。這是一個雙關,我們所說的移除原子就是移除除了(start),(executing action)之外的形式。到現在為止,所有的這些條件都是原子,所以方法可用。迷宮問題是從形式(AT n)中引入條件,所以首先這就是個問題。基本的精神就是當一個程序員使用雙關的時候,也就是將真正發生的事情用比較通俗的話來說,就會出現一些麻煩。我們真正想要做的不是刪除原子,而是找到所有知識操作的元素。下面的代碼就是主要的意思:
(defun GPS (state goals &optional (*ops* *ops*))
?“General Problem Solver: from state, achieve goals using *ops*.”
?(find-all-if #’action-p
? ?(achieve-all (cons ‘(start) state) goals nil)))

(defun action-p (x)
?“Is x something that is (start) or (executing …)?”
?(or (equal x ‘(start)) (executing-p x)))

迷宮問題也顯示出了一個版本2的優點:就是他會返回所做的操作的表現,而不僅僅是打印他們。這樣子就可以利用結果來進行一些處理,而不是僅僅看看而已。假設我們想要一個函數,給我們一個穿越迷宮的路徑,用一系列的位置表示。我們可以將GPS作為一個子函數調用,之后再操作結果。
(defun find-path (start end)
?“Search a maze for a path from start to end.”
?(let ((results (GPS ‘((at ,start)) ’((at ,end)))))
? ?(unless (null results)
? ? ?(cons start (mapcar #’destination
? ? ? ?(remove ‘(start) results
? ? ? ? ?:test #’equal))))))

(defun destination (action)
?“Find the Y in (executing (move from X to Y))”
?(fifth (second action)))
函數find-path調用GPS來獲取results。如果是nil就沒有答案,如果不是nil就會提取results的rest部分(也就是移除start)。從每一個形式(executing (move from x to y))中挑選出目的地,y,并且記住起始點。
> (use *maze-ops*) => 48
?> (find-path 1 25) =>
(1 2 3 4 9 8 7 12 11 16 17 22 23 24 19 20 25)
> (find-path 1 1) => (1)
> (equal (find-path 1 25) (reverse (find-path 25 1))) => T

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內容