Prolog结果不会倍增

时间:2017-11-03 03:22:36

标签: prolog

我有以下prolog程序:

 square([H|T], X) :-
    squareCompare(T, H, X).

 squareCompare([], X, X * X ).
 squareCompare([H|T], V, Result) :-
    (V * V) < (H * H),
    squareCompare(T, V, Result);
    (V * V) > (H * H),
    squareCompare(T, H, Result).

当我进入时:

square([7, 5, 2], Result).

我得到Result = 2 * 2,我想要的是Result = 4

该程序搜索列表中元素的最小平方。

1 个答案:

答案 0 :(得分:3)

除了评论中指出的缺少算术评估(是/ 2)之外,还有使用< / 2和> / 2的问题:您的谓词不适用于列表连续重复,例如:

?- square([7,7],X).
false.

预期结果为49.您可以通过< / 2替换=< / 2或> / 2替换>= / 2来解决这个问题。 squareCompare / 3的递归规则:

squareCompare([], X, Y) :-
   Y is X*X.
squareCompare([H|T], V, Result) :-
  (V * V) < (H * H),
  squareCompare(T, V, Result);
  (V * V) >= (H * H),
  squareCompare(T, H, Result).

现在谓词产生了所需的结果:

?- square([7,7],X).
X = 49.

根据评论中的另一个建议,您可以选择使用CLP(FD)使谓词双向工作。在这种情况下,谓词类似于真实的关系,所以给它一个反映这个事实的更具描述性的名称是合适的,比如list_minsquare / 2。既然你对最小的方块感兴趣,为什么不绕着正方形作为参数而不是数字呢?最坏的情况:最小正方形的根是最后一个列表元素,然后没有区别。最佳情况:最小正方形的根是第一个列表元素,然后您只计算一次而不是列表长度时间。把所有这些放在一起:

:- use_module(library(clpfd)).

list_minsquare([H|T],X) :-
   S #= H*H, 
   list_square_minsquare(T,S,X).

list_square_minsquare([],S,S).
list_square_minsquare([H|T],S,Result) :-
   S #< (H*H),
   list_square_minsquare(T,S,Result).
list_square_minsquare([H|T],S,Result) :-
   H2 #= (H*H),
   S #>= H2,
   list_square_minsquare(T,H2,Result).

现在让我们看一些动作。您的示例查询会产生所需的结果:

?- list_minsquare([7,4,2],X).
X = 4.

连续重复也不会造成麻烦:

?- list_minsquare([7,7],X).
X = 49.

部分实例化列表导致生成所有可能的解决方案:

?- list_minsquare([7,Y,2],X).
X = 4,                        % <- 1st answer: X=4 if
Y^2#=_G670,
_G670 in 50..sup ;            % Y^2 is between 50 and sup
Y in -1..1,                   % <- 2nd answer: if Y in -1..1
Y^2#=X,                       % then X=Y^2
X in 0..1 ;
X = 4,                        % <- 3rd answer: X=4
Y in -7.. -1\/1..7,           % if Y in -7..-1 or 1..7 
Y^2#=_G1754,
_G1754 in 4..49.              % and Y^2 in 4..49

在上面的示例中,Y有三种可能性,其中没有一种具有唯一的解决方案,因此您可以在答案中获得剩余目标。如果您希望得到具体的解决方案,您可以约束Y的范围,并询问带有标签/ 1的具体数字:

?- Y in 0..3, list_minsquare([7,Y,2],X), label([Y]).
Y = X, X = 0 ;
Y = X, X = 1 ;
Y = 2,
X = 4 ;
Y = 3,
X = 4.

最常见的查询也有效。但是,它以不公平的方式列出了解决方案:

?- list_minsquare(L,X).
L = [_G97],                      % <- 1st solution
_G97^2#=X,
X in 0..sup ;
L = [_G266, _G269],              % <- 2nd solution
_G266^2#=X,
X in 0..sup,
X+1#=_G309,
_G309 in 1..sup,
_G332#>=_G309,
_G332 in 1..sup,
_G269^2#=_G332 ;
L = [_G494, _G497, _G500],       % <- 3rd solution
_G494^2#=X,
X in 0..sup,
X+1#=_G540,
X+1#=_G552,
_G540 in 1..sup, 
_G575#>=_G540,
_G575 in 1..sup,
_G500^2#=_G575,
_G552 in 1..sup,
_G620#>=_G552,
_G620 in 1..sup,
_G497^2#=_G620 ;
.
.
.

在进入下一个长度之前,您只能获得每个列表长度的一个解决方案。您可以通过在查询中添加目标长度/ 2来获得公平的排序。然后,您将获得每个列表长度的所有可能性,然后继续:

?- length(L,_), list_minsquare(L,X).
L = [_G339],                    % <- 1st solution: list with one element
_G339^2#=X,
X in 0..sup ;
L = [_G1036, _G1039],           % <- 2nd solution: list with two elements
_G1036^2#=X,                    % X is square of 1st element
X in 0..sup,
X+1#=_G1079,
_G1079 in 1..sup,
_G1102#>=_G1079,
_G1102 in 1..sup,
_G1039^2#=_G1102 ;
L = [_G935, _G938],             % <- 3rd solution: list with two elements
_G935^2#=_G954,
_G954 in 0..sup,
_G954#>=X,
X in 0..sup,
_G938^2#=X ;                    % X is square of 2nd element
.
.
.

当然,你也可以在上面的查询列表中约束和标记数字,你仍然可以在无限多的解决方案中得到具体数字(因为列表长度无限多)。

?- length(L,_), L ins 1..2, list_minsquare(L,X), label(L).
L = [1],
X = 1 ;
L = [2],
X = 4 ;
L = [1, 2],
X = 1 ;
L = [1, 1],
X = 1 ;
L = [2, 1],
X = 1 ;
L = [2, 2],
X = 4 ;
L = [1, 2, 2],
X = 1 ;
L = [1, 2, 1],
X = 1 ;
L = [1, 1, 2],
X = 1 ;
L = [2, 1, 2],
X = 1 ;
.
.
.