How to use dynamic databases in Prolog? - list

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:)

Related

List consisting of each element of another List repeated twice Prolog

I have to write a predicate: double(X,Y) to be true when Y is the list consisting of each element of X
repeated twice (e.g. double([a,b],[a,a,b,b]) is true).
I ended with sth like this:
double([],[]).
double([T],List) :- double([H|T],List).
double([H|T],List) :- count(H, List, 2).
Its working fine for lists like [a,a,b] but it shouldnt... please help.
And i need help with another predicate: repeat(X,Y,N) to be true when Y is the list consisting of each element of X
repeated N times (e.g. repeat([a,b], [a,a,a,b,b,b],3) is true).
double([],[]).
double([I|R],[I,I|RD]) :-
double(R,RD).
Here's how you could realize that "repeat" predicate you suggested in the question:
:- use_module(library(clpfd)).
Based on if_/3 and (=)/3 we define:
each_n_reps([E|Es], N) :-
aux_n_reps(Es, E, 1, N).
aux_n_reps([], _, N, N). % internal auxiliary predicate
aux_n_reps([E|Es], E0, N0, N) :-
if_(E0 = E,
( N0 #< N, N1 #= N0+1 ), % continue current run
( N0 #= N, N1 #= 1 )), % start new run
aux_n_reps(Es, E, N1, N).
Sample queries1 using SICStus Prolog 4.3.2:
?- each_n_reps(Xs, 3).
Xs = [_A,_A,_A]
; Xs = [_A,_A,_A,_B,_B,_B] , dif(_A,_B)
; Xs = [_A,_A,_A,_B,_B,_B,_C,_C,_C], dif(_A,_B), dif(_B,_C)
...
How about fair enumeration?
?- length(Xs, _), each_n_reps(Xs, N).
N = 1, Xs = [_A]
; N = 2, Xs = [_A,_A]
; N = 1, Xs = [_A,_B] , dif(_A,_B)
; N = 3, Xs = [_A,_A,_A]
; N = 1, Xs = [_A,_B,_C] , dif(_A,_B), dif(_B,_C)
; N = 4, Xs = [_A,_A,_A,_A]
; N = 2, Xs = [_A,_A,_B,_B], dif(_A,_B)
; N = 1, Xs = [_A,_B,_C,_D], dif(_A,_B), dif(_B,_C), dif(_C,_D)
...
How can [A,B,C,D,E,F] be split into runs of equal length?
?- each_n_reps([A,B,C,D,E,F], N).
N = 6, A=B , B=C , C=D , D=E , E=F
; N = 3, A=B , B=C , dif(C,D), D=E , E=F
; N = 2, A=B , dif(B,C), C=D , dif(D,E), E=F
; N = 1, dif(A,B), dif(B,C), dif(C,D), dif(D,E), dif(E,F).
Footnote 1: Answers were reformatted to improve readability.
Ok for repeat/3 i have sth like this:
repeat1([],[],0).
repeat1([A|B],[X|T],Y):- repeat1(B,T,Z), Y is 1+Z.
repeat1([A1|B],[X1|T], Z) :- A1\=A, X1\=X, repeat1(B,T,Z).

How to convert split/3 to split/4 in Prolog?

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]).

Find the max element and its index in a list - Prolog

I am fresh in Prolog. And I am trying to write a predicate that finds the Max value and its index of a list of integers. i.e max_list([2,3,4], MAX, INDEX) will yield MAX=4, INDEX=2
Thank you for reply~ My apologize! This is the first time I ask questions in stackoverflow. I could write a predicate to find the maximum or a minimum of a list, but I don't know how to get the exact position the value in the list. I am just trying to comprehend the answers.
Using clpfd ...
:- use_module(library(clpfd)).
..., meta-predicate maplist/2, and nth0/3 we define:
zs_maximum_at(Zs,Max,Pos) :-
maplist(#>=(Max),Zs),
nth0(Pos,Zs,Max).
Here's the query the OP gave:
?- zs_maximum_at([2,3,4],M,I).
I = 2, M = 4.
OK! ... how about the most general query?
?- zs_maximum_at(Zs,M,I).
Zs = [M], I = 0, M in inf..sup
; Zs = [ M,_B], I = 0, M #>= _B
; Zs = [_A, M], I = 1, M #>= _A
; Zs = [ M,_B,_C], I = 0, M #>= _B, M #>= _C
; Zs = [_A, M,_C], I = 1, M #>= _A, M #>= _C
; Zs = [_A,_B, M], I = 2, M #>= _A, M #>= _B
; Zs = [ M,_B,_C,_D], I = 0, M #>= _B, M #>= _C, M #>= _D
; Zs = [_A, M,_C,_D], I = 1, M #>= _A, M #>= _C, M #>= _D
...
Edit: What about arithmetic expressions?
We can allow the use of arithmetic expressions by adding an additional goal (#=)/2:
zs_maximum_at(Zs,Expr,Pos) :-
maplist(#>=(Max),Zs),
nth0(Pos,Zs,Expr),
Expr #= Max.
Now we can run queries like the following one—but lose monotonicity (cf. this clpfd manual)!
?- zs_maximum_at([0+1,1+1,2-0,3-1,1+0],M,I).
I = 1, M = 1+1
; I = 2, M = 2-0
; I = 3, M = 3-1
; false.
To disable arithmetic expressions we can use length/2 in combination with ins/2:
zs_maximum_at(Zs,Max,Pos) :-
length(Zs,_),
Zs ins inf..sup,
maplist(#>=(Max),Zs),
nth0(Pos,Zs,Max).
Running above query again, we now get:
?- zs_maximum_at([0+1,1+1,2-0,3-1,1+0],M,I).
ERROR: Type error: `integer' expected, found `0+1' (a compound)
Note that the issue (of allowing arithmetic expressions or not) is not limited to clpfd.It is also present when using plain-old Prolog arithmetic predicates like is/2 and friends.
a variation on joel76 answer:
max_list(L, M, I) :- nth0(I, L, M), \+ (member(E, L), E > M).
I'm no Prolog expert myself so this is probably not the most beautiful solution, but this predicate should do what you want:
max_list([X|Xs],Max,Index):-
max_list(Xs,X,0,0,Max,Index).
max_list([],OldMax,OldIndex,_, OldMax, OldIndex).
max_list([X|Xs],OldMax,_,CurrentIndex, Max, Index):-
X > OldMax,
NewCurrentIndex is CurrentIndex + 1,
NewIndex is NewCurrentIndex,
max_list(Xs, X, NewIndex, NewCurrentIndex, Max, Index).
max_list([X|Xs],OldMax,OldIndex,CurrentIndex, Max, Index):-
X =< OldMax,
NewCurrentIndex is CurrentIndex + 1,
max_list(Xs, OldMax, OldIndex, NewCurrentIndex, Max, Index).
Another approach, not very efficient but more "prologish" is to say :
What is the max of a list ? it's a member of the list, and no other member of this list is greater than the max !
So :
max_list(Lst, Max, Ind) :-
member(Max, Lst),
\+((member(N, Lst), N > Max)),
% Now, with SWI-Prolog, (may be with other Prolog)
% nth0/3 gives you the index of an element in a list
nth0(Ind, Lst, Max).

Prolog: Take the first "N" elements of a list

I need to write a Prolog predicate take(L, N, L1) which succeeds if list L1 contains the first N elements of list L, in the same order. For example:
?- take([5,1,2,7], 3, L1).
L1 = [5,1,2]
?- take([5,1,2,7], 10, L1).
L1 = [5,1,2,7]
Prolog thus far is making little sense to me, and I'm having a hard time breaking it down. Here is what I have so far:
take([H|T], 0, []).
take([H|T], N, L1) :-
take(T, X, L2),
X is N-1.
Can you please explain what I did wrong here?
Here is a definition that implements the relational counterpart to take in functional languages like Haskell1. First, the argument order should be different which facilitates partial application. There is a cut, but only after the error checking built-in (=<)/2 which produces an instantiation_error should the argument contain a variable.
take(N, _, Xs) :- N =< 0, !, N =:= 0, Xs = [].
take(_, [], []).
take(N, [X|Xs], [X|Ys]) :- M is N-1, take(M, Xs, Ys).
?- take(2, Xs, Ys).
Xs = [], Ys = []
; Xs = [_A], Ys = [_A]
; Xs = [_A,_B|_C], Ys = [_A,_B].
Note how above query reads:
How can one take 2 elements from Xs to get Ys?
And there are 3 different answers. If Xs is empty, then so is Ys. If Xs is a list with one element, then so is Ys. If Xs has at least 2 elements, then those two are Ys.
1) The only difference being that take(-1, Xs,Ys) fails (for all Xs, Ys). Probably the best would be to issue a domain_error similar to arg(-1,s(1),2)
findall/3 it's a bit the 'swiss knife' of Prolog. I would use this snippet:
take(Src,N,L) :- findall(E, (nth1(I,Src,E), I =< N), L).
The code by #CapelliC works if the instantiation is right; if not, it can show erratic behavior:
?- take(Es, 0, Xs).
**LOOPS** % trouble: goal does not terminate
?- take([A,_], 1, [x]).
true. % trouble: variable A remains unbound
To safeguard against this you can use
iwhen/2 like so:
take(Src, N, L) :-
iwhen(ground(N+Src), findall(E, (nth1(I,Src,E), I =< N), L)).
Sample queries run with SWI-Prolog 8.0.0:
?- take([a,b,c,d,e,f], 3, Ls).
Ls = [a,b,c].
?- take([a,b,c,d,e,f], N, Ls).
ERROR: Arguments are not sufficiently instantiated
?- take(Es, 0, Xs).
ERROR: Arguments are not sufficiently instantiated
?- take([A,_], 1, [x]).
ERROR: Arguments are not sufficiently instantiated
Safer now!
The obvious solution would be:
take(List, N, Prefix) :-
length(List, Len),
( Len =< N
-> Prefix = List
; length(Prefix, N),
append(Prefix, _, List)
).
Less thinking means less opportunity for mistakes. It also makes the predicate more general.
your base case is fine
take([H|T], 0, []).
And also you can say what if N is 1
take([H|T],1,[H]).
But you recursive case some variable is not defined like L2. So we can write this as
take([X|T1],N,[X|T2]):-
N>=0,
N1 is N-1,
take(T1,N1,T2).
which case all varibles are pattern-matched.
take(L, N, L1) :- length(L1, N), append(L1, _, L).
This is performant, general and deterministic:
first_elements_of_list(IntElems, LongLst, ShortLst) :-
LongLst = [H|T],
( nonvar(IntElems) -> Once = true
; is_list(ShortLst) -> Once = true
; Once = false
),
first_elements_of_list_(T, H, 1, IntElems, ShortLst),
(Once = true -> ! ; true).
first_elements_of_list_([], H, I, I, [H]).
first_elements_of_list_([_|_], H, I, I, [H]).
first_elements_of_list_([H|LongLst], PrevH, Upto, IntElems, [PrevH|ShortLst]) :-
Upto1 is Upto + 1,
first_elements_of_list_(LongLst, H, Upto1, IntElems, ShortLst).
Result in swi-prolog:
?- first_elements_of_list(N, [a, b, c], S).
N = 1,
S = [a] ;
N = 2,
S = [a,b] ;
N = 3,
S = [a,b,c].
?- first_elements_of_list(2, [a, b, c], S).
S = [a,b].
Below is a variant which also supports:
?- first_elements_of_list_more(10, [5, 1, 2, 7], L1).
L1 = [5,1,2,7].
first_elements_of_list_more(IntElems, [H|LongLst], [H|ShortLst]) :-
once_if_nonvar(IntElems, first_elements_of_list_more_(LongLst, 1, IntElems, ShortLst)).
first_elements_of_list_more_([], Inc, Elems, []) :-
(var(Elems) -> Inc = Elems
; Elems >= Inc).
first_elements_of_list_more_([_|_], E, E, []).
first_elements_of_list_more_([H|LongLst], Upto, IntElems, [H|ShortLst]) :-
succ(Upto, Upto1),
first_elements_of_list_more_(LongLst, Upto1, IntElems, ShortLst).
once_if_nonvar(Var, Expr) :-
nonvar(Var, Bool),
call(Expr),
(Bool == true -> ! ; true).
nonvar(Var, Bool) :-
(nonvar(Var) -> Bool = true ; Bool = false).

Fill list in SWI-Prolog

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