3

如果我有以下知识库,如何在 parent_of 术语中添加一个剪辑,以便如果 X 已经确定为父亲,prolog 不会尝试“检查”X 是否也是母亲?

father_of(max,john).
father_of(max,james).
father_of(max,gabe).
mother_of(june,john).
mother_of(june,james).

parent_of(X,Y) :- father_of(X,Y).
parent_of(X,Y) :- mother_of(X,Y).

例如,我想要:

parent_of(max,Y) 为:Y=john, Y=james, Y=gabe

parent_of(june,Y) 为:Y=john, Y=james

对于第一个,我什至不希望 prolog 尝试检查 max 是否是母亲,因为已经确定他是父亲。

我已经尝试了很多组合,包括:

parent_of(X,Y) :- father_of(X,Y),!.  <-- fixes an X and Y and thus will list only Y=john
parent_of(X,Y) :- !,father_of(X,Y). <-- works for parent_of(max,Y) but not parent_of(jane)

这甚至可能吗?

4

2 回答 2

1

做这样的优化是非常棘手的。Prolog 在没有任何优化的情况下在此类问题上表现出色。

但作为一般规则:你不能简单地在程序中设置cut,你需要提前进行各种测试。我怀疑这些测试很容易比您打算删除的开销更昂贵。这是一个尝试。老实说,我感觉不是很好,因为你宁愿先学习纯Prolog。

所以我们假设没有解决方案:?- father_of(P,_), mother_of(P,_).

parent_of(F, C) :-
   ( atom(F), \+ \+ 父亲_of(F, _) -> !
   ; 真的
   ),
   父亲(F,C)。
parent_of(M, C) :-
   母亲(M,C)。

这真的更好吗?也许,也许不是。

但无论如何,你已经明白了一个重要的点:巧妙的优化需要大量的测试。我相信上面是正确的,但我什至不确定这会更快。毕竟,现在有两个查找father_of/2代替一个 forfather_of/2和一个 for mother_of/2。天真的版本可能会更快......

于 2012-11-16T00:08:18.273 回答
0

为此,一些 Prolog 系统提供了“软剪辑” *->/2

parent_of(X,Y) :- father_of(X,Y) *-> true ; mother_of(X,Y).

通常 for If *-> Then ; Else,如果条件If成功,Then则执行,回溯时只返回If和的替代解决方案Then。只有在If根本没有解决方案的情况下,Else才会执行。

这需要您知道谓词的模式,即调用模式。在您的情况下,如果您的谓词模式parent_ofparent_of(++,?),那么添加软切就可以了(假设名称是唯一的或仅针对一种性别出现)。在 的情况下parent_of(++,++),即使是常规切割也可以,尽管没有必要,除非您的数据库中有重复的事实(对称性破坏是切割的一个用例)。但是,如果您还必须满足parent_of(-,?),那么削减确实会削减解决方案。

通常:仅当您确定您切掉的搜索树的分支不包含任何解决方案或仅包含您不感兴趣的对称解决方案时才使用剪切。

于 2012-11-16T07:16:02.480 回答