2013-02-02 146 views
1

學習一些基本的序言,並且難以將我的頭圍繞邏輯​​。Prolog邏輯技巧

情景:個體感染病毒性腦膜炎並碰巧與其他人發生相互作用。這是我迄今爲止的序言邏輯。

%-- Set a sickness condition. 
%-- -------------------------------------------------------- --% 
setILL(X) :- write(X), write(' is ill'), nl. 

%-- Link some interactions between individuals. 
%-- -------------------------------------------------------- --% 
interact(ella, james). 
interact(ella, tyrone). 
interact(james, ben). 
interact(james, frank). 
interact(james, carl). 
interact(carl, james). 
interact(carl, evan). 
interact(evan, mike). 
interact(evan, kelly). 
interact(mike, frank). 
interact(kelly, carl). 
interact(kelly, frank). 
interact(kelly, ben). 
interact(sven, mike). 

%-- Create an interaction condition. 
%-- -------------------------------------------------------- --% 
came_in_contact(X, Y) :- setILL(X), write(X), write(' has had contact with '), write(Y), X\=Y, !, nl. 

%-- Create a rule for sickness 
%-- -------------------------------------------------------- --% 
sick(X) :- interact(X, Y), contact(X, Y), Y\=X. 
whosick(R) :- findall([X], sick(X), R). 

現在的相互作用是他們應該做的是和應該有兩條路徑每次啓動時間與Ella(誰是最初患病)與斯文(假想的最後一個個體要生病)結束。我只是希望打印出兩條可能的路徑,而不包含無用的交互。例如。 tyrone會和別人說話,也不會說話。我也想刪除重複(見下文)。

當我執行

whosick(X). 

我得到的所有的

ella is ill 
ella has had contact with james 
ella is ill 
ella has had contact with tyrone 
james is ill 
james has had contact with ben 
james is ill 
james has had contact with frank 
james is ill 
james has had contact with carl 
carl is ill 
carl has had contact with james 
carl is ill 
carl has had contact with evan 
evan is ill 
evan has had contact with mike 
evan is ill 
evan has had contact with kelly 
mike is ill 
mike has had contact with frank 
kelly is ill 
kelly has had contact with carl 
kelly is ill 
kelly has had contact with frank 
kelly is ill 
kelly has had contact with ben 
sven is ill 
sven has had contact with mike 
X = [[ella], [ella], [james], [james], [james], [carl], [carl], [evan], [...]|...]. 

回答

1

首先,有一個在你提供的代碼一個錯字:came_in_contact應該contact,否則將無法運行。小問題。

第二期:我不知道你這是什麼意思:findall([X], sick(X), R).有沒有特殊的理由在這裏使用[X],而不是僅僅X,結果看起來更好一點這種變化:

X = [ella, ella, james, james, james, carl, carl|...]. 

一個更重要的問題是,從風格上看,setill是100%的副作用,儘管名稱有聲有聲。 setill不會「設置」任何人「生病」,它只是打印到標準輸出中,表示某人生病。如果這是MVC,你可能會說,它是「視圖」的一部分。因此,您遇到的問題的一部分是您從sick/2的「模型」中深處調用此「查看」代碼。

你在括號中提到Ella是爆發的起源,但在Prolog數據庫中沒有事實,所以Prolog肯定不知道它。此外,您似乎對感染所採取的「路徑」感興趣,但您的Prolog不知道任何關於路徑的事實 - 實際上,它只是將您的事實數據庫拋出。爲了證明這一點,讓我們在頂部加入一個新的事實:

interact(gail, hank). 

果然,它現在是第一個「解決方案」,即使蓋爾和漢克從圖表的其餘部分隔離:

gail is ill 
gail has had contact with hank 
… (old output repeated) 

...

因此,,你在這裏的雜草。你有一個不完整的事實數據庫,你的規則並沒有真正捕捉到問題的邏輯,而是通過打印來散佈邏輯。當我們在這裏完成代碼會看起來很不一樣。我不確定這是否是家庭作業,這聽起來像你自學,但它有一種家庭氣氛的氛圍,所以我要試着勾畫出我將如何進行而不把它放在一起。


首先,你需要做的Prolog知道所有它需要計算解決方案的事實。換句話說,你必須添加關於創始人的事實:

infected(ella) :- !. 

這將成爲基本案例。現在,我們需要採用歸納推理,並說,如果這個人有過接觸受感染的人一個人被感染:

infected(X) :- interact(X, Y), X \= Y, infected(Y), !. 

注意:這些削減是非常重要的。沒有必要計算另一個解決方案,因爲一個人或者沒有被感染。如果我們在任何一個分支上都能成功證明他們受到感染,那麼就沒有別的可說的了。

現在我們可以對某些人得到合理的解決方案:

?- infected(ella). 
true. 

?- infected(gail). 
false. 

其他人似乎沒有得到解決:

?- infected(james). 
(I typed Ctrl+C) 
^CAction (h for help) ? abort 
% Execution Aborted 

之所以詹姆斯沒有達成解決辦法,是因爲Prolog是使用深度優先搜索。有意思的是,接下來你要做的是發現感染途徑,所以如果你能阻止Prolog嘗試已經在路上的人,你可以通過獲得你所需要的路徑來解決問題。你將不得不採用類似的基本病例/歸納病例結構,但是還要傳遞一條關於感染途徑的額外論點。你可以在這裏找到這種事情的例子,所以我不會在這裏提供你的細節。

請注意這一點:我們是而不是將混合問題的邏輯與結果的顯示。由於回溯,這只是Prolog的良好策略。如果因爲綁定在此處成功而打印出某些內容,並且在下一期失敗,則整個失敗可能會超過打印輸出,從而導致用戶感到困惑。我們可以很容易地欺騙Prolog從後來失敗的解決方案中打印出謊言。所以你總是想編寫你的Prolog,以便它找到解決方案,然後單獨顯示它們。認爲模型視圖控制器。

因此,讓我們假設您找到了一個謂詞path/3(推測爲path(Source, Last, Path))。當你運行它,你會得到的解決方案是這樣的:

?- path(ella, X, Path). 
X = sven 
Path = [ella, james, ...] ; 

X = sven 
Path = [ella, tyrone, ...] ; 
false. 

這是你要與你的findall/3包裹謂詞,然後你就會想通過結果來走,並打印出你需要的路徑的部分。

編輯:在回答您的意見,讓我們來看看你的新斷言:

path(_, X, P) :- findall(X, interact(_, X), P). 

這恐怕不會比以前更接近。讓我們來看看,當我問路徑從自己發生了什麼:

?- path('Daniel Lyons', X, Path). 
Path = [james, tyrone, ben, frank, carl, james, evan, mike|...]. 

其實你可以把絕對的東西在那裏,你會得到完全相同的結果:

?- path('Jack Donaghy', X, Path). 
Path = [james, tyrone, ben, frank, carl, james, evan, mike|...]. 
?- path(3.1415926, X, Path). 
Path = [james, tyrone, ben, frank, carl, james, evan, mike|...]. 
?- path([a,b,c,d,e], X, Path). 
Path = [james, tyrone, ben, frank, carl, james, evan, mike|...]. 

這是因爲你規則任何東西在第一個位置是正確的。如果你有更多的條款,這可能是有意義的,因爲其他條款之一可以說這個論點的一些東西,但缺乏它確實意味着什麼。所以你的謂詞可以寫成:

path(X, P) :- findall(X, interact(_, X), P). 

每個_是一個完全獨特的綁定;他們不互相影響可言,因此,如果你希望的效果有你想要的東西更是這樣的:

path(F, X, P) :- findall(X, interact(F, X), P). 

你馬上看到,這並不能幫助你多少:

?- path(ella, X, P). 
P = [james, tyrone]. 

所以我們已經解決了這個問題。

person(X) :- interact(X, _) ; interact(_, X). 

這只是一個幫助器,它返回每個人是否在交互的左側或右側。

path(Originator, Path) :- 
    setof(X, person(X), People), 
    path(Originator, Path, People). 

這個幫手讓你從一個特定的人的路徑。我們正在依靠我將在短短一秒內展示的幫手功能。我們從所有人的名單開始,通過合理的方式修剪可能性。這樣我們可以從我們還沒有檢查過的人員列表中選擇下一個人,我們不必擔心週期或遞歸太多。

path(Originator, [], _). 
path(Originator, [NextPerson|Rest], Considering) :- 
    select(NextPerson, Considering, RemainingToConsider), 
    interact(Originator, NextPerson), 
    path(NextPerson, Rest, RemainingToConsider). 

第一個條款說,我們總是可以做到。從發端到沒有人的路徑是空路。這是我們歸納的基本情況。

第二個條款說,從我們已經離開的人員列表中選擇一個人來考慮。有人與創作者互動。現在找到一個從那個人到剩下的人的路徑。 (select/3將第三個參數與沒有第一個參數的第二個參數統一)。

讓我們來看看在運行:現在

?- path(ella, X). 
X = [] ; 
X = [james] ; 
X = [james, ben] ; 
X = [james, carl] ; 
X = [james, carl, evan] ; 
X = [james, carl, evan, kelly] ; 
X = [james, carl, evan, kelly, ben] ; 
X = [james, carl, evan, kelly, frank] ; 
X = [james, carl, evan, mike] ; 
X = [james, carl, evan, mike, frank] ; 
X = [james, frank] ; 
X = [tyrone] ; 
false. 

,在你原來的問題,你說了一些關於本和弗蘭克和不感興趣的其他路徑。我還沒有看到一個合乎邏輯的閱讀,將這些案件進行區分,但你至少可以找到所有最長的路徑,像這樣:

longest_paths(Originator, Path) :- 
    path(Originator, Path), 
    \+ (path(Originator, Path2), 
     length(Path, MaxLen), 
     length(Path2, NextLen), 
     NextLen > MaxLen). 

這並不十分有效,但它說的是,找到我一個來自發起者的路徑,這樣就沒有其他長度更長的路徑。這發現我們三個解決方案:

?- longest_paths(ella, X). 
X = [james, carl, evan, kelly, ben] ; 
X = [james, carl, evan, kelly, frank] ; 
X = [james, carl, evan, mike, frank] ; 
false. 

而這是儘可能接近我想我可以讓你找到你想要的解決方案。我希望它有幫助!

+0

謝謝@丹尼爾里昂。實際上,我正在對不同的人工智能應用程序進行獨立研究,而序言碰巧是有人建議的。 – user2035757

+0

現在關於路徑,現在我有'路徑(_,X,P): - findall(X,interact(_,X),P).'這給了我一個接近我預期的路徑。這就是我現在得到的結果'[2] 23? - 路徑(ella,X,Path)。 Path = [james,tyrone,ben,frank,carl,james,evan,mike,kelly | ...]。 – user2035757

+0

我已經添加了一些評論到最後討論爲什麼這不是一個解決方案並告訴你什麼是實際的解決方案看起來像。 –