The "best" way depends on your specific use cases! Here's another way to do this with clpfd :
:- use_module(library(clpfd)).
We define the predicate equidistant_stride/2 proposed by @mat in a comment on a previous answer to a related question :
equidistant_stride([],_). equidistant_stride([Z|Zs],D) :- foldl(equidistant_stride_(D),Zs,Z,_). equidistant_stride_(D,Z1,Z0,Z1) :- Z1
Based on equidistant_stride/2 , we define:
consecutive_ascending_integers(Zs) :- equidistant_stride(Zs,1). consecutive_ascending_integers_from(Zs,Z0) :- Zs = [Z0|_], consecutive_ascending_integers(Zs). consecutive_ascending_integers_from_1(Zs) :- consecutive_ascending_integers_from(Zs,1).
Run some queries! First, your initial use case:
?- length(Zs,N), consecutive_ascending_integers_from_1(Zs). N = 1, Zs = [1] ; N = 2, Zs = [1,2] ; N = 3, Zs = [1,2,3] ; N = 4, Zs = [1,2,3,4] ; N = 5, Zs = [1,2,3,4,5] ...
With clpfd , we can ask fairly general queries - and get logical answers too!
? - consecutive_ascending_integers ([A, B, 0 , D, E]).
A = -2, B = -1, D = 1, E = 2.
? - consecutive_ascending_integers ([A, B, C, D, E]).
A + 1 # = B, B + 1 # = C, C + 1 # = D, D + 1 # = E.
Alternative implementation of equidistant_stride/2 :
I hope the new code makes better use of proliferation restrictions.
Thanks to @WillNess for offering test cases that motivated this rewriting!
equidistant_from_nth_stride([],_,_,_). equidistant_from_nth_stride([Z|Zs],Z0,N,D) :- Z #= Z0 + N*D, N1 #= N+1, equidistant_from_nth_stride(Zs,Z0,N1,D). equidistant_stride([],_). equidistant_stride([Z0|Zs],D) :- equidistant_from_nth_stride(Zs,Z0,1,D).
Comparison of the old vs new version with @mat clpfd:
First, the old version:
?- equidistant_stride([1,_,_,_,14],D). _G1133+D
Now go to the new version and ask the same requests!
? - equidistant_stride ([1, _, _, _, 14], D).
false % fails, as it should
? - equidistant_stride ([1, _, _, _, 14 | _], D).
false % fails, as it should
Once again, again! Can we fail earlier by using redundant constraints beforehand?
Earlier, we proposed using the restrictions Z1 #= Z0+D*1, Z2 #= Z0+D*2, Z3 #= Z0+D*3 instead of Z1 #= Z0+D, Z2 #= Z1+D, Z3 #= Z2+D (which is in the 1st version of the code in this answer).
Again, thanks to @WillNess for motivating this little experiment, noting that the goal of equidistant_stride([_,4,_,_,14],D) does not fail, but succeeds with pending achievements instead:
?- Zs = [_,4,_,_,14], equidistant_stride(Zs,D). Zs = [_G2650, 4, _G2656, _G2659, 14], 14
Add some redundant restrictions with equidistantRED_stride/2 :
equidistantRED_stride([],_). equidistantRED_stride([Z|Zs],D) :- equidistant_from_nth_stride(Zs,Z,1,D), equidistantRED_stride(Zs,D).
Request example:
?- Zs = [_,4,_,_,14], equidistant_stride(Zs,D), equidistantRED_stride(Zs,D). false.
Are you done? Not yet! In the general case, we do not want a quadratic number of redundant constraints. That's why:
?- Zs = [_,_,_,_,14], equidistant_stride(Zs,D). Zs = [_G2683, _G2686, _G2689, _G2692, 14], 14#=_G2683+4*D, _G2692#=_G2683+3*D, _G2689#=_G2683+2*D, _G2686#=_G2683+D. ?- Zs = [_,_,_,_,14], equidistant_stride(Zs,D), equidistantRED_stride(Zs,D). Zs = [_G831, _G834, _G837, _G840, 14], 14#=_G831+4*D, _G840#=_G831+3*D, _G837#=_G831+2*D, _G834#=_G831+D, 14#=_G831+4*D, _G840#=_G831+3*D, _G837#=_G831+2*D, _G834#=_G831+D, D+_G840#=14, 14#=2*D+_G837, _G840#=D+_G837, 14#=_G834+3*D, _G840#=_G834+2*D, _G837#=_G834+D.
But if we use a double negation trick, the residual balance remains in those cases where success ...
?- Zs = [_,_,_,_,14], equidistant_stride(Zs,D), \+ \+ equidistantRED_stride(Zs,D). Zs = [_G454, _G457, _G460, _G463, 14], 14
... and ...
? - Zs = [_, 4, _, _, 14], equidistant_stride (Zs, D), \ + \ + equidistantRED_stride (Zs, D).
false
... we find failure in more cases than before!
Let dig a little deeper! Can we detect failure earlier even for more generalized purposes?
With the code so far presented, these two logically false requests do not end:
? - Zs = [_, 4, _, _, 14 | _], \ + \ + equidistantRED_stride (Zs, D), equidistant_stride (Zs, D).
...% Execution Aborted
? - Zs = [_, 4, _, _, 14 | _], equidistant_stride (Zs, D), \ + \ + equidistantRED_stride (Zs, D).
...% Execution Aborted
Is there a fix? Got a hack!
? - use_module (library (lambda)).
true
? - Zs = [_, 4, _, _, 14 | _],
\ + (term_variables (Zs, Vs),
maplist (\ X ^ when (nonvar (X), integer (X)), Vs),
\ + equidistantRED_stride (Zs, D)),
equidistant_stride (Zs, D).
false
The hack does not guarantee the end of the "part" of the excess restriction, but IMO is not so bad for a quick first shot. The integer/1 test when creating any variable in Zs means that clpfd solver to restrict domain variables to singletones, while instantiation with cons pairs (which directly leads to list-based predicates being interrupted) is suppressed.
I understand that hacking can be quite easily broken in several ways (for example, using cyclic terms). Any suggestions and comments are welcome!