Prolog:枚举可数无限结果的所有元素

时间:2015-02-10 05:26:20

标签: prolog logic-programming

是否有任何prolog实现能够枚举可数无限结果的所有元素?

让我们考虑列举所有自然数对。 如果我们按{(0,0),(0,1),(1,0),(0,2),(1,1),(2,0),...}的顺序枚举对,我们可以枚举所有对。 但是,如果我们按照{(0,0),(0,1),(0,2),(0,3)...}的顺序枚举对作为以下GNU prolog程序,我们永远不会达到诸如( 1,1)。

% cat nats.pl
nat(0).
nat(X1) :- nat(X), X1 is X + 1.

pair_of_nats(X, Y) :- nat(X), nat(Y).
% prolog
GNU Prolog 1.3.0
By Daniel Diaz
Copyright (C) 1999-2007 Daniel Diaz
| ?- ['nats.pl'].
compiling /home/egi/prolog/nats.pl for byte code...
/home/egi/prolog/nats.pl compiled, 4 lines read - 762 bytes written, 9 ms

yes
| ?- pair_of_nats(X,Y).

X = 0
Y = 0 ? ;

X = 0
Y = 1 ? ;

X = 0
Y = 2 ? ;

X = 0
Y = 3 ? 

4 个答案:

答案 0 :(得分:3)

您使用nat/1的这个定义不容易实现的原因是,您想要的顺序需要搜索既不是深度优先也不是广度优先的证明树。 @CapelliC的答案是广泛的第一次搜索。 @lurker的答案为您提供了您所追求的答案。

如果由于某种原因您不想使用CLPFD,这里是纯Prolog的解决方案:

pairs(A, B) :-
    pairs_1(0, 0, A, B).

pairs_1(A, B, A, B).
pairs_1(A, B, RA, RB) :-
    (   succ(B1, B)
    ->  succ(A, A1),
        pairs_1(A1, B1, RA, RB)
    ;   succ(A, B1),
        pairs_1(0, B1, RA, RB)
    ).

它简单地描述了如何移动"通过有理数矩阵来枚举所有整数对。

答案 1 :(得分:2)

您可以使用CLPFD(有限域上的约束逻辑编程)生成所有对:

nat(0).
nat(X1) :- nat(X), X1 is X + 1.

pairs((A, B)) :-
    nat(X),
    A + B #= X,
    fd_labeling([A,B]).

这大致遵循经典Cantor's proof that the rationals are countable中使用的有理数矩阵的遍历(在每个对角线上运行相同的方向而不是交替),导致:

| ?- pairs(P).

P = (0,0) ? ;

P = (0,1) ? ;

P = (1,0) ? ;

P = (0,2) ? ;

P = (1,1) ? ;

P = (2,0) ? ;

P = (0,3) ? ;

P = (1,2) ? ;

P = (2,1) ? ;

P = (3,0) ? ;

P = (0,4) ? ;
...

答案 2 :(得分:2)

我首先想到的是CappeliCs解决方案很好。但随后看着潜伏者 CLP(FD)解决方案,我认为以下是一个完整的Prolog解决方案:

?- between(0, inf, X), between(0, X, A), B is X-A.

再见

P.S。:这是在SWI-Prolog中运行的示例:

Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.1.33)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
?- [user].
pair((A, B)) :- 
   between(0, inf, X), 
   between(0, X, A), 
   B is X-A.

?- pair(P).
P = (0, 0) ;
P = (0, 1) ;
P = (1, 0) ;
P = (0, 2) ;
P = (1, 1) ;
P = (2, 0) ;
...

答案 3 :(得分:-1)

我建议使用具有可选有限上限值的生成器,例如在/ 3之间,而不是nat / 1,以便能够使“内部级别”饱和。例如

?- between(0,inf,A),between(0,A,B).
A = B, B = 0 ;
A = 1,
B = 0 ;
A = B, B = 1 ;
A = 2,
B = 0 ;
A = 2,
B = 1 ;
A = B, B = 2 ;
A = 3,
B = 0
....

GNU Prolog不允许between(0,inf,A),因此可以添加current_prolog_flag(max_integer,Z)并使用Z代替inf