Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to generate integer numbers in Prolog

Tags:

prolog

I want to generate integer numbers and I'm looking for the best way to do this. Example:

?- number2(N).
N = 0;
N = 1;
N = 2;
...
(and so on)

Now I'm simply using length/2:

number2(N) :- length(_, N).

But I think that there should be some better way (without creating temporary list). I could probably write some code myself basing on code of length/2 but I'm looking for solution that employs already existing, built-in predicates. Is there any built-in predicate that would work better than length/2? I couldn't find anything like that.

like image 730
Grzegorz Adam Kowalski Avatar asked Feb 09 '23 20:02

Grzegorz Adam Kowalski


1 Answers

It is hard to top your solution ; and probably it is not worth the effort. After all, there are now three suggestions that all are incorrect for one case or another:

?- time( (number2_gk(N), N == 10000) ). % your original
% 20,002 inferences, 0.007 CPU in 0.007 seconds (99% CPU, 3006132 Lips)
N = 10000 

?- time( (number2_cc(N), N == 10000) ). % quadratic overhead
% 50,025,001 inferences, 28.073 CPU in 28.196 seconds (100% CPU, 1781945 Lips)
N = 10000 

?- time( (next_integer(N), N == 10000) ).
% 20,002 inferences, 0.011 CPU in 0.011 seconds (100% CPU, 1822247 Lips)
N = 10000 

However, number2_cc(-1) and next_integer(-1) simply loop, length/2 actually should produce a domain error, like SICStus and many other systems do.

As you can see, CC's solution is worse than your original one.

Also the suggestion by mat produces different behavior in the following situation:

goal_expansion(length(Ls,L), between(0,infinite,L)) :-
   var_property(Ls, fresh(true)).

as(N) :-
   length(L,N),
   phrase(a, L).

a --> [a], a.
a --> [].

The goal as(N) now loops instead of enumerating all N.

If you really insist on an improvement, consider the following tail-recursive solution using library(clpfd):

nat(N) :-
   nat(N, 0).

nat(N, N0) :-
  N #>= N0,
  (  N = N0
  ;  N1 is N0+1,
     nat(N, N1)
  ).

?- time( (nat(N), N == 10000) ).
% 1,850,152 inferences, 0.544 CPU in 0.545 seconds (100% CPU, 3399793 Lips)

Which is only an improvement for queries like the following. Otherwise it is just a waste of resources.

?- N in 1..2, nat(N).
like image 128
false Avatar answered Feb 20 '23 10:02

false