【问题标题】:Getting an order into predicate resolution让订单进入谓词解析
【发布时间】:2012-11-22 14:48:20
【问题描述】:

查看以下目标(我正在使用 swi-prolog 和 Markus Triska 的 clpfd):

result(Input,Result) :-
    Input #> 10,
    Result=decline.
result(Input,Result) :-
    Input in 0..20,
    Result=offer.

可能的查询如下所示:

?- result(15,B).
B = decline ;
B = offer.

我想添加一个订单或某种解决方案优先级。 如果“拒绝”是对Input=15 的有效响应,则不应再考虑第二个目标,因此只有B=decline 是解决方案,而不是B=offer

我知道我可以添加!/0,但反过来就不行了。给我这个谓词的所有可能答案。

考虑到这个例子,Result=offer 应该只对 Input 0..10 成立,否则应该触发更高的先前下降目标。

当我尝试考虑谓词中的顺序时,我是否认为过于迫切?

【问题讨论】:

  • 我也知道我当然可以更改 Input 变量的约束,但这不应该是解决方案。
  • 谓词的子句中有 顺序。我认为改变 Input 变量的约束是这里的解决方案。
  • 是的,你的想法很程序化,但这本身就是一个问题。为什么要使用 CLP/FD?按照您的设置方式,它看起来不像是一个约束和生成程序,只是一个普通的生成和测试程序。
  • 此外,您的要求似乎是矛盾的:“如果“拒绝”是对Input=15 的有效响应,则不应再考虑第二个目标”意味着“所有可能的答案”应该只是 @ 987654330@,对吧?
  • 嗯,不完全是,应该如下:Result=decline if Input in 11..sup and Result=offer if Input in 0..10

标签: prolog clpfd


【解决方案1】:

这里有几个问题,我们先从最明显的开始:

建模问题

你有一个关系(result/2 可能不是最好的名字),并且这个关系应该在declineoffer 应该为真时建模。在阅读你的程序之前,我更喜欢问 Prolog:

?- 结果(X,拒绝),结果(X,报价)。 X 在 11..20 ; 错误的。

因此,对于从 11 到 20 的值,您的关系是不明确的。如果您要做出决定,请先修复此关系。其实,我会从

  • 一个更好的关系名称,表明它是一个关系
  • 没有命令式措辞(如Input 或命令式)
  • 更紧凑的公式,您的程序中不需要那么多(=)/2 目标。相反,你可以这样写:
heigth_decision(我,拒绝):- 我#

CLP 中的答案和成功与解决方案

还有一个更根本的问题。这实际上要严重得多,因为到目前为止给出的所有 SO 答案都完全忽略了这一方面。这是关于答案和成功的概念,另一方面是解决方案的概念。

当您在 Prolog 中提出查询时 - 您得到的是一个答案。这样的答案可能包含解决方案,例如答案 L = [_,_] 包含无限多的解决方案。或者一个答案可能只包含一个解决方案,例如Decision = decline。但是,如果您使用像 library(clpfd) 这样的约束,那么在两者之间还有更多。

您现在可以获得有限多个解决方案:

?- abs(X) #

或无限多:

?- X #> Y。
Y#=

但你也可以得到一个完全不同的解决方案:

?- 2^X #= 1。 2^X#=1。

所以,重申一下:我们这里只有一个整数解,但对于 Prolog,这太复杂了。我们得到的答案是:是的,这都是真的,前提是所有这些细则都是真的

更糟糕的是,有时我们得到的答案不包含任何解决方案。

?- X^X#=0。 X^X#=0。

如果 Prolog 足够聪明,它会回答 false。但它不可能总是那么聪明,仅仅因为你可以很容易地提出无法确定的问题。这样的答案有时被称为不一致。德国的概念 Scheinlösung(~假解决方案,但负面含义较少)更好地传达了这个想法。

所以答案可能包含解决方案,但有些答案根本不包含解决方案。因此,一个目标的成功不能被认为是一个解决方案的存在!也就是说,所有建议某种提交为 (;)/2 – if-then-else、once/1 或 !/0 的 SO 答案都是不正确的,如果他们将成功作为解决方案。要看到这一点,请尝试:

?- X^X#=0,结果(X,下降)。 X 在 11..sup, X^X#=0 ; 错误的。 ?- X^X#=0,结果(X,报价)。 X 在 0..20, X^X#=0。

那么你现在怎么能确定任何事情呢?

  • 你可以依靠目标的失败。

  • 您可以尝试labeling/2,但这仅适用于有限域。

  • 您可以使用call_residue_vars/2copy_term/3 来确定是否存在“徘徊”的约束

  • 不幸的是,您不能完全依赖 SWI 的顶层,它隐藏了与答案中的变量无关的约束。只有 SICStus 能正确显示它们。

【讨论】:

  • 哇,再次感谢您为我提供了如此多的背景信息。我真的很感激,你已经完全理解了我的问题。在这里,成功并不总是一个解决方案。
【解决方案2】:

让我困惑的部分是当你说“反过来行不通”时。为什么要反其道而行之?

这是确定性搜索的一个明显案例,在 Prolog 中执行此操作的方法是剪切。 如果满足第一条规则,则不要保持其他分支打开。 或者,您可以使您检查的范围互斥。

如果您不只是在胡闹,而且您正在尝试实施一些严肃的事情,我建议您阅读具有 priorityteleo-reactive 规则的规则。您应该能够找到构建在 Prolog 之上的框架,这些框架可以用来解决您的问题,而无需重新发明轮子。

【讨论】:

  • 好吧,我认为我需要一个谓词来接受输入并给出正确的答案。这就是削减的地方,它适用于这种方式。但我想要的是能够查询:?-result(Input,Ouput) 它应该返回给我以下内容:Result=decline, Input in 11..supResult=offer,Input in 0..10
  • 好的,我就是这样做的。我会重新定义你的问题。您想根据最严格的条件分配结果。所以首先定义一个订单,例如拒绝>>报价。然后对结果也使用有限约束,假设 Result 是一个具有域 {decline,offer} 的变量。通过约束处理结果,最终得到最严格的。
  • 我现在要做的是:Input #> 10, decline; #\ Input #>10, Input in 0..20, Result=offer. 然后它给了我预期的结果:11..sup 下降,0..10 报价。我希望有一种更优雅的方式来做到这一点,而不是否定每个目标中的每个条件。
  • 您对使用剪切的建议不正确。第一条规则是否成功(您如何确保它“满足”?)与所描述的内容没有任何关系。
  • @false 你是对的。我的即时响应是基于提供的示例查询结果(15,B)。在这种情况下,约束变得无用。在更一般的情况下,切割是坏的。
【解决方案3】:

谓词顺序是 Prolog 程序的重要组成部分。这是因为证明搜索按照严格定义的顺序进行,应用SLD resolution

你的谓词给出了合理的结果:

?- result(X,Y).
Y = decline,
X in 11..sup ;
Y = offer,
X in 0..20.

您可以在调用它时使用一次/1,而不是对结果/2 进行删减,同时保留适当的定义以供一般使用。

?- once(result(X,Y)).
Y = decline,
X in 11..sup.

【讨论】:

  • 但是?- once(result(X, offer)) 给了你不同的答案。您的代码只能从程序上理解。
【解决方案4】:

来自建设性否定的一些想法可能会有所帮助。

理论

有一个简单的方法来进行逻辑切割。特别是对于约束,因为约束通常是否定完成的。因此,如果您有一个约束 C,您通常可以找到具有以下属性的约束 C':

C' <=> ~C

在如下两个子句中强加一个偏好:

p :- C, q.
p :- r

只需执行以下操作:

p :- C, q.
p :- C', r.

如果您的约束求解器提供了一个具体化的否定,例如(#\)/1 你甚至可以为此定义一个运算符:

:- op(1050,xfy,#?).
:- op(1100,xfy,#:).
(A #? B #: C) :- (A, B); (#\ A, C).

然后写下:

p :- C #? q #: r.

让我们将此策略应用于您的示例:

示例

您的代码目前如下:

result(Input, Result) :-
    Input #> 10,
    Result = decline.
result(Input, Result) :-
    Input in 0..20,
    Result = offer.

然后执行以下操作:

result(Input, Result) :-
    Input #> 10,
    Result = decline.
result(Input, Result) :-
    Input #=< 10, Input in 0..20,
    Result = offer.

这是一个运行示例:

?- result(15, X).
X = decline ;
false.

?- result(8, X).
X = offer.

现在使用(#?)/2,例如可以在 SWI-Prolog 中使用,因为那里的 CLP(FD) 库支持具体化。假设我们已经查阅了 CLP(FD) 库,然后如上定义了(#:)/2

 result(Input, Result) :-
    Input #> 10 
    #? 
       Result = decline 
    #: 
       Input in 0..20,
       Result = offer.

这是一个运行示例:

?- result(15, X).
X = decline ;
false.

?- result(8, X).
X = offer.

免责声明

(#?)/2(#:)/2 的后期语法受到 Java if-then-else 运算符 (?)/2(:)/2 的启发。由于我们无法覆盖或扩展定义 (;)/2,因此不可能有更多受 Prolog 启发的语法。

有关具体化的更多信息,请参见例如here 第 A.8.4 节具体化。我们没有做的是具体化 CLP(FD) if-then-else 定义中的合取和析取,因为 then 和 else 部分可能包含其他目标,然后是 CLP(FD) 约束。

再见

【讨论】:

    猜你喜欢
    • 2022-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多