Prolog CLPFD

时间:2016-04-21 17:32:40

标签: prolog infinite-loop clpfd failure-slice

假设我想表示这样的整数:integer:Sign:[FirstDigit,SecondDigit,...]。例如,42将表示为integer:positive:[4,2]

我需要一个基于此表示生成整数值的谓词,反之亦然。

以下是我提出的建议:

integer_value_('integer':Sign:[H],E) :-
    H in 0..9,
    (
        Sign = 'positive',
        E #= H
        ;
        Sign = 'negative',
        E #= -H
    ).
integer_value_('integer':Sign:[H,I|T],E) :-
    H in 0..9,
    length([I|T],L),
    (
        Sign = 'positive',
        E #= F + H * 10^L
        ;
        Sign = 'negative',
        E #= F - H * 10^L
    ),
    integer_value_('integer':Sign:[I|T],F).

这可以按预期工作。然而,它具有接受诸如integer:positive:[0,1]之类的事情的不幸特性,即在列表的开头处引导零。当我使用integer_value_(I,J), label([J]).枚举所有可能的整数时,这尤其成问题:带有前导零的整数也出现。

然后,我尝试使用integer_value_仅针对除第一个数字之外的所有数字进行更正,并使用integer_value作为第一个数字(请记住,我们需要容纳0表示为列表只包含0):

integer_value('integer':Sign:[H],E) :-
    abs(E) #< 10,
    abs(E) #> -1,
    integer_value_('integer':Sign:[H],E).
integer_value('integer':Sign:[H,I|T],E) :-
    H in 1..9,
    length([I|T],L),
    (
        Sign = 'positive',
        E #= F + H * 10^L
        ;
        Sign = 'negative',
        E #= F - H * 10^L
    ),
    integer_value_('integer':Sign:[I|T],F).

但现在它表现不正常。例如,integer_value(I,-19).会返回I = integer:negative:[1, 9],但如果我们要求另一个答案Prolog会因为我不理解的原因而进入无限循环(它应该说是假的,或者已经知道没有其他的答案)。

&#34;对面&#34;不会发生此问题。查询integer_value(integer:negative:[1,9],Z).返回Z = 19然后返回false,当两个参数都是变量时(它正确枚举数字,没有前导零)也不会发生,这对我来说是令人惊讶的。

知道无限循环发生了什么,以及是否有一种简单的方法可以修复它?

2 个答案:

答案 0 :(得分:5)

要查看问题,只需查看程序的一小部分就足够了。实际上,以下就足够了:

integer_value('integer':Sign:[H],E) :- false,
    abs(E) #< 10,
    abs(E) #> -1,
    integer_value_('integer':Sign:[H],E).
integer_value('integer':Sign:[H,I|T],E) :-
    H in 1..9,
    length([I|T],L), false,
    (   Sign = 'positive',
        E #= F + H * 10^L
        ;
        Sign = 'negative',
        E #= F - H * 10^L
    ),
    integer_value_('integer':Sign:[I|T],F).

L这是第一次出现在这里,所以任何长度都是可能的。 你必须以某种方式修改长度目标。

答案 1 :(得分:3)

我设法使用@false

指出的this other answer解决了我的问题

其中一个问题是决定数字的符号作为最后一步,这样当迭代可能的整数时,我们得到正数和负数之间的交替答案:达到9(1位数)后,它将统一-9,然后-8等。在-1之后,它将与10,11等统一。在99之后,它将与-99,-98等统一。你明白了。

integer_value('integer':Sign:I,E) :-
    integer_value('integer':Sign:I,0,E,E).

integer_value('integer':Sign:[H],N0,N,M) :-
    H in 0..9,
    N1 #= H + N0 * 10,
    abs(M) #>= abs(N1),
    integer_value_('integer':Sign:[],N1,N,M).
integer_value('integer':Sign:[H,I|T],N0,N,M) :-
    H in 1..9,
    N1 #= H + N0 * 10,
    abs(M) #>= abs(N1),
    integer_value_('integer':Sign:[I|T],N1,N,M).

integer_value_('integer':Sign:[],N0,N,_) :-
    (
        Sign = 'positive',
        N #= N0
        ;
        Sign = 'negative',
        N #\= 0,
        N #= - N0
    ).
integer_value_('integer':Sign:[H],N0,N,M) :-
    H in 0..9,
    N1 #= H + N0 * 10,
    abs(M) #>= abs(N1),
    integer_value_('integer':Sign:[],N1,N,M).
integer_value_('integer':Sign:[H,I|T],N0,N,M) :-
    H in 0..9,
    N1 #= H + N0 * 10,
    abs(M) #>= abs(N1),
    integer_value_('integer':Sign:[I|T],N1,N,M).