如何防止Datalog规则修剪空值?

时间:2012-06-04 22:25:14

标签: database prolog logic datalog

我有以下事实和规则:

% frequents(D,P) % D=drinker, P=pub
% serves(P,B) % B=beer
% likes(D,B)

frequents(janus, godthaab).
frequents(janus, goldenekrone).
frequents(yanai, goldenekrone).
frequents(dimi,  schlosskeller).

serves(godthaab, tuborg).
serves(godthaab, carlsberg).
serves(goldenekrone, pfungstaedter).
serves(schlosskeller, fix).

likes(janus, tuborg).
likes(janus, carlsberg).

count_good_beers_for_at(D,P,F) :- group_by((frequents(D,P), serves(P,B), likes(D,B)),[D,P],(F = count)).
possible_beers_served_for_at(D,P,B) :- lj(serves(P,B), frequents(D,R), P=R).

现在我想构建一个规则,当一个“饮酒者”“频繁”的每个酒吧的可用“喜欢”啤酒的数量大于0时,它应该像谓词返回“true”一样工作。

当规则没有返回元组时,我会认为谓词是真的。如果谓词是假的,我打算让它返回没有单一“喜欢”啤酒的酒吧。

正如你所看到的,我已经有一条规则可以在给定的酒吧里为特定饮酒者计算好啤酒。我也有一条规则给我可用的啤酒数量。

DES> count_good_beers_for_at(A,B,C)

{                                           
  count_good_beers_for_at(janus,godthaab,2)
}
Info: 1 tuple computed.          

正如您所看到的,柜台不会返回经常光顾的酒吧,但却有0个喜欢的啤酒。我打算通过使用左外连接来解决这个问题。

DES> is_happy_at(D,P,Z) :- lj(serves(P,B), count_good_beers_for_at(D,Y,Z), (Y=P))

Info: Processing:
  is_happy_at(D,P,Z) :-
    lj(serves(P,B),count_good_beers_for_at(D,Y,Z),Y = P).
{                                           
  is_happy_at(janus,godthaab,2),
  is_happy_at(null,goldenekrone,null),
  is_happy_at(null,schlosskeller,null)
}
Info: 3 tuples computed.

这几乎是正确的,除了它还给了我没有经常光顾的酒吧。我尝试添加一个额外的条件:

DES> is_happy_at(D,P,Z) :- lj(serves(P,B), count_good_beers_for_at(D,Y,Z), (Y=P)), frequents(D,P)

Info: Processing:
  is_happy_at(D,P,Z) :-
    lj(serves(P,B),count_good_beers_for_at(D,Y,Z),Y = P),
    frequents(D,P).
{                                           
  is_happy_at(janus,godthaab,2)
}
Info: 1 tuple computed.

现在我以某种方式过滤了包含空值的所有内容!我怀疑这是由于DES中的空值逻辑。

我认识到我可能会以错误的方式接近整个问题。任何帮助表示赞赏。

编辑:作业是“非常快乐(D)ist wahr,genau dann wenn jede Bar,die Trinker D besucht,wenigstens ein Bier ausschenkt,das er mag。”这意味着“ very_happy(D)是真的,如果每个酒吧饮酒者D访问,至少服用1啤酒,他喜欢”。由于这个任务是关于Datalog的,我认为绝对可以在不使用Prolog的情况下解决。

2 个答案:

答案 0 :(得分:4)

我认为,对于您的分配,您应该使用基本的Datalog,而不会滥用聚合。问题的关键是如何表达普遍量化的条件。我搜索了“通用量化数据记录”,并在第一个位置找到了deductnotes.pdf断言:

  

普遍量化的条件只能用存在量化和否定的等价条件来表达。

在该PDF中,你会发现一个有用的例子(pagg 9& 10)。

因此,我们必须重新提出我们的问题。我最终得到了这段代码:

not_happy(D) :-
  frequents(D, P),
  likes(D, B),
  not(serves(P, B)).

very_happy(D) :-
  likes(D, _),
  not(not_happy(D)).

这似乎是必要的:

DES> very_happy(D)

{                                           
}
Info: 0 tuple computed.          

注意likes(D, _),这是避免将yanai和dimi列为very_happy所必需的,没有明确断言他们喜欢什么(对不起我的英语真的很糟糕......)

编辑:对不起,但上述解决方案无效。我用这种方式重写了它:

likes_pub(D, P) :-
  likes(D, B),
  serves(P, B).

unhappy(D) :-
  frequents(D, P),
  not(likes_pub(D, P)).

very_happy(D) :-
  likes(D, _),
  not(unhappy(D)).

试验:

DES> unhappy(D)

{                                           
  unhappy(dimi),
  unhappy(janus),
  unhappy(yanai)
}
Info: 3 tuples computed.          

DES> very_happy(D)

{                                           
}
Info: 0 tuples computed.          

现在我们添加一个事实:

serves(goldenekrone, tuborg).

我们可以看到更正的代码结果:

DES> unhappy(D)

{                                           
  unhappy(dimi),
  unhappy(yanai)
}
Info: 2 tuples computed.          

DES> very_happy(D)

{                                           
  very_happy(janus)
}
Info: 1 tuple computed.          

答案 1 :(得分:2)

也许不是你期待的答案。但你可以使用普通的Prolog,并通过bagof / 3或setof / 3内置谓词轻松地进行分组。

?- bagof(B,(frequents(D,P), serves(P,B), likes(D,B)),L), length(L,N).
D = janus,
P = godthaab,
L = [tuborg,carlsberg],
N = 2

bagof / 3的语义是这样的,它不计算给定查询的外连接。查询通常由Prolog执行。结果首先累积并按键排序。最后,通过回溯返回结果。如果你的数据记录不能没有空值,那么你必须过滤。

但是当你只想知道喜欢啤酒的存在时,你不需要进入聚合。您可以通过查询直接执行此操作而无需任何聚合:

is_happy_at(D,P) :- frequents(D,P), once((serves(P,B), likes(D,B))).
?- is_happy_at(D,P).
D = janus,
P = godthaab ;
Nein

一次/ 1可防止不必要的回溯。当数据记录在is_happy_at / 2中看到投影时,它可能会自动不进行不必要的回溯,即B被投射掉。或者您可能需要显式使用与SQL DISTINCT对应的内容。或者最终你的数据记录为你提供了与SQL EXISTS相对应的东西,它最接近于一次/ 1。

再见