How would you code your own predicate in Prolog, to do exactly what the nth1 function does?
For those not familiar with that function, its power is best displayed through an example:
?- nth1(2, [a,b,c], E, R).
E = b
R = [a, c]
When the nth1 function is called, and is passed the following:
- an index of an element, of which is to be removed from the list (note that it is not zero-indexed, and that here, we are passing index 2)
- the list (in this case, it is [a,b,c])
- E, which will be assigned the element that was removed from the list
- R, a new list, which will hold the new list, minus that one element that was removed.
I'm stomped on how to start. Any advice would be appreciated. I know that it should be do-able using recursion in about 3 or 4 lines in SWI-Prolog, I just have no idea where to start.
Check out this link which should basically give you the answer. To get you started, consider your base case, which should be
nth1(1, [E|R], E, R).
Now how can you write the other cases by recursing on that idea? Really this is just a matter of getting the hang of Prolog list syntax.
#EMS answer is fairly good, but implementing correctly that predicate can be tricky. We must consider each instantiation pattern that make sense over the relation nth1/4, cause the question requires exactly the same builtin' behaviour. So nth1 can also search elements and insert at position.
SWI-Prolog for efficiency switch among different implementation, but should be possible model the relation testing the instantiation where needed.
Instead of nth1 I called it mth1.
mth1(1, [X|R], X, R).
mth1(_, L, _, _) :-
L == [], % (==)/2 fails when L is a var
!, fail.
mth1(P, [H|T], X, [H|R]) :-
( var(P) % are we searching the position?
-> mth1(Q, T, X, R),
P is Q + 1
; Q is P - 1,
mth1(Q, T, X, R)
).
the test L == [] is required to insert.
Of course debugging it is mandatory, here some simple test:
?- mth1(2,[a,b,c,d,e],X,Y).
X = b,
Y = [a, c, d, e] ;
false.
?- mth1(X,[a,b,c,d,e],b,Y).
X = 2,
Y = [a, c, d, e] ;
false.
?- mth1(2,X,b,[a,c,d,e]).
X = [a, b, c, d, e] ;
false.
You should check if all instantiation patterns allowed by SWI-Prolog are covered...
How does perform this simple minded implementation? Here a basic test
test_performance(N) :-
numlist(1, N, L),
time(test_performance(L, N, nth1)),
time(test_performance(L, N, mth1)).
test_performance(L, N, P) :-
writeln(P),
writeln('access last'),
time((call(P, N, L, X, _), assertion(X == N))),
writeln('find position of last'),
time((call(P, Z, L, N, _), assertion(Z == N))),
writeln('add tail'),
time(call(P, N, _, tail, L)).
To my surprise, peeking the element and adding at tail are (slightly) faster, while find position is way slower (because of miss tail recursion?):
?- test_performance(1000000).
nth1
access last
% 1,000,011 inferences, 0,624 CPU in 0,626 seconds (100% CPU, 1602617 Lips)
find position of last
% 1,000,003 inferences, 0,670 CPU in 0,671 seconds (100% CPU, 1493572 Lips)
add tail
% 1,000,009 inferences, 0,482 CPU in 0,484 seconds (100% CPU, 2073495 Lips)
% 3,000,243 inferences, 1,777 CPU in 1,781 seconds (100% CPU, 1688815 Lips)
mth1
access last
% 1,000,002 inferences, 0,562 CPU in 0,563 seconds (100% CPU, 1779702 Lips)
find position of last
% 2,000,001 inferences, 1,998 CPU in 2,003 seconds (100% CPU, 1001119 Lips)
add tail
% 1,000,000 inferences, 0,459 CPU in 0,460 seconds (100% CPU, 2179175 Lips)
% 4,000,223 inferences, 3,019 CPU in 3,027 seconds (100% CPU, 1324901 Lips)
true .
Indeed, with longer lists the position search shows its inefficiency, with a classic StackOverflow:
?- test_performance(2000000).
nth1
access last
% 2,000,011 inferences, 1,218 CPU in 1,221 seconds (100% CPU, 1641399 Lips)
find position of last
% 2,000,003 inferences, 1,327 CPU in 1,330 seconds (100% CPU, 1507572 Lips)
add tail
% 2,000,009 inferences, 0,958 CPU in 0,960 seconds (100% CPU, 2088038 Lips)
% 6,000,243 inferences, 3,504 CPU in 3,511 seconds (100% CPU, 1712549 Lips)
mth1
access last
% 2,000,002 inferences, 1,116 CPU in 1,118 seconds (100% CPU, 1792625 Lips)
find position of last
% 1,973,658 inferences, 2,479 CPU in 2,485 seconds (100% CPU, 796219 Lips)
% 3,973,811 inferences, 3,595 CPU in 3,603 seconds (100% CPU, 1105378 Lips)
ERROR: Out of local stack
Suggest searching for nth1 in the swi-prolog implementation source at:
http://www.swi-prolog.org/pldoc/doc/swi/library/lists.pl?show=src
The trickiness is that you have to generate OR return the nth1 item, depending on which unbound variable you pass in.. so it might not be possible to do in a few lines.
First, decompose the problem into smaller constituent parts. To select the Nth item from a list is easy. Collection the difference is less so.
Therefore, break it down into two parts:
First, burst the list into a prefix, the desired item and the suffix.
Next, concatenate the prefix and suffix via append/3 to form the remainder list.
Your my_nth1\4 predicate should therefore look something like so:
nth1( N , List , Nth, Rest ) :-
burst( N , List , Pfx , Nth , Sfx ) ,
append( Pfx , Sfx , Rest )
.
% ------------------------------------------------------------------------------
% burst a list into 3 parts - a prefix, an item and a suffix
% based on the specified offset N (where 0 indicates the first item of the list)
%
% The prefix is built up using a "difference list" as we recurse down looking
% for the Nth item.
% ------------------------------------------------------------------------------
burst( 0 , [L|Ls] , [] , L , Ls ).
burst( N , [L|Ls] , [L|Pfx] , Nth , Sfx ) :-
N > 0 ,
N1 is N - 1 ,
burst( N1 , Ls , Pfx , Nth , Sfx )
.
Related
The point of the program is to calculate the sum of all even numbers in a list of integers.
is_even(Q):- Q mod 2 =:= 0.
sum_even([],0).
sum_even([A|L],X) :- sum_even(L,X1) -> is_even(A) -> X is X1 + A .
Whenever the is_even predicate succeeds there is no problem, it normally goes back to calculate the sum. However when the number is not even and is_even checks it, it fails, goes back to the recursion and fails everything that follows, doesn't even check if the number is even anymore and just returns false. In a list full of even numbers it works as intended, it returns the sum of all numbers in the list. This here is the trace of the code
Using an accumulator with tail-end recursion is fastest:
is_even(N) :-
N mod 2 =:= 0.
sum_even(Lst, Sum) :-
sum_even_(Lst, 0, Sum).
sum_even_([], Sum, Sum).
sum_even_([H|T], Upto, Sum) :-
( is_even(H) ->
Upto1 is Upto + H
; Upto1 = Upto
),
sum_even_(T, Upto1, Sum).
sum_even_slow([], 0).
sum_even_slow([H|T], Sum) :-
sum_even_slow(T, Sum0),
( is_even(H) ->
Sum is Sum0 + H
; Sum = Sum0
).
Performance comparison in swi-prolog:
?- numlist(1, 1_000_000, L), time(sum_even(L, Sum)).
% 4,000,002 inferences, 0.765 CPU in 0.759 seconds (101% CPU, 5228211 Lips)
Sum = 250000500000.
?- numlist(1, 1_000_000, L), time(sum_even_slow(L, Sum)).
% 4,000,001 inferences, 4.062 CPU in 4.023 seconds (101% CPU, 984755 Lips)
Sum = 250000500000.
add_even(X, Buffer, Sum) :-
(0 =:= X mod 2 ->
Sum is Buffer + X
; Sum = Buffer).
Used with foldl(add_even, Nums, 0, Sum) is about as fast as brebs' tail recursion. Using SWISH Online:
?- numlist(1, 1_000_000, _L), time(sum_even(_L, Sum)).
4,000,002 inferences, 0.699 CPU in 0.699 seconds (100% CPU, 5724382 Lips)
Sum = 250000500000
?- numlist(1, 1_000_000, _L), time(foldl(add_even, _L, 0, Sum)).
4,000,002 inferences, 0.712 CPU in 0.712 seconds (100% CPU, 5621314 Lips)
Sum = 250000500000
(I am curious, if they both do exactly 4,000,002 inferences how come the sum_even seems to get higher LIPS throughput and finish slightly faster?)
The reason that this
is_even(Q):- Q mod 2 =:= 0.
sum_even([],0).
sum_even([A|L],X) :- sum_even(L,X1) -> is_even(A) -> X is X1 + A .
fails when there's odd numbers in the list is that '->'/2, the "implies" operator, is a soft cut. It eliminates the choice point. That means that backtracking into it fails, thus unwinding the whole thing and failing the entire predicate.
Your code is roughly equivalent to
sum_even([],0).
sum_even([A|L],X) :- sum_even(L,X1), !, is_even(A), !, X is X1 + A .
You need to
Eliminate the '->'/2 — it's not necessary the ',' operator is the AND operator, and
Provide an alternative to handle the case when an item is odd.
For instance, you could say this:
is_even( Q ) :- Q mod 2 =:= 0.
sum_even( [] , 0 ) .
sum_even( [A|L] , X ) :-
sum_even(L,X1),
( is_even(A) ->
X is X1 + A
;
X is X1
) .
Or something like this:
is_even( Q ) :- Q mod 2 =:= 0.
sum_even( [] , 0 ) .
sum_even( [A|L] , X ) :-
sum_even(L,X1),
add_even(A,X1,X) .
add_even(X,Y,Z) :- is_even(X), !, Z is X + Y .
add_even(_,Z,Z) .
But the easiest, faster way is to use a helper predicate that carries the extra state. The above predicates will die with a stack overflow given a sufficiently long list. This will not: Prolog has TRO (tail recursion optimization) built in, which effectively turns the recursive call into iteration by reusing the stack frame, so it can handle recursion of any depth:
sum_even( Xs , S ) :- sum_even(Xs,0,S) .
sum_even( [] , S , S ) .
sum_even( [X|Xs] , T , S ) :- is_even(X), !, T1 is T+X, sum_even(Xs,T1,S) .
is_even( Q ) :- Q mod 2 =:= 0.
I wanted to solve "the giant cat army riddle" by Dan Finkel using Prolog.
Basically you start with [0], then you build this list by using one of three operations: adding 5, adding 7, or taking sqrt. You successfully complete the game when you have managed to build a list such that 2,10 and 14 appear on the list, in that order, and there can be other numbers between them.
The rules also require that all the elements are distinct, they're all <=60 and are all only integers.
For example, starting with [0], you can apply (add5, add7, add5), which would result in [0, 5, 12, 17], but since it doesn't have 2,10,14 in that order it doesn't satisfy the game.
I think I have successfully managed to write the required facts, but I can't figure out how to actually build the list. I think using dcg is a good option for this, but I don't know how.
Here's my code:
:- use_module(library(lists)).
:- use_module(library(clpz)).
:- use_module(library(dcgs)).
% integer sqrt
isqrt(X, Y) :- Y #>= 0, X #= Y*Y.
% makes sure X occurs before Y and Y occurs before Z
before(X, Y, Z) --> ..., [X], ..., [Y], ..., [Z], ... .
... --> [].
... --> [_], ... .
% in reverse, since the operations are in reverse too.
order(Ls) :- phrase(before(14,10,2), Ls).
% rule for all the elements to be less than 60.
lt60_(X) :- X #=< 60.
lt60(Ls) :- maplist(lt60_, Ls).
% available operations
add5([L0|Rs], L) :- X #= L0+5, L = [X, L0|Rs].
add7([L0|Rs], L) :- X #= L0+7, L = [X, L0|Rs].
root([L0|Rs], L) :- isqrt(L0, X), L = [X, L0|Rs].
% base case, the game stops when Ls satisfies all the conditions.
step(Ls) --> { all_different(Ls), order(Ls), lt60(Ls) }.
% building the list
step(Ls) --> [add5(Ls, L)], step(L).
step(Ls) --> [add7(Ls, L)], step(L).
step(Ls) --> [root(Ls, L)], step(L).
The code emits the following error but I haven't tried to trace it or anything because I'm convinced that I'm using DCG incorrectly:
?- phrase(step(L), X).
caught: error(type_error(list,_65),sort/2)
I'm using Scryer-Prolog, but I think all the modules are available in swipl too, like clpfd instead of clpz.
step(Ls) --> [add5(Ls, L)], step(L).
This doesn't do what you want. It describes a list element of the form add5(Ls, L). Presumably Ls is bound to some value when you get here, but L is not bound. L would become bound if Ls were a non-empty list of the correct form, and you executed the goal add5(Ls, L). But you are not executing this goal. You are storing a term in a list. And then, with L completely unbound, some part of the code that expects it to be bound to a list will throw this error. Presumably that sort/2 call is inside all_different/1.
Edit: There are some surprisingly complex or inefficient solutions posted here. I think both DCGs and CLP are overkill here. So here's a relatively simple and fast one. For enforcing the correct 2/10/14 order this uses a state argument to keep track of which ones we have seen in the correct order:
puzzle(Solution) :-
run([0], seen_nothing, ReverseSolution),
reverse(ReverseSolution, Solution).
run(FinalList, seen_14, FinalList).
run([Head | Tail], State, Solution) :-
dif(State, seen_14),
step(Head, Next),
\+ member(Next, Tail),
state_next(State, Next, NewState),
run([Next, Head | Tail], NewState, Solution).
step(Number, Next) :-
( Next is Number + 5
; Next is Number + 7
; nth_integer_root_and_remainder(2, Number, Next, 0) ),
Next =< 60,
dif(Next, Number). % not strictly necessary, added by request
state_next(State, Next, NewState) :-
( State = seen_nothing,
Next = 2
-> NewState = seen_2
; State = seen_2,
Next = 10
-> NewState = seen_10
; State = seen_10,
Next = 14
-> NewState = seen_14
; NewState = State ).
Timing on SWI-Prolog:
?- time(puzzle(Solution)), writeln(Solution).
% 13,660,415 inferences, 0.628 CPU in 0.629 seconds (100% CPU, 21735435 Lips)
[0,5,12,17,22,29,36,6,11,16,4,2,9,3,10,15,20,25,30,35,42,49,7,14]
Solution = [0, 5, 12, 17, 22, 29, 36, 6, 11|...] .
The repeated member calls to ensure no duplicates make up the bulk of the execution time. Using a "visited" table (not shown) takes this down to about 0.25 seconds.
Edit: Pared down a bit further and made 100x faster:
prev_next(X, Y) :-
between(0, 60, X),
( Y is X + 5
; Y is X + 7
; X > 0,
nth_integer_root_and_remainder(2, X, Y, 0) ),
Y =< 60.
moves(Xs) :-
moves([0], ReversedMoves),
reverse(ReversedMoves, Xs).
moves([14 | Moves], [14 | Moves]) :-
member(10, Moves).
moves([Prev | Moves], FinalMoves) :-
Prev \= 14,
prev_next(Prev, Next),
( Next = 10
-> member(2, Moves)
; true ),
\+ member(Next, Moves),
moves([Next, Prev | Moves], FinalMoves).
?- time(moves(Solution)), writeln(Solution).
% 53,207 inferences, 0.006 CPU in 0.006 seconds (100% CPU, 8260575 Lips)
[0,5,12,17,22,29,36,6,11,16,4,2,9,3,10,15,20,25,30,35,42,49,7,14]
Solution = [0, 5, 12, 17, 22, 29, 36, 6, 11|...] .
The table of moves can be precomputed (enumerate all solutions of prev_next/2, assert them in a dynamic predicate, and call that) to gain another millisecond or two. Using a CLP(FD) instead of "direct" arithmetic makes this considerably slower on SWI-Prolog. In particular, Y in 0..60, X #= Y * Y instead of the nth_integer_root_and_remainder/4 goal takes this up to about 0.027 seconds.
Given that the question seems to have shifted from using DCGs to solving the puzzle, I thought I might post a more efficient approach. I am using clp(fd) on SICStus, but I included a modified version that should work with clpz on Scryer (replacing table/2 with my_simple_table/2).
:- use_module(library(clpfd)).
:- use_module(library(lists)).
move(X,Y):-
(
X+5#=Y
;
X+7#=Y
;
X#=Y*Y
).
move_table(Table):-
findall([X,Y],(
X in 0..60,
Y in 0..60,
move(X,Y),
labeling([], [X,Y])
),Table).
% Naive version
%%post_move(X,Y):- move(X,Y).
%%
% SICSTUS clp(fd)
%%post_move(X,Y):-
%% move_table(Table),
%% table([[X,Y]],Table).
%%
% clpz is mising table/2
post_move(X,Y):-
move_table(Table),
my_simple_table([[X,Y]],Table).
my_simple_table([[X,Y]],Table):-
transpose(Table, [ListX,ListY]),
element(N, ListX, X),
element(N, ListY, Y).
post_moves([_]):-!.
post_moves([X,Y|Xs]):-
post_move(X,Y),
post_moves([Y|Xs]).
state(N,Xs):-
length(Xs,N),
domain(Xs, 0, 60),
all_different(Xs),
post_moves(Xs),
% ordering: 0 is first, 2 comes before 10, and 14 is last.
Xs=[0|_],
element(I2, Xs, 2),
element(I10, Xs, 10),
I2#<I10,
last(Xs, 14).
try_solve(N,Xs):-
state(N, Xs),
labeling([ffc], Xs).
try_solve(N,Xs):-
N1 is N+1,
try_solve(N1,Xs).
solve(Xs):-
try_solve(1,Xs).
Two notes of interest:
It is much more efficient to create a table of the possible moves and use the table/2 constraint rather than posting a disjunction of constraints. Note that we are recreating the table every time we post it, but we might as well create it once and pass it along.
This is using the element/3 constraint to find and constraint the position of the numbers of interest (in this case just 2 and 10, because we can fix 14 to be last). Again, this is more efficient than checking the order as filtering after solving the constraint problem.
Edit:
Here is an updated version to conform to the bounty constraints (predicate names, -hopefully- SWI-compatible, create the table only once):
:- use_module(library(clpfd)).
:- use_module(library(lists)).
generate_move_table(Table):-
X in 0..60,
Y in 0..60,
( X+5#=Y
#\/ X+7#=Y
#\/ X#=Y*Y
),
findall([X,Y],labeling([], [X,Y]),Table).
%post_move(X,Y,Table):- table([[X,Y]],Table). %SICStus
post_move(X,Y,Table):- tuples_in([[X,Y]],Table). %swi-prolog
%post_move(X,Y,Table):- my_simple_table([[X,Y]],Table). %scryer
my_simple_table([[X,Y]],Table):- % Only used as a fall back for Scryer prolog
transpose(Table, [ListX,ListY]),
element(N, ListX, X),
element(N, ListY, Y).
post_moves([_],_):-!.
post_moves([X,Y|Xs],Table):-
post_move(X,Y,Table),
post_moves([Y|Xs],Table).
puzzle_(Xs):-
generate_move_table(Table),
N in 4..61,
indomain(N),
length(Xs,N),
%domain(Xs, 0, 60), %SICStus
Xs ins 0..60, %swi-prolog, scryer
all_different(Xs),
post_moves(Xs,Table),
% ordering: 0 is first, 2 comes before 10, 14 is last.
Xs=[0|_],
element(I2, Xs, 2),
element(I10, Xs, 10),
I2#<I10,
last(Xs, 14).
label_puzzle(Xs):-
labeling([ffc], Xs).
solve(Xs):-
puzzle_(Xs),
label_puzzle(Xs).
I do not have SWI-prolog installed so I can't test the efficiency requirement (or that it actually runs at all) but on my machine and with SICStus, the new version of the solve/1 predicate takes 16 to 31 ms, while the puzzle/1 predicate in Isabelle's answer (https://stackoverflow.com/a/65513470/12100620) takes 78 to 94 ms.
As for elegance, I guess this is in the eye of the beholder. I like this formulation, it is relatively clear and is showcasing some very versatile constraints (element/3, table/2, all_different/1), but one drawback of it is that in the problem description the size of the sequence (and hence the number of FD variables) is not fixed, so we need to generate all sizes until one matches. Interestingly, it appears that all the solutions have the very same length and that the first solution of puzzle_/1 produces a list of the right length.
An alternative that uses dcg only to build the list. The 2,10,14 constraint is checked after building the list, so this is not optimal.
num(X) :- between(0, 60, X).
isqrt(X, Y) :- nth_integer_root_and_remainder(2, X, Y, 0). %SWI-Prolog
% list that ends with an element.
list([0], 0) --> [0].
list(YX, X) --> list(YL, Y), [X], { append(YL, [X], YX), num(X), \+member(X, YL),
(isqrt(Y, X); plus(Y, 5, X); plus(Y, 7, X)) }.
soln(X) :-
list(X, _, _, _),
nth0(I2, X, 2), nth0(I10, X, 10), nth0(I14, X, 14),
I2 < I10, I10 < I14.
?- time(soln(X)).
% 539,187,719 inferences, 53.346 CPU in 53.565 seconds (100% CPU, 10107452 Lips)
X = [0, 5, 12, 17, 22, 29, 36, 6, 11, 16, 4, 2, 9, 3, 10, 15, 20, 25, 30, 35, 42, 49, 7, 14]
I tried a little magic set. The predicate path/2 does search a path without giving us a path. We can therefore use commutativity of +5 and +7, doing less search:
step1(X, Y) :- N is (60-X)//5, between(0, N, K), H is X+K*5,
M is (60-H)//7, between(0, M, J), Y is H+J*7.
step2(X, Y) :- nth_integer_root_and_remainder(2, X, Y, 0).
:- table path/2.
path(X, Y) :- step1(X, H), (Y = H; step2(H, J), path(J, Y)).
We then use path/2 as a magic set for path/4:
step(X, Y) :- Y is X+5, Y =< 60.
step(X, Y) :- Y is X+7, Y =< 60.
step(X, Y) :- nth_integer_root_and_remainder(2, X, Y, 0).
/* without magic set */
path0(X, L, X, L).
path0(X, L, Y, R) :- step(X, H), \+ member(H, L),
path0(H, [H|L], Y, R).
/* with magic set */
path(X, L, X, L).
path(X, L, Y, R) :- step(X, H), \+ member(H, L),
path(H, Y), path(H, [H|L], Y, R).
Here is a time comparison:
SWI-Prolog (threaded, 64 bits, version 8.3.16)
/* without magic set */
?- time((path0(0, [0], 2, H), path0(2, H, 10, J), path0(10, J, 14, L))),
reverse(L, R), write(R), nl.
% 13,068,776 inferences, 0.832 CPU in 0.839 seconds (99% CPU, 15715087 Lips)
[0,5,12,17,22,29,36,6,11,16,4,2,9,3,10,15,20,25,30,35,42,49,7,14]
/* with magic set */
?- abolish_all_tables.
true.
?- time((path(0, [0], 2, H), path(2, H, 10, J), path(10, J, 14, L))),
reverse(L, R), write(R), nl.
% 2,368,325 inferences, 0.150 CPU in 0.152 seconds (99% CPU, 15747365 Lips)
[0,5,12,17,22,29,36,6,11,16,4,2,9,3,10,15,20,25,30,35,42,49,7,14]
Noice!
I managed to solve it without DCG's, it takes about 50 minutes on my machine to solve for the length N=24. I suspect this is because the order check is done for every list from scratch.
:- use_module(library(lists)).
:- use_module(library(clpz)).
:- use_module(library(dcgs)).
:- use_module(library(time)).
%% integer sqrt
isqrt(X, Y) :- Y #>= 0, X #= Y*Y.
before(X, Y, Z, L) :-
%% L has a suffix [X|T], and T has a suffix of [Y|_].
append(_, [X|T], L),
append(_, [Y|TT], T),
append(_, [Z|_], TT).
order(L) :- before(2,10,14, L).
game([X],X).
game([H|T], H) :- ((X #= H+5); (X #= H+7); (isqrt(H, X))), X #\= H, H #=< 60, X #=< 60, game(T, X). % H -> X.
searchN(N, L) :- length(L, N), order(L), game(L, 0).
I know there are some topics already about this. But I still dont get it.
Could be somebody describe step by step how:
length1([],0).
length1([X|Xs],N) :-length1(Xs,M), N is M+1.
works? I put traces on but I still have no idea.
Thanks!
Let's walk through an example:
?- length1([a, b, c], N).
First Prolog tries to unify with the first rule, but [a, b, c] doesn't match []. So it tries to unify with the second rule, and we get:
length1([a|[b, c]], N) :-
length1([b, c], M), % We do this first
N is M + 1. % We can't solve this yet because we don't know what M is
So we've matched [a, b, c] to [a|[b,c]], which is part of the list syntax. We can't work out what N is yet, but we've got to do the middle line first, which unifies with the same rule:
length1([b|[c]], M) :-
length1([c], L),
M is L + 1.
As before, we need to do the middle line to work out what M is.
length1([c|[]], L) :-
length1([], K),
L is K + 1.
We still can't work it out, but now our middle line unifies with the first rule:
length1([], 0). % So now we know what K is!
We've unified K with 0, so now we can start going back up:
length1([c|[]], 1) :-
length1([], 0),
1 is 0 + 1. % L is K + 1
length1([b|[c]], 2) :-
length1([c], 1),
2 is 1 + 1. % M is L + 1
length1([a|[b, c]], 3) :-
length1([b, c], 2),
3 is 2 + 1. % N is M + 1
So we exit our recursion with N unified to 3:
?- length1([a, b, c], N).
N = 3.
List-processing predicates in Prolog are almost always going to have two clauses, because the list type is defined inductively as:
A list is either:
Empty: [], or
An item, plus a list: [X|Xs]
Inductive data structures often have predicates whose definitions break down into the same cases as the structure itself. In the case of length, the inductive definition looks like:
The length of a list is either:
0 for empty lists, or
1 + the length of the rest of the list
And that's exactly what you have here in the Prolog code:
length1([], 0).
says that the length of the empty list is zero. This is your base case. A better second clause would be:
length1([_|Xs], N1) :- length1(Xs, N), N1 is N+1
This says, supposing you have a list with some item (we don't care about what it is) and a tail of a list, the length of this list is N1, where N1 is 1 + the length of the tail of the list.
It works badly. Here is how it is supposed to work:
?- length([], N).
N = 0.
?- length([_,_], N).
N = 2.
?- length(L, 0).
L = [].
?- length(L, 2).
L = [_5494, _5500].
?- length(L, N).
L = [],
N = 0 ;
L = [_5524],
N = 1 ;
L = [_5524, _5530],
N = 2 .
?- L = [_|L], length(L, N).
ERROR: Type error: `list' expected, found `#(S_1,[S_1=[_6396|S_1]])' (a cyclic)
ERROR: In:
ERROR: [12] throw(error(type_error(list,...),context(...,_6460)))
ERROR: [9] <user>
ERROR:
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.
... and here is how the version from your question works:
?- length1([], N).
N = 0. % OK
?- length1([_,_], N).
N = 2. % OK
?- length1(L, 0).
L = [] ; % does not terminate!
^CAction (h for help) ? abort
% Execution Aborted
?- length1(L, 2).
L = [_9566, _9572] ; % does not terminate
^CAction (h for help) ? abort
% Execution Aborted
?- length1(L, N).
L = [],
N = 0 ;
L = [_9602],
N = 1 ;
L = [_9602, _9608],
N = 2 . % OK
?- L = [_|L], length1(L, N).
ERROR: Stack limit (1.0Gb) exceeded
ERROR: Stack sizes: local: 1.0Gb, global: 37Kb, trail: 1Kb
ERROR: Stack depth: 11,180,538, last-call: 0%, Choice points: 3
ERROR: Probable infinite recursion (cycle):
ERROR: [11,180,538] user:length1([cyclic list], _9792)
ERROR: [11,180,537] user:length1([cyclic list], _9818)
The last one looks the same, but the built-in length/2 throws a type error instead of exceeding the stack.
There is another problem with length1/2, it uses up the stack if the list is too long, because every recursive step must be left on the stack with the current definition.
?- length(L, 10 000 000). % make a long list, works
L = [_984, _990, _996, _1002, _1008, _1014, _1020, _1026, _1032|...].
?- length(L, 10 000 000), length(L, N). % how long is the long list?
L = [_1258, _1264, _1270, _1276, _1282, _1288, _1294, _1300, _1306|...],
N = 10000000.
?- length(L, 10 000 000), length1(L, N). % how long is the list? too long!
ERROR: Stack limit (1.0Gb) exceeded
ERROR: Stack sizes: local: 0.5Gb, global: 0.2Gb, trail: 1Kb
ERROR: Stack depth: 5,592,186, last-call: 0%, Choice points: 3
ERROR: Possible non-terminating recursion:
ERROR: [5,592,186] user:length1([length:4,407,825], _60000944)
ERROR: [5,592,185] user:length1([length:4,407,826], _60000970)
Moreover:
?- time( length(L, 1 000) ).
% 2 inferences, 0.000 CPU in 0.000 seconds (86% CPU, 46417 Lips)
L = [_886, _892, _898, _904, _910, _916, _922, _928, _934|...].
?- time( length(L, 10 000) ).
% 2 inferences, 0.001 CPU in 0.001 seconds (99% CPU, 3495 Lips)
L = [_888, _894, _900, _906, _912, _918, _924, _930, _936|...].
?- time( length1(L, 1 000) ).
% 501,499 inferences, 0.067 CPU in 0.067 seconds (100% CPU, 7511131 Lips)
L = [_878, _884, _890, _896, _902, _908, _914, _920, _926|...] .
?- time( length1(L, 10 000) ).
% 50,014,999 inferences, 4.938 CPU in 4.941 seconds (100% CPU, 10128365 Lips)
L = [_876, _882, _888, _894, _900, _906, _912, _918, _924|...] .
It takes too long to make bigger lists using length1/2 so this is why I am showing it with such a short list. But you might notice that a list 10 times longer makes your length1/2 run 100 times longer. You should ask whoever showed you this code what that means.
Why am I writing this? Not sure. I think it is irresponsible to show students shitty code. On the other hand, this is a popular question (in the sense that many people before you have asked the exact same thing).
That's a very frequently asked question but i'd like to pose it in relation with two examples that seem very similar in my eyes, and are yet the one correct and the other not.
Correct example:
k_th_element(X,[X|_],1).
k_th_element(X,[_|L],K):- K>1,K1 is (K-1),k_th_element(X,L,K1).
Wrong Example
length2(1,[_]).
length2(X,[_|Ys]) :- X>1, X1 is (X-1), length(X1,Ys).
Why prolog complains or doesn't for each case?
Update: I think i got it. What i couldn't understand was that it doesn't matter what the predicate is but how you are calling it. so this is correct:
k_th_element(X,[1,2,3,4,5],3) because you have a value for K which is the right variable of "is" operator. But at the same time k_th_element(3,[1,2,3,4,5],Y) will not work, because Y is a variable, our "goal" and we can't have that in the right part of "is" operator. Correct me if i'm wrong.
as mat proposed, there is a more flexible way to achieve the same:
:- use_module(library(clpfd)).
length2(0,[]).
length2(X,[_|Ys]) :- X#>0, X1#=X-1, length2(X1,Ys).
First, there is the argument order. For length/2 it is rather length(List, Length).
For the case of a given list and an unknown length, your version is relatively inefficient because of all the X1 #= X-1 constraints which implies about N constrained variables. The version length3/2 has a single constrained variable. (It is about 7 times faster. I am still surprised that it is not faster than it is, maybe someone can help with another answer?)
:- use_module(library(clpfd)).
length2([], 0).
length2([_E|Es], N0) :-
N0 #> 0,
N1 #= N0-1,
length2(Es, N1).
length3(Es, N) :-
length3(Es, 0, N).
length3([], N,N).
length3([_E|Es], N0,N) :-
N1 is N0+1,
N #>= N1,
length3(Es, N1,N).
?- length(L,1000), time(length2(L,N)).
% 783,606 inferences, 0.336 CPU in 0.347 seconds (97% CPU, 2332281 Lips)
L = [_A, _B, _C, _D, _E, _F, _G, _H, _I|...], N = 1000.
?- length(L,1000), time(length3(L,N)).
% 127,006 inferences, 0.047 CPU in 0.058 seconds (81% CPU, 2719603 Lips)
L = [_A, _B, _C, _D, _E, _F, _G, _H, _I|...], N = 1000.
Using reflection predicates one can build the following variant of list_length/2:
:- use_module(library(clpfd)).
list_length(Es, N) :-
( fd_sup(N, Ub), integer(Ub)
-> ( length(Es, M),
( M >= Ub
-> !,
M == Ub
; true
),
M = N
)
; length(Es, N)
).
The above implementation combines two nice properties:
It works well with clpfd.
In particular, list_length(Xs,N) terminates universally whenever N has a finite upper bound.
Using SWI-Prolog 8.0.0:
?- N in 1..3, list_length(Xs, N).
N = 1, Xs = [_A]
; N = 2, Xs = [_A,_B]
; N = 3, Xs = [_A,_B,_C]. % terminates universally
It minimizes auxiliary computation (and thus runtime) by using the builtin predicate length/2.
Let's compare the runtime of list_length/2 with length3/2—presented in this earlier answer!
Using SWI-Prolog 8.0.0 with command-line option -O:
?- time(( N in 1..100000, list_length(_,N), false ; true )).
% 2,700,130 inferences, 0.561 CPU in 0.561 seconds (100% CPU, 4812660 Lips)
true.
?- time(( N in 1..100000, length3(_,N), false ; true )).
% 14,700,041 inferences, 3.948 CPU in 3.949 seconds (100% CPU, 3723234 Lips)
true.
Note that the above also works with SICStus Prolog: SWI's fd_sup/2 is called fd_max/2 in SICStus.
in short: How to find min value in a list? (thanks for the advise kaarel)
long story:
I have created a weighted graph in amzi prolog and given 2 nodes, I am able to retrieve a list of paths. However, I need to find the minimum value in this path but am unable to traverse the list to do this. May I please seek your advise on how to determine the minimum value in the list?
my code currently looks like this:
arc(1,2).
arc(2,3).
arc(3,4).
arc(3,5).
arc(3,6).
arc(2,5).
arc(5,6).
arc(2,6).
path(X,Z,A) :-
(arc(X,Y),path(Y,Z,A1),A is A1+1;arc(X,Z), A is 1).
thus, ' keying findall(Z,path(2,6,Z),L).' in listener allows me to attain a list [3,2,2,1].
I need to retrieve the minimum value from here and multiply it with an amount. Can someone please advise on how to retrieve the minimum value? thanks!
It is common to use a so-called "lagged argument" to benefit from first-argument indexing:
list_min([L|Ls], Min) :-
list_min(Ls, L, Min).
list_min([], Min, Min).
list_min([L|Ls], Min0, Min) :-
Min1 is min(L, Min0),
list_min(Ls, Min1, Min).
This pattern is called a fold (from the left), and foldl/4, which is available in recent SWI versions, lets you write this as:
list_min([L|Ls], Min) :- foldl(num_num_min, Ls, L, Min).
num_num_min(X, Y, Min) :- Min is min(X, Y).
Notice though that this cannot be used in all directions, for example:
?- list_min([A,B], 5).
is/2: Arguments are not sufficiently instantiated
If you are reasoning about integers, as seems to be the case in your example, I therefore recommend you use CLP(FD) constraints to naturally generalize the predicate. Instead of (is)/2, simply use (#=)/2 and benefit from a more declarative solution:
:- use_module(library(clpfd)).
list_min([L|Ls], Min) :- foldl(num_num_min, Ls, L, Min).
num_num_min(X, Y, Min) :- Min #= min(X, Y).
This can be used as a true relation which works in all directions, for example:
?- list_min([A,B], 5).
yielding:
A in 5..sup,
5#=min(B, A),
B in 5..sup.
This looks right to me (from here).
min_in_list([Min],Min). % We've found the minimum
min_in_list([H,K|T],M) :-
H =< K, % H is less than or equal to K
min_in_list([H|T],M). % so use H
min_in_list([H,K|T],M) :-
H > K, % H is greater than K
min_in_list([K|T],M). % so use K
%Usage: minl(List, Minimum).
minl([Only], Only).
minl([Head|Tail], Minimum) :-
minl(Tail, TailMin),
Minimum is min(Head, TailMin).
The second rule does the recursion, in english "get the smallest value in the tail, and set Minimum to the smaller of that and the head". The first rule is the base case, "the minimum value of a list of one, is the only value in the list".
Test:
| ?- minl([2,4,1],1).
true ?
yes
| ?- minl([2,4,1],X).
X = 1 ?
yes
You can use it to check a value in the first case, or you can have prolog compute the value in the second case.
This program may be slow, but I like to write obviously correct code when I can.
smallest(List,Min) :-
sort(List,[Min|_]).
SWI-Prolog offers library(aggregate). Generalized and performance wise.
:- [library(aggregate)].
min(L, M) :- aggregate(min(E), member(E, L), M).
edit
A recent addition was library(solution_sequences). Now we can write
min(L,M) :- order_by([asc(M)], member(M,L)), !.
max(L,M) :- order_by([desc(M)], member(M,L)), !.
Now, ready for a surprise :) ?
?- test_performance([clpfd_max,slow_max,member_max,rel_max,agg_max]).
clpfd_max:99999996
% 1,500,000 inferences, 0.607 CPU in 0.607 seconds (100% CPU, 2470519 Lips)
slow_max:99999996
% 9,500,376 inferences, 2.564 CPU in 2.564 seconds (100% CPU, 3705655 Lips)
member_max:99999996
% 1,500,009 inferences, 1.004 CPU in 1.004 seconds (100% CPU, 1494329 Lips)
rel_max:99999996
% 1,000,054 inferences, 2.649 CPU in 2.648 seconds (100% CPU, 377588 Lips)
agg_max:99999996
% 2,500,028 inferences, 1.461 CPU in 1.462 seconds (100% CPU, 1710732 Lips)
true
with these definitions:
```erlang
:- use_module(library(clpfd)).
clpfd_max([L|Ls], Max) :- foldl([X,Y,M]>>(M #= max(X, Y)), Ls, L, Max).
slow_max(L, Max) :-
select(Max, L, Rest), \+ (member(E, Rest), E #> Max).
member_max([H|T],M) :-
member_max(T,N), ( \+ H#<N -> M=H ; M=N ).
member_max([M],M).
rel_max(L,M) :-
order_by([desc(M)], member(M,L)), !.
agg_max(L,M) :-
aggregate(max(E), member(E,L), M).
test_performance(Ps) :-
test_performance(Ps,500 000,_).
test_performance(Ps,N_Ints,Result) :-
list_of_random(N_Ints,1,100 000 000,Seq),
maplist({Seq}/[P,N]>>time((call(P,Seq,N),write(P:N))),Ps,Ns),
assertion(sort(Ns,[Result])).
list_of_random(N_Ints,L,U,RandomInts) :-
length(RandomInts,N_Ints),
maplist({L,U}/[Int]>>random_between(L,U,Int),RandomInts).
clpfd_max wins hands down, and to my surprise, slow_max/2 turns out to be not too bad...
SWI-Prolog has min_list/2:
min_list(+List, -Min)
True if Min is the smallest number in List.
Its definition is in library/lists.pl
min_list([H|T], Min) :-
min_list(T, H, Min).
min_list([], Min, Min).
min_list([H|T], Min0, Min) :-
Min1 is min(H, Min0),
min_list(T, Min1, Min).
This is ok for me :
minimumList([X], X). %(The minimum is the only element in the list)
minimumList([X|Q], M) :- % We 'cut' our list to have one element, and the rest in Q
minimumList(Q, M1), % We call our predicate again with the smallest list Q, the minimum will be in M1
M is min(M1, X). % We check if our first element X is smaller than M1 as we unstack our calls
Similar to andersoj, but using a cut instead of double comparison:
min([X], X).
min([X, Y | R], Min) :-
X < Y, !,
min([X | R], Min).
min([X, Y | R], Min) :-
min([Y | R], Min).
Solution without "is".
min([],X,X).
min([H|T],M,X) :- H =< M, min(T,H,X).
min([H|T],M,X) :- M < H, min(T,M,X).
min([H|T],X) :- min(T,H,X).
thanks for the replies. been useful. I also experimented furthur and developed this answer:
% if list has only 1 element, it is the smallest. also, this is base case.
min_list([X],X).
min_list([H|List],X) :-
min_list(List,X1), (H =< X1,X is H; H > X1, X is X1).
% recursively call min_list with list and value,
% if H is less than X1, X1 is H, else it is the same.
Not sure how to gauge how good of an answer this is algorithmically yet, but it works! would appreciate any feedback nonetheless. thanks!
min([Second_Last, Last], Result):-
Second_Last < Last
-> Result = Second_Last
; Result = Last, !.
min([First, Second|Rest], Result):-
First < Second
-> min([First|Rest], Result)
; min([Second|Rest], Result).
Should be working.
This works and seems reasonably efficient.
min_in_list([M],M).
min_in_list([H|T],X) :-
min_in_list(T,M),
(H < M, X = H; X = M).
min_list(X,Y) :- min_in_list(X,Y), !.
smallest(List,X):-
sort(List,[X|_]).
% find minimum in a list
min([Y],Y):-!.
min([H|L],H):-min(L,Z),H=<Z.
min([H|L],Z):-min(L,Z),H>=Z.
% so whattaya think!