4

Are there any prolog implementations that are able to enumerate all elements of countably infinite results?

Let's consider to enumerate all pairs of natural numbers. If we enumerate pairs in order {(0,0), (0,1), (1,0), (0,2), (1,1), (2,0), ...}, we can enumerate all pairs. However, if we enumerate pairs in order {(0,0), (0,1), (0,2), (0,3) ...} as the following GNU prolog program, we never reach pairs such as (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 ? 
egi
  • 41
  • 3
  • Thanks! Are there any implementation that we can configure search algorithm from depth-first search to breadth-first search? I think in some case breadth-first search is useful and rewriting program for depth-first search makes program messy. – egi Feb 10 '15 at 05:51
  • 1
    There are good reasons why the default strategy is depth first. The solutions you are after are not ordered in any trivial order, so it is reasonable to expect that you would need to describe, in your program, what it is exactly that you are after. –  Feb 10 '15 at 13:16
  • 1
    The answers offered so far are nice for generating pairs of natural numbers, but the more general problem I think will be inhibited by Prolog's search strategy as emphasized by @Boris. If you have two (or more) arbitrary predicates, `p1` and `p2`, that each generate a infinite series of solutions of some kind, I'm not sure there's a way in Prolog to explore their solutions in conjunction, breadth first, unless they have an explicit association with natural numbers (*e.g.*, `p1(N,...)`, `p2(N,...)`), in which case the natural number method may be used to constrain the results on backtracking. – lurker Feb 10 '15 at 13:52

4 Answers4

3

I first thought CappeliCs solution is fine. But then looking at lurkers
CLP(FD) solution, I think the following is a complete Prolog solution:

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

Bye

P.S.: Here is an example run in 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) ;
...
2

The reason why it is not easily doable with this definition of nat/1 that you have, is that the order you want requires a search of the proof tree that is neither depth first, nor breadth first. The answer by @CapelliC is a breadth first search. The answer by @lurker gives you the answers you are after.

If for one reason or another you don't want to use CLPFD, here is a solution in pure 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)
    ).

It simply describes how to "move" through the rational number matrix to enumerate all pairs of integers.

1

You can use CLPFD (constraint logic programming over finite domains) to generate all of the pairs:

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

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

This approximately follows the traversal of the rational number matrix used in the classic Cantor's proof that the rationals are countable (running the same direction on each diagonal instead of alternating), resulting in:

| ?- 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) ? ;
...
lurker
  • 56,987
  • 9
  • 69
  • 103
  • 1
    Your definition of `nat/1` is very inefficient: It has quadratic cost. Even `length(_,X)` is much faster. Try it with: `(nat(N),N = 10000)` and `(length(_,N),N = 10000)` – false Feb 10 '15 at 13:37
  • 2
    As for `pairs/2`: `pairs((A,B)) :- A#>=0, B #>=0, X #>= 0, A+B #= X, length(_,X).` this is not only faster, terminates better, but also runs in SICStus and SWI. – false Feb 10 '15 at 13:44
  • @false I was just echoing the OP's definition of `nat/1` for illustration. Not looking to offer a more efficient version, but the essence of the answer is what to do with `nat/1` once defined. And thanks for the suggested efficiency improvement on `pairs`. But it generates, `uncaught exception: error(type_error(integer,_#4195348(0..268435455)),(#=)/2)` in GNU Prolog. – lurker Feb 10 '15 at 13:56
  • 1
    You would need to label "up" for the even and "down" for the odd sums to faithfully reconstructs Cantor's argument. – false Feb 10 '15 at 14:00
  • @false yeah, you're right. As is, it's "sort of" following the Cantor traversal but not quite. Good catch. :) – lurker Feb 10 '15 at 14:04
  • `X #>= 0 length(_,X)` gives an error in GNU. That's a bug in GNU's length/2. Filed. – false Feb 10 '15 at 14:13
  • It is a common error for many to try to simulate Cantor too faithfully. – false Feb 10 '15 at 14:18
  • @false yeah, I actually didn't set out to do so faithfully, but I did have Cantor in mind when I was looking for a complete solution. On the other hand, Cantor's proof would have still worked if he traversed the matrix the same way I did. :) – lurker Feb 10 '15 at 14:18
0

I would suggest to use a generator with optional limited upper value, like between/3, instead of nat/1, to be able to saturate 'inner levels'. For instance

?- 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 doesn't allow between(0,inf,A), so maybe add current_prolog_flag(max_integer,Z) and use Z instead of inf.

CapelliC
  • 59,646
  • 5
  • 47
  • 90