2012-12-29 210 views
0

我在知識庫中的以下事實:避免無限循環中的Prolog

line(a,b). -- denotes the line determined by point a and b 
line(c,d). -- denotes the line determined by point c and d 
lineEqual(line(a,b),line(c,d)) -- denotes the length of two lines are equal 

我希望有另一個規則,可以lineEqual的兩個參數左右交換/ 2:

lineEqual(line(C, D), line(A, B)):- 
    lineEqual(line(A,B),line(C,D)). 

不幸的是,這個規則會在Prolog中創建一個無限循環。任何其他想法?

感謝您的更新。不知道是否我明白你的最後一條規則:

transitiveSymmetricRelPath(L1, L2, IntermediateNodes) :- symmetricRel(L1, L3), 
       \+member(L3, IntermediateNodes), 
       transitiveSymmetricRelPath(L1, L2, [L3 | IntermediateNodes]). 

我能想象在每次嘗試,如果它正好與L1和L3被鏈接到剝去頭節點的時間,對不對?因此,如果我們結束了一個空表,然後我們就可以使用這樣的規則:

transitiveSymmetricRel(L1, L2) :- transitiveSymmetricRelPath(L1, L2, []). 

但位,我沒有真正得到的是你在哪裏得到transitiveSymmetricRelPath/3的中間節點開始的非空列表。我已經用給定的事實rel(a,b)嘗試了你的代碼。相對(A,C)。並且它不返回transitiveSymmetricRel(b,c),也不返回transitiveSymmetricRel(c,b)。你可以看看它嗎?

非常感謝!

編輯: 我知道了通過修改規則一樣工作:

transitiveSymmetricRelPath(L2, L3, IntermediateNodes) :- symmetricRel(L1, L3), 
    \+member(L3, IntermediateNodes), 
    transitiveSymmetricRelPath(L1, L2, [L3 | IntermediateNodes]). 

感謝您的建議,反正。

回答

1

您應該避免在單個名稱下引入類似數據的語句(如第一個示例中的linelineEqual)和代碼(如第二個示例中的lineEqual)。相反,保持您的數據庫事實在不同的名稱。然後,你可以定義:

areLinesEqual(L1, L2) :- linesEqual(L1, L2). 
areLinesEqual(L1, L2) :- linesEqual(L2, L1). 

一般情況下,如果你有一個關係rel,你想建立一個對稱傳遞閉包,你應該同時引入一個概念。例如:

symmetricRel(L1, L2) :- rel(L1, L2). 
symmetricRel(L1, L2) :- rel(L2, L1). 

transitiveSymmetricRel(L1, L2) :- 
    transitiveSymmetricRelPath(L1, L2, []). 

transitiveSymmetricRelPath(L1, L2, _) :- 
    symmetricRel(L1, L2). 

transitiveSymmetricRelPath(L1, L2, IntermediateNodes) :- 
    symmetricRel(L1, L3), 
    \+ member(L3, IntermediateNodes), 
    transitiveSymmetricRelPath(L1, L2, [L3 | IntermediateNodes]). 

(注意,這裏我們必須找到基本上在無向圖的路徑,必須小心爲了要注意避免循環)。在你的情況下,也可能希望將line(A, B)line(B, A)視爲相同。對於這一點,同樣,你應該出臺間接的另一個層面:

% to check two lines for identity 
same(line(A, B), line(A, B)). 
same(line(A, B), line(B, A)). 

linesEqual2(L1, L2) :- 
    same(L1, LI1), 
    same(L2, LI2), 
    (linesEqual(LI1, LI2); linesEqual(LI2, LI1)). 

...在對稱關係的定義中使用linesEqual2代替linesEqual

難的現在與命名方案來,這樣你就不會混淆所有這些謂詞...

你也可以做到這一點的另一種方式。考慮到你尋求一個對稱關係的傳遞閉包,它基本上是所有節點集合(這裏:行)的一個分區,成爲可分的子集。這種見解將幫助您編寫更高效的代碼,但上述內容已經超出了這個問題的範圍。

+0

感謝您的回覆。傳遞關係呢?我可能需要根據您的建議編寫8條規則:areLinesEqual(L1,L3): - linesEqual(L2,L1),linesEqual(L2,L3)。 areLinesEqual(L1,L3): - 線等於(L1,L2),線等於(L2,L3)。 areLinesEqual(L1,L3): - 線等於(L2,L1),線等於(L3,L2)。 areLinesEqual(L1,L3): - 線等於(L1,L2),線等於(L3,L2)。另外4條規則可以交換L1和L3嗎?可能不是一個好方法。 – user1935724

+0

@ user1935724:我更新了答案。 – liori

+0

感謝您的更新,我根據您的回覆編輯了問題。 – user1935724