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

Prolog 序言:枚举可数无限结果的所有元素,prolog,logic-programming,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)这样的对 我建议使用具有可选上限值的生成器,如/3之间,而不是nat/1,以便能够饱和“内部电平”。比如说 ?- between(0,inf

是否有任何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)这样的对


我建议使用具有可选上限值的生成器,如/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不允许
介于(0,inf,A)
之间,因此可以添加
当前\u Prolog\u标志(max\u integer,Z)
并使用
Z
而不是
inf

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

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

pairs((A, B)) :-
    nat(X),
    A + B #= X,
    fd_labeling([A,B]).
这大致遵循经典中使用的有理数矩阵的遍历(在每个对角线上以相同的方向运行,而不是交替运行),导致:

| ?- 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) ? ;
...

使用您所拥有的
nat/1
的定义不容易实现的原因是,您想要的顺序要求搜索既不是深度优先,也不是广度优先的证明树。@capelical的答案是广度优先搜索。@潜伏者的答案会给你你想要的答案

如果出于某种原因您不想使用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)
    ).

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

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

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

注意:以下是在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) ;
...

谢谢是否有任何实现可以配置从深度优先搜索到广度优先搜索的搜索算法?我认为在某些情况下广度优先搜索是有用的,而重写深度优先搜索的程序会使程序变得混乱。有充分的理由可以解释为什么默认策略是深度优先。您所追求的解决方案并不是以任何琐碎的顺序排列的,因此,有理由期望您需要在程序中描述您所追求的是什么。目前提供的答案对于生成自然数对非常有用,但我认为更普遍的问题将被Prolog的搜索策略所抑制,正如@Boris所强调的那样。如果您有两个(或更多)任意谓词,
p1
p2
,它们各自生成某种类型的无穷系列解,我不确定Prolog中是否有方法结合广度优先来探索它们的解,除非它们与自然数有明确的关联(例如,
p1(N,…)
p2(N,…)
),在这种情况下,可以使用自然数方法来约束回溯的结果。这种方法的一个限制是,它永远不会生成
(A,B)
,其中
B>A
长度(\uu,A)
inf是SWI特有的您对
nat/1的定义非常低效:它有二次成本。即使
长度(u,X)
也要快得多。请尝试:
(nat(N),N=10000)
(长度(,N),N=10000)
至于
对/2
对((A,B)):-A#>=0,B#>=0,X#>=0,A+B#>=X,长度.
这不仅更快,终止效果更好,还可以在SICStus和SWI中运行。@false我只是重复OP对
nat/1
的定义以示说明。我不想提供一个更有效的版本,但答案的实质是定义后如何处理
nat/1
。感谢您提出的提高效率的建议但它会在GNU Prolog中生成,
未捕获的异常:error(输入_error(整数,35; 4195348(0..268435455)),(#=)/2)
。偶数和需要标记为“up”,奇数和需要标记为“down”,才能忠实地重建Cantor的参数。@false是的,你是对的。实际上,它是“某种程度上的”在康托穿越之后,但不是完全。好的捕获。:)
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) ;
...