Related
I have written the following program, which calculates the longest non-decreasing sub-sequence of input array.
The sub-program to find the longest list from the list of lists is taken from stackoverflow (How do I find the longest list in a list of lists) itself.
:- dynamic lns/2.
:- retractall(lns(_, _)).
lns([], []).
lns([X|_], [X]).
lns([X|Xs], [X, Y|Ls]) :-
lns(Xs, [Y|Ls]),
X < Y,
asserta(lns([X|Xs], [X, Y|Ls])).
lns([_|Xs], [Y|Ls]) :-
lns(Xs, [Y|Ls]).
% Find the longest list from the list of lists.
lengths([], []).
lengths([H|T], [LH|LengthsT]) :-
length(H, LH),
lengths(T, LengthsT).
lengthLongest(ListOfLists, Max) :-
lengths(ListOfLists, Lengths),
max_list(Lengths, Max).
longestList(ListOfLists, Longest) :-
lengthLongest(ListOfLists, Len),
member(Longest, ListOfLists),
length(Longest, Len).
optimum_solution(List, Ans) :-
setof(A, lns(List, A), P),
longestList(P, Ans),
!.
I have used the Prolog dynamic database for memoization purpose.
Though the program with database runs slower than the program without database. Below are the comparative times between two runs.
?- time(optimum_solution([0, 8, 4, 12, 2, 10, 6, 14, 1, 9], Ans)).
% 53,397 inferences, 0.088 CPU in 0.088 seconds (100% CPU, 609577 Lips)
Ans = [0, 2, 6, 9]. %% With database
?- time(optimum_solution([0, 8, 4, 12, 2, 10, 6, 14, 1, 9], Ans)).
% 4,097 inferences, 0.002 CPU in 0.002 seconds (100% CPU, 2322004 Lips)
Ans = [0, 2, 6, 9]. %% Without database. commented out the database usage.
I would like to know if I am using the dynamic database correctly. Thanks!
The issue is that as you are traversing the list building subsequences, you need to consider only prior subsequences whose last value is less than the value you have in-hand. The problem is that Prolog's first-argument indexing is doing an equality check, not a less-than check. So Prolog will have to traverse the entire store of lns/2, unifying the first parameter with a value so you can check to see if it's less and then backtracking to get the next.
Earlier, we presented a concise solution based on clpfd.
Now we aim at generality and efficiency!
:- use_module([library(clpfd), library(lists)]).
list_long_nondecreasing_subseq(Zs, Xs) :-
minimum(Min, Zs),
append(_, Suffix, Zs),
same_length(Suffix, Xs),
zs_subseq_taken0(Zs, Xs, Min).
zs_subseq_taken0([], [], _).
zs_subseq_taken0([E|Es], [E|Xs], E0) :-
E0 #=< E,
zs_subseq_taken0(Es, Xs, E).
zs_subseq_taken0([E|Es], Xs, E0) :-
zs_subseq_taken0_min0_max0(Es, Xs, E0, E, E).
zs_subseq_taken0_min0_max0([], [], E0, _, Max) :-
Max #< E0.
zs_subseq_taken0_min0_max0([E|Es], [E|Xs], E0, Min, Max) :-
E0 #=< E,
E0 #> Min #\/ Min #> E,
E0 #> Max #\/ Max #> E,
zs_subseq_taken0(Es, Xs, E).
zs_subseq_taken0_min0_max0([E|Es], Xs, E0, Min0, Max0) :-
Min #= min(Min0,E),
Max #= max(Max0,E),
zs_subseq_taken0_min0_max0(Es, Xs, E0, Min, Max).
Sample query using SICStus Prolog 4.3.2 (with pretty-printed answer sequence):
?- list_long_nondecreasing_subseq([0,8,4,12,2,10,6,14,1,9], Xs).
Xs = [0,8,12,14]
; Xs = [0,8,10,14]
; Xs = [0,4,12,14]
; Xs = [0,4,10,14]
; Xs = [0,4, 6,14]
; Xs = [0,4, 6, 9]
; Xs = [0,2,10,14]
; Xs = [0,2, 6,14]
; Xs = [0,2, 6, 9]
; Xs = [0,8,9]
; Xs = [0,4,9]
; Xs = [0,2,9]
; Xs = [0,1,9]
; false.
Note that the answer sequence of list_long_nondecreasing_subseq/2
may be a lot smaller than the one given by list_nondecreasing_subseq/2.
Above list [0,8,4,12,2,10,6,14,1,9] has 9 non-descending subsequences of length 4—all are "returned" by both list_nondecreasing_subseq/2 and
list_long_nondecreasing_subseq/2.
The respective answer sequence sizes, however, differ considerably: (65+9=74) vs (4+9=13).
TL;DR:
In this answer we implement a very general approach based on clpfd.
:- use_module(library(clpfd)).
list_nondecreasing_subseq(Zs, Xs) :-
append(_, Suffix, Zs),
same_length(Suffix, Xs),
chain(Xs, #=<),
list_subseq(Zs, Xs). % a.k.a. subset/2 by #gusbro
Sample query using SWI-Prolog 7.3.16:
?- list_nondecreasing_subseq([0,8,4,12,2,10,6,14,1,9], Zs).
Zs = [0,8,12,14]
; Zs = [0,8,10,14]
; Zs = [0,4,12,14]
; Zs = [0,4,10,14]
; Zs = [0,4,6,14]
; Zs = [0,4,6,9]
; Zs = [0,2,10,14]
; Zs = [0,2,6,14]
; Zs = [0,2,6,9]
; Zs = [0,8,12]
...
; Zs = [9]
; Zs = []
; false.
Note the particular order of the answer sequence!
The longest lists come first, followed by the lists a little smaller ... all the way down to singleton lists, and the empty list.
Keeps getting better!
In this answer we present list_long_nondecreasing_subseq__NEW/2, a drop-in replacement of list_long_nondecreasing_subseq/2—presented in this earlier answer.
Let's cut to the chase and define list_long_nondecreasing_subseq__NEW/2!
:- use_module([library(clpfd), library(lists), library(random), library(between)]).
list_long_nondecreasing_subseq__NEW(Zs, Xs) :-
minimum(Min, Zs),
append(Prefix, Suffix, Zs),
same_length(Suffix, Xs),
zs_skipped_subseq_taken0(Zs, Prefix, Xs, Min).
zs_skipped_subseq_taken0([], _, [], _).
zs_skipped_subseq_taken0([E|Es], Ps, [E|Xs], E0) :-
E0 #=< E,
zs_skipped_subseq_taken0(Es, Ps, Xs, E).
zs_skipped_subseq_taken0([E|Es], [_|Ps], Xs, E0) :-
zs_skipped_subseq_taken0_min0_max0(Es, Ps, Xs, E0, E, E).
zs_skipped_subseq_taken0_min0_max0([], _, [], E0, _, Max) :-
Max #< E0.
zs_skipped_subseq_taken0_min0_max0([E|Es], Ps, [E|Xs], E0, Min, Max) :-
E0 #=< E,
E0 #> Min #\/ Min #> E,
E0 #> Max #\/ Max #> E,
zs_skipped_subseq_taken0(Es, Ps, Xs, E).
zs_skipped_subseq_taken0_min0_max0([E|Es], [_|Ps], Xs, E0, Min0, Max0) :-
Min #= min(Min0,E),
Max #= max(Max0,E),
zs_skipped_subseq_taken0_min0_max0(Es, Ps, Xs, E0, Min, Max).
So ... does it still work as before? Let's run some tests and compare the answer sequences:
| ?- setrand(random(29251,13760,3736,425005073)),
between(7, 23, N),
nl,
write(n=N),
write(' '),
length(Zs, N),
between(1, 10, _),
maplist(random(1,N), Zs),
findall(Xs1, list_long_nondecreasing_subseq( Zs,Xs1), Xss1),
findall(Xs2, list_long_nondecreasing_subseq__NEW(Zs,Xs2), Xss2),
( Xss1 == Xss2 -> true ; throw(up) ),
length(Xss2,L),
write({L}),
false.
n=7 {3}{8}{3}{7}{2}{5}{4}{4}{8}{4}
n=8 {9}{9}{9}{8}{4}{4}{7}{5}{6}{9}
n=9 {9}{8}{5}{7}{10}{7}{9}{4}{5}{4}
n=10 {7}{12}{7}{14}{13}{19}{13}{17}{10}{7}
n=11 {14}{17}{7}{9}{17}{21}{14}{10}{10}{21}
n=12 {25}{18}{20}{10}{32}{35}{7}{30}{15}{11}
n=13 {37}{19}{18}{22}{20}{14}{10}{11}{8}{14}
n=14 {27}{9}{18}{10}{20}{29}{69}{28}{10}{33}
n=15 {17}{24}{13}{26}{32}{14}{22}{28}{32}{41}
n=16 {41}{55}{35}{73}{44}{22}{46}{47}{26}{23}
n=17 {54}{43}{38}{110}{50}{33}{48}{64}{33}{56}
n=18 {172}{29}{79}{36}{32}{99}{55}{48}{83}{37}
n=19 {225}{83}{119}{61}{27}{67}{48}{65}{90}{96}
n=20 {58}{121}{206}{169}{111}{66}{233}{57}{110}{146}
n=21 {44}{108}{89}{99}{149}{148}{92}{76}{53}{47}
n=22 {107}{137}{221}{79}{172}{156}{184}{78}{162}{112}
n=23 {163}{62}{76}{192}{133}{372}{101}{290}{84}{378}
no
All answer sequences were exactly identical! ... So, how about runtimes?
Let's run some more queries using SICStus Prolog 4.3.2 and pretty-print the answers!
?- member(N, [15,20,25,30,35,40,45,50]),
length(Zs, N),
_NN #= N*N,
maplist(random(1,_NN), Zs),
call_time(once(list_long_nondecreasing_subseq( Zs, Xs )), T1),
call_time(once(list_long_nondecreasing_subseq__NEW(Zs,_Xs2)), T2),
Xs == _Xs2,
length(Xs,L).
N = 15, L = 4, T1 = 20, T2 = 0, Zs = [224,150,161,104,134,43,9,111,76,125,50,68,202,178,148], Xs = [104,111,125,202] ;
N = 20, L = 6, T1 = 60, T2 = 10, Zs = [71,203,332,366,350,19,241,88,370,100,288,199,235,343,181,90,63,149,215,285], Xs = [71,88,100,199,235,343] ;
N = 25, L = 7, T1 = 210, T2 = 20, Zs = [62,411,250,222,141,292,276,94,548,322,13,317,68,488,137,33,80,167,101,475,475,429,217,25,477], Xs = [62,250,292,322,475,475,477] ;
N = 30, L = 10, T1 = 870, T2 = 30, Zs = [67,175,818,741,669,312,99,23,478,696,63,793,280,364,677,254,530,216,291,660,218,664,476,556,678,626,75,834,578,850], Xs = [67,175,312,478,530,660,664,678,834,850] ;
N = 35, L = 7, T1 = 960, T2 = 120, Zs = [675,763,1141,1070,299,650,1061,1184,512,905,139,719,844,8,1186,1006,400,690,29,791,308,1180,819,331,482,982,81,574,1220,431,416,357,1139,636,591], Xs = [299,650,719,844,1006,1180,1220] ;
N = 40, L = 9, T1 = 5400, T2 = 470, Zs = [958,1047,132,1381,22,991,701,1548,470,1281,358,32,605,1270,692,1020,350,794,1451,11,985,1196,504,1367,618,1064,961,463,736,907,1103,719,1385,1026,935,489,1053,380,637,51], Xs = [132,470,605,692,794,985,1196,1367,1385] ;
N = 45, L = 10, T1 = 16570, T2 = 1580, Zs = [1452,171,442,1751,160,1046,470,450,1245,971,1574,901,1613,1214,1849,1805,341,34,1923,698,156,1696,717,1708,1814,1548,463,421,1584,190,1195,1563,1772,1639,712,693,1848,1531,250,783,1654,1732,1333,717,1322], Xs = [171,442,1046,1245,1574,1613,1696,1708,1814,1848] ;
N = 50, L = 11, T1 = 17800, T2 = 1360, Zs = [2478,2011,2411,1127,1719,1286,1081,2042,1166,86,355,894,190,7,1973,1912,753,1411,1082,70,2142,417,1609,1649,2329,2477,1324,37,1781,1897,2415,1018,183,2422,1619,1446,1461,271,56,2399,1681,267,977,826,2145,2318,2391,137,55,1995], Xs = [86,355,894,1411,1609,1649,1781,1897,2145,2318,2391] ;
false.
Of course, the baroque approach shown in this answer simply cannot compete with "serious" suitable algorithms for determining the lis—still, getting 10X speedup always feels good:)
Below code works for split_list/3:
split_list([], _, [[],[]]).
split_list(T, 0, [[],T]).
split_list([H|T], N, [[H|Y],Z]) :-
N1 is N-1,
split_list(T, N1, [Y,Z]).
For example:
?- split_list([a,s,d,f,g,h,j], 3, R).
R = [[a, s, d], [f, g, h, j]] . % observed answer
But, I want to convert split_list/3 to split/4:
?- split([a,s,d,f,g,h,j], 2, R1, R2).
R1 = [a,s], R2 = [d,f,g,h,j]. % expected answer
How can I get the answer that I want? Any suggestions? Thank you :)
Here's a straight-forward definition of split/4:
split(AsBs, N, As, Bs) :-
append(As, Bs, AsBs),
length(As, N).
Sample query as given by the OP:
?- split([a,s,d,f,g,h,j], 2, R1, R2).
R1 = [a,s], R2 = [d,f,g,h,j]
; false.
How about a generalisation of above query?
?- split([a,s,d,f,g,h,j], I, R1, R2).
I = 0, R1 = [], R2 = [a,s,d,f,g,h,j]
; I = 1, R1 = [a], R2 = [s,d,f,g,h,j]
; I = 2, R1 = [a,s], R2 = [d,f,g,h,j]
; I = 3, R1 = [a,s,d], R2 = [f,g,h,j]
; I = 4, R1 = [a,s,d,f], R2 = [g,h,j]
; I = 5, R1 = [a,s,d,f,g], R2 = [h,j]
; I = 6, R1 = [a,s,d,f,g,h], R2 = [j]
; I = 7, R1 = [a,s,d,f,g,h,j], R2 = [].
In this answer, we use clpfd constraints for expressing declarative integer arithmetic.
:- use_module(library(clpfd)).
We define split/4 by combining the code of append/3 and the code1 of fd_length/2.
Note the parallels of fd_length/2 with split/4 and of fd_length/3 with split_/5:
split(Zs, N, Xs, Ys) :- %% fd_length(Xs, N) :-
N #>= 0, %% N #>= 0,
split_(Xs, N,0, Ys, Zs). %% fd_length(Xs, N,0).
%%
split_([], N,N0, Zs, Zs) :- %% fd_length([], N,N0) :-
N #= N0. %% N #= N0.
split_([X|Xs], N,N0, Ys, [X|Zs]) :- %% fd_length([_|Xs], N,N0) :-
N1 #= N0+1, %% N1 #= N0+1,
N #>= N1, %% N #>= N1,
split_(Xs, N,N1, Ys, Zs). %% fd_length(Xs, N,N1).
Now, if look at the code of split_/5 again, then we can see the code of append/3 in it:
%% split_([], N,N0, Zs, Zs) :- %% append([], Zs, Zs).
%% N #= N0, %%
%% split_([X|Xs], N,N0, Ys, [X|Zs]) :- %% append([X|Xs], Ys, [X|Zs]) :-
%% N1 #= N0+1, %%
%% N #>= N1, %%
%% split_(Xs, N,N1, Ys, Zs). %% append(Xs, Ys, Zs).
Sample queries:
?- N = 2, split(XsYs, N, Xs, Ys).
XsYs = [_A,_B|Ys], N = 2, Xs = [_A,_B]
; false.
?- N = 2, XsYs = [a,b,c,d,e], split(XsYs, N, Xs, Ys).
XsYs = [a,b,c,d,e], N = 2, Xs = [a,b], Ys = [c,d,e]
; false.
?- XsYs = [a,s,d,f,g,h,j], split(XsYs, N, Xs, Ys).
XsYs = [a,s,d,f,g,h,j], N = 0, Xs = [] , Ys = [a,s,d,f,g,h,j]
; XsYs = [a,s,d,f,g,h,j], N = 1, Xs = [a] , Ys = [s,d,f,g,h,j]
; XsYs = [a,s,d,f,g,h,j], N = 2, Xs = [a,s] , Ys = [d,f,g,h,j]
; XsYs = [a,s,d,f,g,h,j], N = 3, Xs = [a,s,d] , Ys = [f,g,h,j]
; XsYs = [a,s,d,f,g,h,j], N = 4, Xs = [a,s,d,f] , Ys = [g,h,j]
; XsYs = [a,s,d,f,g,h,j], N = 5, Xs = [a,s,d,f,g] , Ys = [h,j]
; XsYs = [a,s,d,f,g,h,j], N = 6, Xs = [a,s,d,f,g,h] , Ys = [j]
; XsYs = [a,s,d,f,g,h,j], N = 7, Xs = [a,s,d,f,g,h,j], Ys = []
; false.
?- Xs = [a,b,c], Ys = [d,e,f], split(XsYs, N, Xs, Ys).
XsYs = [a,b,c,d,e,f], N = 3, Xs = [a,b,c], Ys = [d,e,f].
Footnote 1: To accentuate the parallels, the program text of fd_length/2 (optimized variant) was altered slightly:
L was replaced by Xs,
the argument pair N, N0 by N,N0, and
(is)/2 by (#=)/2.
if you are interested in preserving the semantic of your existing definition, you can reuse it in this way
split_list(L,N,R1,R2) :- split_list(L,N,[R1,R2]).
I have been trying to split a given list into two different lists: Unique and Duplicate.
For example, if we have the list [1, 1, 2, 3, 3, 4, 5] I want the Unique list to be [2, 4, 5] and Duplicate to be [1, 3].
I don't want all the 1's in the list to be in the Duplicate list. I just need one of it.
The code I have right now:
compareL([_|[]], Unique, Dup).
compareL([X3,Y3 | Tail], [X3 | Unique], Dup) :-
X3 =\= Y3,
compareL([Y3 | Tail], Unique, Dup).
compareL([X3,Y3 | Tail], Unique, [X3 | Dup]) :-
X3 = Y3,
skipDups(X3, Tail, Unique, Dup).
skipDups(_, [], Unique, Dup).
skipDups(X3,[Y3 | Tail], Unique, Dup) :-
X3 =\= Y3,
compareL([Y3 | Tail], Unique, Dup).
skipDups(X3,[Y3 | Tail], Unique, Dup) :-
X3 = Y3,
skipDups(X3, Tail, Unique, Dup).
Using the example list given above if I run compareL([1, 1, 2, 3, 3, 4, 5], Unique, Dup). I get:
Unique = [2, 4|_G1954],
Dup = [1, 3|_G1948].
I can't figure out why towards the end of both lists I am getting '_G1954' and '_G1948'. Any help would be appreciated. Thanks.
We can preserve logical-purity by building upon if_/3, (=)/3, and tpartition/4!
list_uniqs_dups([],[],[]).
list_uniqs_dups([X|Xs0],Us0,Ds0) :-
tpartition(=(X),Xs0,Es,Xs),
if_(Es=[],
Us0+Ds0=[X|Us]+Ds,
Ds0+Us0=[X|Ds]+Us),
list_uniqs_dups(Xs,Us,Ds).
Here's the query the OP gave:
?- list_uniqs_dups([1,1,2,3,3,4,5],Us,Ds).
Ds = [1,3], Us = [2,4,5]. % succeeds deterministically
OK! How about the following quite general queries?
?- list_uniqs_dups([],Us,Ds).
Ds = [], Us = [].
?- list_uniqs_dups([A],Us,Ds).
Ds = [], Us = [A].
?- list_uniqs_dups([A,B],Us,Ds).
Ds = [B], Us = [] , A=B
; Ds = [] , Us = [A,B], dif(A,B).
?- list_uniqs_dups([A,B,C],Us,Ds).
Ds = [C], Us = [] , A=B , B=C
; Ds = [B], Us = [C] , A=B , dif(B,C)
; Ds = [C], Us = [B] , A=C , dif(B,C)
; Ds = [C], Us = [A] , dif(A,C), B=C
; Ds = [] , Us = [A,B,C], dif(A,B), dif(A,C), dif(B,C).
Answer using (=)/3
list_uniqs_alldups(Es,Us,Ds) :
tpartition(list_uniqmember_t(Es),Es,Us,Ds).
list_uniqmember_t(Es,X,T) :-
tfilter(=(X),Es,Xs),
=(Xs,[X],T).
Sample queries:
?- list_uniqs_alldups([1,1,2,1,1,3,4,3],Us,Ds).
Us = [2, 4],
Ds = [1, 1, 1, 1, 3, 3].
?- list_uniqs_alldups([1,1,2,3,3,1,1,3,4,3],Us,Ds).
Us = [2, 4],
Ds = [1, 1, 3, 3, 1, 1, 3, 3].
?- list_uniqs_alldups([8,1,1,2,3,3,1,1,3,4,3],Us,Ds).
Us = [8, 2, 4],
Ds = [1, 1, 3, 3, 1, 1, 3, 3].
?- list_uniqs_alldups(X,Us,Ds).
X = Us, Us = Ds, Ds = [] ;
X = Us, Us = [_A], Ds = [] ;
X = Ds, Us = [], Ds = [_A,_A] ;
X = Ds, Us = [], Ds = [_A,_A,_A] ;
...
For run length encoding I used splitlistIfAdj/3.
list_rle(List,Rle) :-
splitlistIfAdj(dif,List,Rle0),
maplist(rle_length,Rle0,Rle).
rle_length([H|T],RleLen) :-
length([H|T],L),
RleLen = L*H.
Query:
?- list_rle([a,a,b,a,a,c,d,c],X).
X = [2*a, 1*b, 2*a, 1*c, 1*d, 1*c].
I am not sure how to change this so that it works in both directions.
You could then also do:
new_list_uniqs_alldups(List,Us,Ds):-
list_rle(List,Rle),
tpartition(singlelist_t,Rle,Us,Ds).
singlelist_t(L,T) :-
L=N*_,
if_(N=1,T=true,T=false).
Sample Q:
?- new_list_uniqs_alldups([1,1,2,1,1,3,4,1,1,7,8],U,D).
U = [1*2, 1*3, 1*4, 1*7, 1*8],
D = [2*1, 2*1, 2*1].
?- new_list_uniqs_alldups([7,7,7,2,1,1,3,4,1,1,7,8],U,D).
U = [1*2, 1*3, 1*4, 1*7, 1*8],
D = [3*7, 2*1, 2*1].
here is a solution, the key is take/4 that consumes all matching leading items, thus enabling easy testing of the list ( [_|_] matches any list of at least 1 element )
compareL([], [], []).
compareL([X|Xs], U, D) :-
( take(X, Xs, [_|_], Ys)
-> compareL(Ys, U, B), D = [X|B]
; compareL(Xs, A, D), U = [X|A]
).
take(X, [X|Xs], [X|R], Ys) :-
!, take(X, Xs, R, Ys).
take(_, Ys, [], Ys).
You can write that :
split_seq([], [], []).
split_seq([H | T], L1_out, L2_out) :-
split_seq(T, L1, L2),
( select(H, L1, L1_out)
-> ( member(H, L2)
-> L2_out = L2
; L2_out = [H | L2])
; L1_out = [H | L1],
L2_out = L2).
i m new in prolog that s why may be the question is easy for you but i couldnt find the answer. Can someone please help me.
I just want
a count function s.t
count([c,c,a,a,b,b,d,a,c,b,d,d,a], O).
it will returns the number of occurences of the list members.
O = [[a, 4], [b, 3], [c, 3], [d, 3]]
The following is based on my previous answer to "Remove duplicates in list (Prolog)" and on this previous answer to the question "Prolog union for A U B U C".
list_item_subtracted_count0_count/5 is derived from list_item_subtracted/3.
list_counts/2 is derived from list_setB/2, which were both defined here.
list_item_subtracted_count0_count([], _, [], N,N).
list_item_subtracted_count0_count([A|As], E, Bs1, N0,N) :-
if_(A = E,
( Bs1 = Bs , N1 is N0+1 ),
( Bs1 = [A|Bs], N1 = N0 )),
list_item_subtracted_count0_count(As, E, Bs, N1,N).
list_counts([], []).
list_counts([X|Xs], [X-N|Ys]) :-
list_item_subtracted_count0_count(Xs, X, Xs0, 1,N),
list_counts(Xs0, Ys).
Here's the query the OP gave:
?- list_counts([c,c,a,a,b,b,d,a,c,b,d,d,a], Xss).
Xss = [c-3,a-4,b-3,d-3]. % succeeds deterministically
Note the order of pairs X-N in Counts corresponds to the first occurrence of X in Xs:
?- list_counts([a,b,c,d], Xss).
Xss = [a-1,b-1,c-1,d-1].
?- list_counts([d,c,b,a], Xss).
Xss = [d-1,c-1,b-1,a-1].
Last, let's consider all possible lists Es—enumerated fairly with ascending lengths:
?- length(Es, N), list_counts(Es, Xss).
N = 0, Es = [], Xss = []
; N = 1, Es = [A], Xss = [A-1]
; N = 2, Es = [A,A], Xss = [A-2]
; N = 2, Es = [A,B], Xss = [A-1,B-1], dif(B,A)
; N = 3, Es = [A,A,A], Xss = [A-3]
; N = 3, Es = [A,A,B], Xss = [A-2,B-1], dif(B,A)
; N = 3, Es = [A,B,A], Xss = [A-2,B-1], dif(B,A)
; N = 3, Es = [B,A,A], Xss = [B-1,A-2], dif(A,B), dif(A,B)
; N = 3, Es = [A,B,C], Xss = [A-1,B-1,C-1], dif(C,A), dif(C,B), dif(B,A)
...
co(X,L) :- co(X,[],L).
co([],A,A).
co([X|Xs], A, L) :- p(X-Z,A,R), !, Z1 is Z+1, co(Xs, [X-Z1|R], L).
co([X|Xs], A, L) :- co(Xs, [X-1|A], L).
p(X-Y,[X-Y|R],R):- !.
p(X,[H|Y], [H|Z]) :- p(X,Y,Z).
I did not use very meaningful names on purpose. Try to understand what each one of the predicates does.
I am trying to fill a list of given length N with numbers 1,2,3,...,N.
I thought this could be done this way:
create_list(N,L) :-
length(L,N),
forall(between(1,N,X), nth1(X,L,X)).
However, this does not seem to work. Can anyone say what I am doing wrong?
First things first: Use clpfd!
:- use_module(library(clpfd)).
In the following I present zs_between_and/3, which (in comparison to my previous answer) offers some more features.
For a start, let's define some auxiliary predicates first!
equidistant_stride([] ,_).
equidistant_stride([Z|Zs],D) :-
equidistant_prev_stride(Zs,Z,D).
equidistant_prev_stride([] ,_ ,_). % internal predicate
equidistant_prev_stride([Z1|Zs],Z0,D) :-
Z1 #= Z0+D,
equidistant_prev_stride(Zs,Z1,D).
Let's run a few queries to get a picture of equidistant_stride/2:
?- Zs = [_,_,_], equidistant_stride(Zs,D).
Zs = [_A,_B,_C], _A+D#=_B, _B+D#=_C.
?- Zs = [1,_,_], equidistant_stride(Zs,D).
Zs = [1,_B,_C], _B+D#=_C, 1+D#=_B.
?- Zs = [1,_,_], equidistant_stride(Zs,10).
Zs = [1,11,21].
So far, so good... moving on to the actual "fill list" predicate zs_between_and/3:
zs_between_and([Z0|Zs],Z0,Z1) :-
Step in -1..1,
Z0 #= Z1 #<==> Step #= 0,
Z0 #< Z1 #<==> Step #= 1,
Z0 #> Z1 #<==> Step #= -1,
N #= abs(Z1-Z0),
( fd_size(N,sup)
-> true
; labeling([enum,up],[N])
),
length(Zs,N),
labeling([enum,down],[Step]),
equidistant_prev_stride(Zs,Z0,Step).
A bit baroque, I must confess...
Let's see what features were gained---in comparison to my previous answer!
?- zs_between_and(Zs,1,4). % ascending consecutive integers
Zs = [1,2,3,4]. % (succeeds deterministically)
?- zs_between_and(Zs,3,1). % descending consecutive integers (NEW)
Zs = [3,2,1]. % (succeeds deterministically)
?- zs_between_and(Zs,L,10). % enumerates fairly
L = 10, Zs = [10] % both ascending and descenting (NEW)
; L = 9, Zs = [9,10]
; L = 11, Zs = [11,10]
; L = 8, Zs = [8,9,10]
; L = 12, Zs = [12,11,10]
; L = 7, Zs = [7,8,9,10]
...
?- L in 1..3, zs_between_and(Zs,L,6).
L = 3, Zs = [3,4,5,6]
; L = 2, Zs = [2,3,4,5,6]
; L = 1, Zs = [1,2,3,4,5,6].
Want some more? Here we go!
?- zs_between_and([1,2,3],From,To).
From = 1, To = 3
; false.
?- zs_between_and([A,2,C],From,To).
A = 1, From = 1, C = 3, To = 3 % ascending
; A = 3, From = 3, C = 1, To = 1. % descending
I don't have a prolog interpreter available right now, but wouldn't something like...
isListTo(N, L) :- reverse(R, L), isListFrom(N, R).
isListFrom(0, []).
isListFrom(N, [H|T]) :- M is N - 1, N is H, isListFrom(M, T).
reverse can be done by using e.g. http://www.webeks.net/prolog/prolog-reverse-list-function.html
So tracing isListTo(5, [1, 2, 3, 4, 5])...
isListTo(5, [1, 2, 3, 4, 5])
<=> isListFrom(5, [5, 4, 3, 2, 1])
<=> 5 is 5 and isListFrom(4, [4, 3, 2, 1])
<=> 4 is 4 and isListFrom(3, [3, 2, 1])
<=> 3 is 3 and isListFrom(2, [2, 1])
<=> 2 is 2 and isListFrom(1, [1])
<=> 1 is 1 and isListFrom(0, [])
QED
Since PROLOG will not only evaluate truth, but find satisfying solutions, this should work. I know this is a vastly different approach from the one you are trying, and apologize if your question is specifically about doing loops in PROLOG (if that is the case, perhaps re-tag the question?).
Here's a logically pure implementation of predicate zs_from_to/3 using clpfd:
:- use_module(library(clpfd)).
zs_from_to([],I0,I) :-
I0 #> I.
zs_from_to([I0|Is],I0,I) :-
I0 #=< I,
I1 #= I0 + 1,
zs_from_to(Is,I1,I).
Let's use it! First, some ground queries:
?- zs_from_to([1,2,3],1,3).
true.
?- zs_from_to([1,2,3],1,4).
false.
Next, some more general queries:
?- zs_from_to(Zs,1,7).
Zs = [1,2,3,4,5,6,7]
; false.
?- zs_from_to([1,2,3],From,To).
From = 1, To = 3.
Now, let's have some even more general queries:
?- zs_from_to(Zs,From,2).
Zs = [], From in 3..sup
; Zs = [2], From = 2
; Zs = [1,2], From = 1
; Zs = [0,1,2], From = 0
; Zs = [-1,0,1,2], From = -1
; Zs = [-2,-1,0,1,2], From = -2
...
?- zs_from_to(Zs,0,To).
Zs = [], To in inf.. -1
; Zs = [0], To = 0
; Zs = [0,1], To = 1
; Zs = [0,1,2], To = 2
; Zs = [0,1,2,3], To = 3
; Zs = [0,1,2,3,4], To = 4
...
What answers do we get for the most general query?
?- zs_from_to(Xs,I,J).
Xs = [], J#=<I+ -1
; Xs = [I], I+1#=_A, J#>=I, J#=<_A+ -1
; Xs = [I,_A], I+1#=_A, J#>=I, _A+1#=_B, J#>=_A, J#=<_B+ -1
; Xs = [I,_A,_B], I+1#=_A, J#>=I, _A+1#=_B, J#>=_A, _B+1#=_C, J#>=_B, J#=<_C+ -1
...
Edit 2015-06-07
To improve on above implementation of zs_from_to/3, let's do two things:
Try to improve determinism of the implementation.
Extract a more general higher-order idiom, and implement zs_from_to/3 on top of it.
Introducing the meta-predicates init0/3 and init1/3:
:- meta_predicate init0(2,?,?).
:- meta_predicate init1(2,?,?).
init0(P_2,Expr,Xs) :- N is Expr, length(Xs,N), init_aux(Xs,P_2,0).
init1(P_2,Expr,Xs) :- N is Expr, length(Xs,N), init_aux(Xs,P_2,1).
:- meta_predicate init_aux(?,2,+). % internal auxiliary predicate
init_aux([] , _ ,_ ).
init_aux([Z|Zs],P_2,I0) :-
call(P_2,I0,Z),
I1 is I0+1,
init_aux(Zs,P_2,I1).
Let's see init0/3 and init1/3 in action!
?- init0(=,5,Zs). % ?- numlist(0,4,Xs),maplist(=,Xs,Zs).
Zs = [0,1,2,3,4].
?- init1(=,5,Zs). % ?- numlist(1,5,Xs),maplist(=,Xs,Zs).
Zs = [1,2,3,4,5].
Ok, where do we go from here? Consider the following query:
?- init0(plus(10),5,Zs). % ?- numlist(0,4,Xs),maplist(plus(10),Xs,Zs).
Zs = [10,11,12,13,14].
Almost done! Putting it together, we define zs_from_to/2 like this:
z_z_sum(A,B,C) :- C #= A+B.
zs_from_to(Zs,I0,I) :-
N #= I-I0+1,
init0(z_z_sum(I0),N,Zs).
At last, let's see if determinism has improved!
?- zs_from_to(Zs,1,7).
Zs = [1,2,3,4,5,6,7]. % succeeds deterministically
If I understood correctly, the built-in predicate numlist/3 would do.
http://www.swi-prolog.org/pldoc/man?predicate=numlist/3