我开始使用DLV(析取数据记录),并且在运行代码时我有一条报告“规则不安全”错误的规则。规则如下:
foo(R, 1) :- not foo(R, _)
我已阅读手册并看到“不允许循环依赖”。我想这就是为什么我被报告错误,但我不确定这个陈述对于DLV是如此有问题。最终目标是在尚未定义谓词的情况下进行某种初始化。
更准确地说,如果参数R(和其他任何东西)没有出现'foo',则用参数R和1定义它。一旦定义了规则,就不应该再次触发规则。所以,在我看来,这不是一个真正的递归。
欢迎任何有关如何解决此问题的评论!
我已经意识到我可能需要另一个谓词来匹配规则体中的参数R.像这样:
foo(R, 1) :- not foo(R, _), bar(R)
因为,否则无法知道是否没有出现foo(R,_)。我不知道自己是否明白了。
无论如何,这也不起作用:(
答案 0 :(得分:1)
对特定的"规则不安全"错误:首先,这与循环或非循环依赖无关。对于非循环程序显示相同的错误消息:
foo2(R, 1) :- not foo(R,_), bar(R).
问题是该程序实际上并不安全(http://www.dlvsystem.com/html/DLV_User_Manual.html#SAFETY)。如负面规则部分所述(锚#AEN375,我只允许在我的答案中使用2个链接):
变量,在否定的文字中出现,也必须出现在 体内积极的文字。
观察_是一个匿名变量。即,程序
foo(R,1) :- not foo(R,_), bar(R).
可以等效地写成(并且相当于)
foo(R,1) :- not foo(R,X), bar(R).
匿名变量(DLV手册,锚#AEN264 - 在本节末尾)只是允许我们避免为规则中只出现一次的变量创建名称(即对于仅表达&#34的变量;有一些价值,我绝对不关心它),但它们仍然是变量。因为否定的否定是"否定"而不是"真正的否定" (或"强烈的否定"因为它也经常被称为),规则不满足三个安全条件。
对安全性的一个非常粗略和高级的直觉是它保证程序中的每个变量都可以分配到某个有限域 - 因为现在通过添加bar(R)就是R的情况。但是,匿名变量_也必须如此。
定义默认值的实际问题: 正如lambda.xy.x所指出的,这里的问题是DLV的答案集(或稳定模型)语义:尝试在一个规则中执行它不会给出任何解决方案: 为了获得安全的程序,我们可以替换上述问题,例如由
foo(1,2). bar(1). bar(2).
tmp(R) :- foo(R,_).
foo(R,1) :- not tmp(R), bar(R).
这没有稳定的型号: 假设答案是按预期的, {foo(1,2),bar(1),bar(2),foo(2,1)} 但是,这不是一个有效的模型,因为tmp(R): - foo(R,_)将要求它包含tmp(2)。但是,"不是tmp(2)"不再是真的,因此在模型中使用foo(2,1)会违反模型所需的最小值。 (这不是正在发生的事情,更粗略的直觉。更多技术细节可以在任何关于答案集编程的文章中找到,快速Google搜索给了我这篇论文作为第一批结果之一:http://www.kr.tuwien.ac.at/staff/tkren/pub/2009/rw2009-asp.pdf)
为了解决这个问题,因此必须以某种方式打破周期"。一种可能性是:
foo(1,2). bar(1). bar(2). bar(3).
tmp(R) :- foo(R,X), X!=1.
foo(R,1) :- bar(R), not tmp(R).
即,通过明确声明我们只想在中间原子中添加R,如果值不同于1,模型中的foo(2,1)与tmp(2)不相矛盾也是模特的一部分。当然,这不再允许区分foo(R,1)是作为默认值还是通过输入,但如果不需要...
另一种可能性是不使用foo进行计算,而是使用foo1。即具有
foo1(R,X) :- foo(R,X).
tmp(R) :- foo(R,_).
foo1(R,1) :- bar(R), not tmp(R).
然后只使用foo1而不是foo。