Prolog Recursion and Variables - sorting

I have this insertion sort to sort a list in descending order in Prolog and it works:
insert(X,[],[X]).
insert(X, [Y|Tail], [X,Y|Tail]):- X > Y, !.
insert(X, [Y|Tail], [Y|NTail]):- insert(X, Tail, NTail).
ins_sort([], []).
ins_sort([X|Tail], Sorted):- ins_sort(Tail, STail), insert(X, STail, Sorted).
I am running it on SWISH and trying to understand how it functions with the following trace:
Call:ins_sort([1, 2, 3, 4, 5], _12162)
Call:ins_sort([2, 3, 4, 5], _12358)
Call:ins_sort([3, 4, 5], _12358)
Call:ins_sort([4, 5], _12358)
Call:ins_sort([5], _12358)
Call:ins_sort([], _12358)
Exit:ins_sort([], [])
Call:insert(5, [], _12360)
Exit:insert(5, [], [5])
Exit:ins_sort([5], [5])
Call:insert(4, [5], _12366)
Call:4>5
Fail:4>5
Redo:insert(4, [5], _12370)
Call:insert(4, [], _12282)
Exit:insert(4, [], [4])
Exit:insert(4, [5], [5, 4])
Exit:ins_sort([4, 5], [5, 4])
Call:insert(3, [5, 4], _12378)
Call:3>5
Fail:3>5
Redo:insert(3, [5, 4], _12382)
Call:insert(3, [4], _12294)
Call:3>4
Fail:3>4
Redo:insert(3, [4], _12294)
Call:insert(3, [], _12300)
Exit:insert(3, [], [3])
Exit:insert(3, [4], [4, 3])
Exit:insert(3, [5, 4], [5, 4, 3])
Exit:ins_sort([3, 4, 5], [5, 4, 3])
Call:insert(2, [5, 4, 3], _12396)
Call:2>5
Fail:2>5
Redo:insert(2, [5, 4, 3], _12400)
Call:insert(2, [4, 3], _12312)
Call:2>4
Fail:2>4
Redo:insert(2, [4, 3], _12312)
Call:insert(2, [3], _12318)
Call:2>3
Fail:2>3
Redo:insert(2, [3], _12318)
Call:insert(2, [], _12324)
Exit:insert(2, [], [2])
Exit:insert(2, [3], [3, 2])
Exit:insert(2, [4, 3], [4, 3, 2])
Exit:insert(2, [5, 4, 3], [5, 4, 3, 2])
Exit:ins_sort([2, 3, 4, 5], [5, 4, 3, 2])
Call:insert(1, [5, 4, 3, 2], _12162)
Call:1>5
Fail:1>5
Redo:insert(1, [5, 4, 3, 2], _12162)
Call:insert(1, [4, 3, 2], _12336)
Call:1>4
Fail:1>4
Redo:insert(1, [4, 3, 2], _12336)
Call:insert(1, [3, 2], _12342)
Call:1>3
Fail:1>3
Redo:insert(1, [3, 2], _12342)
Call:insert(1, [2], _12348)
Call:1>2
Fail:1>2
Redo:insert(1, [2], _12348)
Call:insert(1, [], _12354)
Exit:insert(1, [], [1])
Exit:insert(1, [2], [2, 1])
Exit:insert(1, [3, 2], [3, 2, 1])
Exit:insert(1, [4, 3, 2], [4, 3, 2, 1])
Exit:insert(1, [5, 4, 3, 2], [5, 4, 3, 2, 1])
Exit:ins_sort([1, 2, 3, 4, 5], [5, 4, 3, 2, 1])
I get lost once I get beyond the first "Exit". I understand all of the recursive calls until we get to an empty list, which stops the recursive calls because of the other fact and begins going back, but why after the first exit on line 7 does the undefined STail become an empty list [] in the insert call?
Has the exit of ins_sort([], []) set STail to an empty set [] and does this mean that the last argument of a fact is a return value or something?

Traces are much too hard. Re-writing is usually much easier, especially with the deterministic predicates like you have here. Long variable names are also too distracting. Instead of reading and remembering, it just might be easier simply seeing:
insert(X, [], [X]). %1
insert(X, [Y|T], [X,Y|T] ):- X > Y, !. % X was indeed greater than Y: %2
% accept the solution and stop; %3
insert(X, [Y|T], [ Y|NT]):- insert(X, T, NT). % otherwise, insert into tail. %4
%5
ins_sort( [], []). % rule {1} %6
ins_sort( [X|T], S):- % rule {2} %7
ins_sort( T, ST), %8
insert( X, ST, %9
S). %10
Let's try it with a shorter list,
ins_sort([1, 2, 3], S) ? S. %11
= \ / %12
{2: [X1|T1]=[1,2,3] } / %13
ins_sort(T1, ST1), insert(X1, ST1, S). %14
= \ / %15
{2: [X2|T2]=T1=[2,3] } / %16
ins_sort(T2, ST2), insert(X2, ST2, ST1). %17
= \ / %18
{2: [X3|T3]=T2=[3] } / %19
ins_sort(T3, ST3), insert(X3, ST3, ST2). %20
= \ / %21
{1: T3=[] ST3=[] }. %22
and we go by the V-shaped trace from the top left corner down to the middle, winding up the recursion until we reach the base case, and then up and to the right while unwinding the recursion and building the result on our way back from the base case, as usual. Thus we proceed to establish, from the bottom up,
ST3 = []. %22
insert( {X3=3}, {ST3=[]}, ST2 ):- ST2 = [3]. %20
insert( {X2=2}, {ST2=[3]}, ST1 ):- ST1 = [3,2]. %17
insert( {X1=1}, {ST1=[3,2]}, S ):- S = [3,2,1]. %14
And that's that.

I think the problem here is you are having some difficulty understanding what happens with variables during recursion. Let's take a simplified case:
count([], 0).
count([X|Xs], N) :- count(Xs, N0), succ(N0, N).
What happens when I call count([a,b], N) is this:
count([a, b], N)
+-> count([b], N)
The first thing we have to do upon entering count([a,b], N) is a recursive call to count/2. When Prolog re-enters count, we suddenly have a new set of bindings for X and Xs. In the outer call, X=a and Xs=[b], but in the inner call, X=b and Xs=[]. There will then be a third inner call, which begins with the Xs value []. This corresponds to the first three lines of this trace:
Call: (8) count([a, b], _8636) ? creep
Call: (9) count([b], _8866) ? creep
Call: (10) count([], _8866) ? creep
What the tracer is telling you here is "I am trying to enter this predicate with these values and variables." Note that the variable actually changed for N between the first and second calls.
Now, you'll notice that the [] cannot match the second clause, only the first. The first doesn't have a body but it does establish a binding. So the next line of the trace will reflect that:
Exit: (10) count([], 0) ? creep
See the numbers on the side? That's telling you the depth of the call stack. It's convenient to use numbers for traces instead of showing the nesting visually because eventually our call stacks are going to get pretty deep!
Now that we have a value for the variable, it's going to move on to the next expression in the clause we're in:
Call: (10) succ(0, _8866) ? creep
Exit: (10) succ(0, 1) ? creep
Nesting level went up one but was immediately resolved; this is par for the course with built-ins like succ/2. Now let's look at the rest of the trace:
Exit: (9) count([b], 1) ? creep
Call: (9) succ(1, _8636) ? creep
Exit: (9) succ(1, 2) ? creep
Exit: (8) count([a, b], 2) ? creep
So now that we had a binding for the recursive call, we can enter the next step in the parent call, and so on, until the whole call is resolved and we get 2.
Let's see it again, this time with nesting instead of numbers:
[trace] ?- count([a,b],N).
Call: (8) count([a, b], _8636) ? creep
Call: (9) count([b], _8866) ? creep
Call: (10) count([], _8866) ? creep
Exit: (10) count([], 0) ? creep
Call: (10) succ(0, _8866) ? creep
Exit: (10) succ(0, 1) ? creep
Exit: (9) count([b], 1) ? creep
Call: (9) succ(1, _8636) ? creep
Exit: (9) succ(1, 2) ? creep
Exit: (8) count([a, b], 2) ? creep
N = 2.
This should make what's going on in your own trace a little easier to understand.

Prolog works with unification and pattern matching.You are removing the Head and calling the predicate again with tail which keeps removing Head and tries to find matches after each call and at some later time you have an empty list so prolog search your file for a match and at this point it finds a match ins_sort([], []).
At 6th call you have Call:ins_sort([], _12358) where _12358 is a variable and this variable will get the value from ns_sort([], []). which is a fact. It simply means that if you have one empty list in ns_sort and one variable then set that variable also equals to the empty list, variable gets instantiated with anything if you have all other "terms" matching.
Prolog can be easily understood by learning Backtracking and backtracking is an algorithm so prolog self is an algorithm.

Related

Enumerate multi set of all elements from given list which sums up to given number

Given a number N and a list, I want to enumerate all ways to select numbers from the list so that their sum equals N. I can use numbers from the list multiple times. I thought of logic roughly corresponding to following tree:
I came up with following code:
append([], Y, [Y]). %append[] and Y to get Y.
append([H|X], Y, [H|Z]) :- append(X, Y, Z). % append [H|X] and Y to get [H|Z] if appending X and Y gives Z
ss(0, [], Ans).
ss(N, L, Ans) :-
ss1(N, 0, L, [], Ans).
ss1(N, N1, [], L2, Ans) :-
N == N1,
Ans = L2.
ss1(N, N1, L, L1, Ans) :-
N == N1,
Ans = L2.
ss1(N, N1, L, L1, Ans) :-
[A | B] = L,
N2 is (A+N1),
append(L1, A, L2),
N >= N2,
ss1(N, N2, L, L2, Ans).
ss1(N, N1, L, L1, Ans) :-
[A, B | C] = L,
N2 is (B+N1),
append(L1, B, L2),
N >= N2,
ss1(N, N2, L, L2, Ans).
Running it gives following:
?- ss(20, [5, 8, 13, 10, 2], Ans).
Call: (10) cc(20, [5, 8, 13, 10, 2], _3530) ? creep
Call: (11) cc1(20, 0, [5, 8, 13, 10, 2], [], _3530) ? creep
Call: (12) 20==0 ? creep
Fail: (12) 20==0 ? creep
Redo: (11) cc1(20, 0, [5, 8, 13, 10, 2], [], _3530) ? creep
Call: (12) [5, 8, 13, 10, 2]=[_4130|_4132] ? creep
Exit: (12) [5, 8, 13, 10, 2]=[5, 8, 13, 10, 2] ? creep
Call: (12) _4282 is 5+0 ? creep
Exit: (12) 5 is 5+0 ? creep
Call: (12) append([], 5, _4374) ? creep
Exit: (12) append([], 5, [5]) ? creep
Call: (12) 20>=5 ? creep
Exit: (12) 20>=5 ? creep
Call: (12) cc1(20, 5, [5, 8, 13, 10, 2], [5], _3530) ? creep
Call: (13) 20==5 ? creep
Fail: (13) 20==5 ? creep
Redo: (12) cc1(20, 5, [5, 8, 13, 10, 2], [5], _3530) ? creep
Call: (13) [5, 8, 13, 10, 2]=[_4676|_4678] ? creep
Exit: (13) [5, 8, 13, 10, 2]=[5, 8, 13, 10, 2] ? creep
Call: (13) _4828 is 5+5 ? creep
Exit: (13) 10 is 5+5 ? creep
Call: (13) append([5], 5, _4920) ? creep
Call: (14) append([], 5, _4910) ? creep
Exit: (14) append([], 5, [5]) ? creep
Exit: (13) append([5], 5, [5, 5]) ? creep
Call: (13) 20>=10 ? creep
Exit: (13) 20>=10 ? creep
Call: (13) cc1(20, 10, [5, 8, 13, 10, 2], [5, 5], _3530) ? creep
Call: (14) 20==10 ? creep
Fail: (14) 20==10 ? creep
Redo: (13) cc1(20, 10, [5, 8, 13, 10, 2], [5, 5], _3530) ? creep
Call: (14) [5, 8, 13, 10, 2]=[_5316|_5318] ? creep
Exit: (14) [5, 8, 13, 10, 2]=[5, 8, 13, 10, 2] ? creep
Call: (14) _5468 is 5+10 ? creep
Exit: (14) 15 is 5+10 ? creep
Call: (14) append([5, 5], 5, _5560) ? creep
Call: (15) append([5], 5, _5550) ? creep
Call: (16) append([], 5, _5600) ? creep
Exit: (16) append([], 5, [5]) ? creep
Exit: (15) append([5], 5, [5, 5]) ? creep
Exit: (14) append([5, 5], 5, [5, 5, 5]) ? creep
Call: (14) 20>=15 ? creep
Exit: (14) 20>=15 ? creep
Call: (14) cc1(20, 15, [5, 8, 13, 10, 2], [5, 5, 5], _3530) ? creep
Call: (15) 20==15 ? creep
Fail: (15) 20==15 ? creep
Redo: (14) cc1(20, 15, [5, 8, 13, 10, 2], [5, 5, 5], _3530) ? creep
Call: (15) [5, 8, 13, 10, 2]=[_6050|_6052] ? creep
Exit: (15) [5, 8, 13, 10, 2]=[5, 8, 13, 10, 2] ? creep
Call: (15) _6202 is 5+15 ? creep
Exit: (15) 20 is 5+15 ? creep
Call: (15) append([5, 5, 5], 5, _6294) ? creep
Call: (16) append([5, 5], 5, _6284) ? creep
Call: (17) append([5], 5, _6334) ? creep
Call: (18) append([], 5, _6384) ? creep
Exit: (18) append([], 5, [5]) ? creep
Exit: (17) append([5], 5, [5, 5]) ? creep
Exit: (16) append([5, 5], 5, [5, 5, 5]) ? creep
Exit: (15) append([5, 5, 5], 5, [5, 5, 5, 5]) ? creep
Call: (15) 20>=20 ? creep
Exit: (15) 20>=20 ? creep
Call: (15) cc1(20, 20, [5, 8, 13, 10, 2], [5, 5, 5, 5], _3530) ? creep
Call: (16) 20==20 ? creep
Exit: (16) 20==20 ? creep
Call: (16) true ? creep
Exit: (16) true ? creep
Exit: (15) cc1(20, 20, [5, 8, 13, 10, 2], [5, 5, 5, 5], _3530) ? creep
Exit: (14) cc1(20, 15, [5, 8, 13, 10, 2], [5, 5, 5], _3530) ? creep
Exit: (13) cc1(20, 10, [5, 8, 13, 10, 2], [5, 5], _3530) ? creep
Exit: (12) cc1(20, 5, [5, 8, 13, 10, 2], [5], _3530) ? creep
Exit: (11) cc1(20, 0, [5, 8, 13, 10, 2], [], _3530) ? creep
Exit: (10) cc(20, [5, 8, 13, 10, 2], _3530) ? creep
true .
As you can see, it forms the list [5,5,5,5] which sums to 20. But instead of returning it, it returns true, despite we equate it with Ans. It also need to return sets: [5,5,10],[10,10],[2,2,2,2,2,10],[2,8,10],[2,2,2,2,2,2,8],[2,2,8,8].
Why so? Also is there any simpler logic possible?
(ref for append())
phew, there is a lot to say, so let's start:
your definition of append/3 is pretty unorthodox and in some systems, you are not allowed to redefine append/3, which is in-built (and differs from your definition), so let's change that to append2/3 for now:
append2([], Y, [Y]).
append2([H|X], Y, [H|Z]) :- append2(X, Y, Z).
You don't need ss(0, [], Ans), so let's skip this.
We keep:
ss(N, L, Ans) :-
ss1(N, 0, L, [], Ans).
Let's have a look at the next two clauses, your base clauses for ss1:
ss1(N, N1, [], L2, Ans) :-
N == N1,
Ans = L2.
ss1(N, N1, L, L1, Ans) :-
N == N1,
Ans = L2.
In the second clause - where is the prolog system supposed to take L2 from? Also, we do not need two clauses to express what your aiming at, one suffices:
ss1(N, N, _, L1, L1).
We leave the next two clauses for a second (only having renamed append/3):
ss1(N, N1, L, L1, Ans) :-
[A | B] = L,
N2 is (A+N1),
append2(L1, A, L2),
N >= N2,
ss1(N, N2, L, L2, Ans).
ss1(N, N1, L, L1, Ans) :-
[A, B | C] = L,
N2 is (B+N1),
append2(L1, B, L2),
N >= N2,
ss1(N, N2, L, L2, Ans).
So, we now have the program
append2([], Y, [Y]).
append2([H|X], Y, [H|Z]) :- append2(X, Y, Z).
ss(N, L, Ans) :- ss1(N, 0, L, [], Ans).
ss1(N, N, _, L1, L1). % clause 1 for ss1
ss1(N, N1, L, L1, Ans) :- % clause 2 for ss1
[A | B] = L,
N2 is (A+N1),
append2(L1, A, L2),
N >= N2,
ss1(N, N2, L, L2, Ans).
ss1(N, N1, L, L1, Ans) :- %clause 3 for ss1
[A, B | C] = L,
N2 is (B+N1),
append2(L1, B, L2),
N >= N2,
ss1(N, N2, L, L2, Ans).
Now, we get:
?- ss(20, [5, 8, 13, 10, 2], Ans).
Ans = [5, 5, 5, 5] ;
We also get:
?- ss(0, [5, 8, 13, 10, 2], Ans).
Ans = [] ;
We even get:
?- ss(4,[1,2],Ans).
Ans = [1, 1, 1, 1] ;
Ans = [1, 1, 2] ;
Ans = [1, 2, 1] ;
Ans = [2, 1, 1] ;
Ans = [2, 2] ;
So, that's way progress. But the problem is, that in clauses 2 and 3 for ss1/5, we only look at the first elements of the list to pick from, so we still have to solve this ;-)
One solution is to replace clauses 2 and 3 for ss1/5 by one single clause:
ss1(N, N1, L, L1, Ans) :-
member(A,L),
N2 is (A+N1),
append2(L1, A, L2),
N >= N2,
ss1(N, N2, L, L2, Ans).
member/2 is built-in in many prolog systems, if it is not in yours, it is easy to define.
Now, we still have a problem if 0 is not the last member of the list - then we get into an endless loop, for example
?- ss(1, [0,1],Ans).
?- ss(2, [3,0,1],Ans).
Let's therefore ignore 0s and only enumerate sums of integers >0.
From your comments, I also get that you want to enumerate each multiset only once. Here's a solution:
ss(N, L, Ans) :-
sort(L,S),
reverse(S,R),
ss1(N, 0, R, [], Ans).
ss1(N, N, _, L, L) :- !.
ss1(N, N1, [H|T], L1, Ans) :-
H > 0,
N2 is H+N1,
N>=N2,
ss1(N, N2, [H|T], [H|L1], Ans).
ss1(N, N1, [_|T], L1, Ans) :-
ss1(N, N1, T, L1, Ans).
If you want to allow 0s or negative integers in the list, please indicate in your comments - then this needs to be fixed.
To your inital question, we now get:
?- ss(20, [5, 8, 13, 10, 2], Ans).
Ans = [2, 5, 13] ;
Ans = [10, 10] ;
Ans = [2, 8, 10] ;
Ans = [5, 5, 10] ;
Ans = [2, 2, 2, 2, 2, 10] ;
Ans = [2, 2, 8, 8] ;
Ans = [2, 5, 5, 8] ;
Ans = [2, 2, 2, 2, 2, 2, 8] ;
Ans = [5, 5, 5, 5] ;
Ans = [2, 2, 2, 2, 2, 5, 5] ;
Ans = [2, 2, 2, 2, 2, 2, 2, 2, 2|...] ;
false.
Since the last answer is too long to be shown this way, we can also ask:
?- ss(20, [5, 8, 13, 10, 2], Ans), write(Ans), nl,fail.
[2,5,13]
[10,10]
[2,8,10]
[5,5,10]
[2,2,2,2,2,10]
[2,2,8,8]
[2,5,5,8]
[2,2,2,2,2,2,8]
[5,5,5,5]
[2,2,2,2,2,5,5]
[2,2,2,2,2,2,2,2,2,2]
false.

Pathfinding recursion runs out of memory in Prolog

I wrote this prolog program to find all possible paths in a grid:
travel([X,Y],[X,Y1]) :- Y1 is Y+1.
travel([X,Y],[X,Y0]) :- Y0 is Y-1.
travel([X,Y],[X1,Y]) :- X1 is X+1.
move([X,Y],n,[X,Y1]) :- travel([X,Y],[X,Y1]).
move([X,Y],s,[X,Y0]) :- travel([X,Y],[X,Y0]).
move([X,Y],e,[X1,Y]) :- travel([X,Y],[X1,Y]).
safe([Xn,Yn],[Xg,Yg]) :-
Xg >= Xn,
Xn >= 0,
Yg >= Yn,
Yn >= 0. %next state should be whit-in grid
%% solve([X,Y],[TargetX,TargetY],[Xg,Yg],[FirstMove|OtherMoves])
solve([X,Y],[X,Y],_,[]).
solve([X,Y],[Xt,Yt],[Xg,Yg],[Fm|Om]) :-
move([X,Y],Fm,[Xn,Yn]),
safe([Xn,Yn],[Xg,Yg]),
solve([Xn,Yn],[Xt,Yt],[Xg,Yg],Om).
For solve, [X,Y] is the current position. So my ending state is when the current position equals to target position. However, when I run it, I got out of memory error. Any idea what I did wrong? Any help is appreciated!
?- solve([1,2],[4,2],[3,4],P).
ERROR: Stack limit (1.0Gb) exceeded
ERROR: Stack sizes: local: 0.5Gb, global: 0.4Gb, trail: 29.0Mb
ERROR: Stack depth: 951,746, last-call: 0%, Choice points: 1,903,475
ERROR: Possible non-terminating recursion:
ERROR: [951,746] user:solve([length:2], [length:2], [length:2], _114212638)
ERROR: [951,745] user:solve([length:2], [length:2], [length:2], [length:1|_114212704])
?- length(P,4),solve([1,2],[4,2],[3,4],P).
false.
?- length(P,5),solve([1,2],[4,2],[3,4],P).
false.
Your program is infinitely looping between north and south movements. Try removing the south clauses in move and travel and it will work.
To debug how this is happening try using trace and see a recursive calls to solve you can see what is going on.
Exit: (15) move([1, 3], n, [1, 4]) ?
Call: (15) safe([1, 4], [4, 4]) ? s
Exit: (15) safe([1, 4], [4, 4]) ?
Call: (15) solve([1, 4], [3, 4], [4, 4], _3490) ?
Call: (16) move([1, 4], _3804, [_3822, _3828]) ? s
Exit: (16) move([1, 4], n, [1, 5]) ?
Call: (16) safe([1, 5], [4, 4]) ? s
Fail: (16) safe([1, 5], [4, 4]) ?
Redo: (16) move([1, 4], _3804, [_3822, _3828]) ? s
Exit: (16) move([1, 4], s, [1, 3]) ?
Call: (16) safe([1, 3], [4, 4]) ? s
Exit: (16) safe([1, 3], [4, 4]) ?
Call: (16) solve([1, 3], [3, 4], [4, 4], _3806) ?
Call: (17) move([1, 3], _4326, [_4344, _4350]) ? s
Exit: (17) move([1, 3], n, [1, 4]) ?
Call: (17) safe([1, 4], [4, 4]) ? s
Exit: (17) safe([1, 4], [4, 4]) ?
Call: (17) solve([1, 4], [3, 4], [4, 4], _4328) ?
Call: (18) move([1, 4], _4642, [_4660, _4666]) ? s
Exit: (18) move([1, 4], n, [1, 5]) ?
Call: (18) safe([1, 5], [4, 4]) ? s
Fail: (18) safe([1, 5], [4, 4]) ?
Also you seem to be pattern matching variable names in move :- travel, which will also not work. move(P1, n, P2) will try north and south clauses not just the first one(try move([2, 2], s, X) and see that the first solution is north movement). This will work but with south clause you will have infinite recursion.
move([X,Y], n, [X,Y1]) :- Y1 is Y+1.
move([X,Y], s, [X,Y1]) :- Y1 is Y-1.
move([X,Y], e, [X1,Y]) :- X1 is X+1.

Backtracking issue SWI-Prolog

i have some issues with backtracking in SWI-Prolog
In my predicate i have 2 lists as an input and the result is a third one.
I take from L1 each element with nth0/3, then i use another predicate that i need, so i append to the third list the second and the element if other_pred is true.
I'm using fail to force backtracking with nth0, but obviously the mypred fails every time and i can't get the final list i want.
I have also tried to use nth0 with and index I, increasing it, but it also makes fail the predicate. Same problem if i check that I is lower than L1 length for each iteration.
mypred(L1, L2, Result) :-
nth0(_, L1, X),
other_pred(X, L2),
append(L2, [X], Result), fail.
Since you did not give code for other_pred/2 this will use member/2.
mypred([H1|T1], L2, [H1|R]) :-
member(H1,L2),
mypred(T1,L2,R).
mypred([H1|T1], L2, R) :-
\+ member(H1,L2),
mypred(T1,L2,R).
mypred([],_,[]).
Example runs:
?- mypred([1,3,5], [1,2,4,5], R).
R = [1, 5] ;
false.
?- mypred([], [1,2,4,5], R).
R = [].
?- mypred([1,3,5], [], R).
R = [].
?- mypred([1,3,5], [2,4,6], R).
R = [].
?- mypred([1,3,5], [1,3,5], R).
R = [1, 3, 5] ;
false.
While you can use nth0/3 using the list constructor |/2 is much better, see: Lists
In this code [H1|T1] and [H1|R] use the list constructor.
This code also uses recursion.
The recursive clauses are
mypred([H1|T1], L2, [H1|R]) :-
member(H1,L2),
mypred(T1,L2,R).
mypred([H1|T1], L2, R) :-
\+ member(H1,L2),
mypred(T1,L2,R).
because the predicate mypred/3 is called in the clause. Also because the call to mypred/3 is the last call in the clause this is tail-recursive.
The base case for the recursive predicate is
mypred([],_,[]).
How this works for
mypred([1,3,5], [1,2,5], R).
is that the list [1,3,5] for the first parameter is matched with the first predicate
mypred([H1|T1], L2, [H1|R]) :-
member(H1,L2),
mypred(T1,L2,R).
This succeeds with the following unification
H1 = 1
T1 = [3,5]
L2 = [1,2,5]
R = _
The next line in the clause is executed:
member(H1,L2)
This succeeds.
The last line in the clause is executed:
mypred(T1,L2,R)
This matches the first predicate
mypred([H1|T1], L2, [H1|R]) :-
member(H1,L2),
mypred(T1,L2,R).
This succeeds with the following unification
H1 = 3
T1 = [5]
L2 = [1,2,5]
R = _
The next line in the clause is executed:
member(H1,L2)
This fails and backtracks.
Since there is another clause for my_pred/3 it is tried.
mypred([H1|T1], L2, R) :-
\+ member(H1,L2),
mypred(T1,L2,R).
This succeeds with the following unification
H1 = 3
T1 = [5]
L2 = [1,2,5]
R = _
The next line in the clause is executed:
\+ member(H1,L2)
This succeeds.
This pattern of trying different clauses for the predicate continues. At this point this will skip the details until the use of the third clause is used.
When the list for the first parameters is [], the third clause is used,
mypred([],_,[]).
Now the backtracking can begin.
Since the only lines that can call the third clause are like
mypred(T1,L2,R).
in the first and second clauses, R is unified with [].
Now depending upon which of the clauses made that call the list in the third parameter will be constructed differently.
If the second clause was used the third parameter will be constructed using
mypred([H1|T1], L2, R)
So the list is just returned unchanged.
However if the first clause was used the third parameter will be constructed using
mypred([H1|T1], L2, [H1|R])
but this time the result of the third parameter will be the value H1 when the clause was executed combined with the value of R. So if H1 is 5 and R is [] then [H1|R] is [5|[]] which is [5].
Here is a trace run for
mypred([1,3,5], [1,2,5], R).
so that you call look at all of the details.
?- trace.
[trace] ?- mypred([1,3,5], [1,2,5], R).
Call: (8) mypred([1, 3, 5], [1, 2, 5], _1844)
Unify: (8) mypred([1, 3, 5], [1, 2, 5], [1|_2090])
Call: (9) lists:member(1, [1, 2, 5])
Unify: (9) lists:member(1, [1, 2, 5])
Exit: (9) lists:member(1, [1, 2, 5])
Call: (9) mypred([3, 5], [1, 2, 5], _2090)
Unify: (9) mypred([3, 5], [1, 2, 5], [3|_2096])
Call: (10) lists:member(3, [1, 2, 5])
Unify: (10) lists:member(3, [1, 2, 5])
Fail: (10) lists:member(3, [1, 2, 5])
Redo: (9) mypred([3, 5], [1, 2, 5], _2090)
Unify: (9) mypred([3, 5], [1, 2, 5], _2090)
Call: (10) lists:member(3, [1, 2, 5])
Unify: (10) lists:member(3, [1, 2, 5])
Fail: (10) lists:member(3, [1, 2, 5])
Redo: (9) mypred([3, 5], [1, 2, 5], _2090)
Call: (10) mypred([5], [1, 2, 5], _2090)
Unify: (10) mypred([5], [1, 2, 5], [5|_2096])
Call: (11) lists:member(5, [1, 2, 5])
Unify: (11) lists:member(5, [1, 2, 5])
Exit: (11) lists:member(5, [1, 2, 5])
Call: (11) mypred([], [1, 2, 5], _2096)
Unify: (11) mypred([], [1, 2, 5], [])
Exit: (11) mypred([], [1, 2, 5], [])
Exit: (10) mypred([5], [1, 2, 5], [5])
Exit: (9) mypred([3, 5], [1, 2, 5], [5])
Exit: (8) mypred([1, 3, 5], [1, 2, 5], [1, 5])
R = [1, 5] ;
Redo: (10) mypred([5], [1, 2, 5], _2090)
Unify: (10) mypred([5], [1, 2, 5], _2090)
Call: (11) lists:member(5, [1, 2, 5])
Unify: (11) lists:member(5, [1, 2, 5])
Exit: (11) lists:member(5, [1, 2, 5])
Fail: (10) mypred([5], [1, 2, 5], _2090)
Fail: (9) mypred([3, 5], [1, 2, 5], _2090)
Redo: (9) lists:member(1, [1, 2, 5])
Fail: (9) lists:member(1, [1, 2, 5])
Redo: (8) mypred([1, 3, 5], [1, 2, 5], _1844)
Unify: (8) mypred([1, 3, 5], [1, 2, 5], _1844)
Call: (9) lists:member(1, [1, 2, 5])
Unify: (9) lists:member(1, [1, 2, 5])
Exit: (9) lists:member(1, [1, 2, 5])
Fail: (8) mypred([1, 3, 5], [1, 2, 5], _1844)
false.
If you are using SWI-Prolog then do this combination of queries to bring up the GUI tracer which is nicer for learning.
?- gtrace.
[trace] ?- mypred([1,3,5], [1,2,5], R).
Per suggestion in comment
Here are some other slight code variations and performance measures.
mypred_01([H1|T1], L2, [H1|R]) :-
member(H1,L2),
mypred_01(T1,L2,R).
mypred_01([H1|T1], L2, R) :-
\+ member(H1,L2),
mypred_01(T1,L2,R).
mypred_01([],_,[]).
mypred_02(L1,L2,R) :-
mypred_02_helper(L1,L2,[],R).
mypred_02_helper([H1|T1],L2,R0,R) :-
(
member(H1,L2)
->
mypred_02_helper(T1,L2,[H1|R0],R)
;
mypred_02_helper(T1,L2,R0,R)
).
mypred_02_helper([],_,R,R).
mypred_03(L1,L2,R) :-
mypred_03_helper(L1,L2,[],R0),
reverse(R0,R).
mypred_03_helper([H1|T1],L2,R0,R) :-
(
member(H1,L2)
->
mypred_03_helper(T1,L2,[H1|R0],R)
;
mypred_03_helper(T1,L2,R0,R)
).
mypred_03_helper([],_,R,R).
mypred_04(L1,L2,R) :-
mypred_04_helper(L1,L2,[],R).
mypred_04_helper([H1|T1],L2,R0,R) :-
(
memberchk(H1,L2)
->
mypred_04_helper(T1,L2,[H1|R0],R)
;
mypred_04_helper(T1,L2,R0,R)
).
mypred_04_helper([],_,R,R).
mypred_05(L1,L2,R) :-
mypred_05_helper(L1,L2,[],R0),
reverse(R0,R).
mypred_05_helper([H1|T1],L2,R0,R) :-
(
memberchk(H1,L2)
->
mypred_05_helper(T1,L2,[H1|R0],R)
;
mypred_05_helper(T1,L2,R0,R)
).
mypred_05_helper([],_,R,R).
Here are the performance results.
?- findall(N, between(1,100000,N), L1),time(mypred_01(L1,[1,10,100,10000,100000],R)).
% 1,400,020 inferences, 0.109 CPU in 0.103 seconds (106% CPU, 12800183 Lips)
L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
R = [1, 10, 100, 10000, 100000] ;
% 36 inferences, 0.000 CPU in 0.000 seconds (?% CPU, Infinite Lips)
false.
?- findall(N, between(1,100000,N), L1),time(mypred_02(L1,[1,10,100,10000,100000],R)).
% 799,988 inferences, 0.063 CPU in 0.062 seconds (101% CPU, 12799808 Lips)
L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
R = [100000, 10000, 100, 10, 1].
?- findall(N, between(1,100000,N), L1),time(mypred_03(L1,[1,10,100,10000,100000],R)).
% 800,059 inferences, 0.047 CPU in 0.053 seconds (88% CPU, 17067925 Lips)
L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
R = [1, 10, 100, 10000, 100000].
?- findall(N, between(1,100000,N), L1),time(mypred_04(L1,[1,10,100,10000,100000],R)).
% 299,999 inferences, 0.031 CPU in 0.041 seconds (77% CPU, 9599968 Lips)
L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
R = [100000, 10000, 100, 10, 1].
?- findall(N, between(1,100000,N), L1),time(mypred_05(L1,[1,10,100,10000,100000],R)).
% 300,005 inferences, 0.031 CPU in 0.032 seconds (98% CPU, 9600160 Lips)
L1 = [1, 2, 3, 4, 5, 6, 7, 8, 9|...],
R = [1, 10, 100, 10000, 100000].

Declarative interpretation of Bubble Sort algorithm in Prolog

I have some doubt about how work the following implementation of BubbleSort algorithm in Prolog.
I have very clear how BubbleSort algorithm work so my doubt is only related to the Prolog first order logic and declarative interpretation.
This is my code:
bubbleSort(List, SortedList) :- swap(List, List1),
!,
bubbleSort(List1, SortedList).
bubbleSort(SortedList, SortedList).
/* swap predicate swap the two element if X come after Y in lexicographical order */
swap([X,Y|Tail], [Y,X|Tail]) :- X #> Y.
/* If it is not true that X come after Y in lexicographical order let the head in its
original position and call the swap predicate on the sublist */
swap([Z|Tail], [Z|Tail1]) :- swap(Tail, Tail1).
So I have some doubt about declarative interpretation of this program:
The core of the program is the bubbleSort/2 predicate that perform the scansion of List in which are performed eventual swap of adjacent elements.
So swap/2 predicate work like a procedural if:
1) IF the first element in the sublist (X) follow the second element in the sublist (Y) in the lexicographical order it is not good, so perform the swap.
2) Otherwise X and Y are in the right order and try to execute te swap on the sublist Tail
So for example if I perform the following query:
[trace] ?- bubbleSort([3,2,1], Sorted).
I obtain:
Call: (7) bubbleSort([3, 2, 1], _G399) ? creep
Call: (8) swap([3, 2, 1], _G478) ? creep
Call: (9) 3#>2 ? creep
Exit: (9) 3#>2 ? creep
Exit: (8) swap([3, 2, 1], [2, 3, 1]) ? creep
Call: (8) bubbleSort([2, 3, 1], _G399) ? creep
Here call the first version of bubbleSort/2 on the original list. To be TRUE call the first version of swap/2 predicate that check if the first two elements of the list are not in lexicographical order each other, this fact is TRUE so swap these elements. Now that swap/2 predicate is verified, come back by backtracking and (to satisfy bubbleSort/2) call again bubbleSort2 saying now that the original list to order is the list after the swap (the list in which the first and the second element are swapped)
So call again bubbleSort and happen:
Call: (8) bubbleSort([2, 3, 1], _G399) ? creep
Call: (9) swap([2, 3, 1], _G484) ? creep
Call: (10) 2#>3 ? creep
Fail: (10) 2#>3 ? creep
Redo: (9) swap([2, 3, 1], _G484) ? creep
Call: (10) swap([3, 1], _G480) ? creep
Call: (11) 3#>1 ? creep
Exit: (11) 3#>1 ? creep
Exit: (10) swap([3, 1], [1, 3]) ? creep
Exit: (9) swap([2, 3, 1], [2, 1, 3]) ? creep
So now it try to satisfy swap/2 on the list [2,3,1] but now this is not true that the first two elements are not in lexicographical order each other, so the first version of swap/2 predicate fail, so it use the second version that simply call swap/2 on the sublist **[3,1] where it is true that 3 don't follow 1, so swap it and I obtain the [1,3] list.
Here I have the first doubt: after this swap on this sublist (from [3,1] to [1,3]) I obtain the list: [2, 1, 3] in this line:
Exit: (9) swap([2, 3, 1], [2, 1, 3]) ? creep
why? is this because after have satisfied swap(Tail, Tail1) predicate:
swap([Z|Tail], [Z|Tail1]) :- swap(Tail, Tail1).
I have that Tail1 is [1,3] so Z was the old head 2 and [Z|Tail1] is [2,1,3] ?
However, now it is end the first scansion of the bubble sort algorithm that have take the "bigger" element at the end of the list
The execution continues in the same way but I have a doubt about the end of the program execution that is:
Redo: (10) bubbleSort([1, 2, 3], _G399) ? creep
Exit: (10) bubbleSort([1, 2, 3], [1, 2, 3]) ? creep
Exit: (9) bubbleSort([2, 1, 3], [1, 2, 3]) ? creep
Exit: (8) bubbleSort([2, 3, 1], [1, 2, 3]) ? creep
Exit: (7) bubbleSort([3, 2, 1], [1, 2, 3]) ? creep
Sorted = [1, 2, 3].
So at the end call the bubbleSort/2 predicate on an ordered List by:
Redo: (10) bubbleSort([1, 2, 3], _G399) ? creep
where [1,2,3] is List1.
Now I am in the second version of bubbleSort/2 predicate, this one:
bubbleSort(SortedList, SortedList).
where the list to sort and the sorted list is the same (so it means that the original list is totatly sorted).
So what is this? the base case that, once verified, say that the program execution have to end?
So execute backtracking to say that all the previous bubbleSort/2 are verified, untill reach the first bubbleSort/2 call and say that this is vierified and unify Sorted with [1,2,3] list
Is my reasoning correct? Are there a more declarative interpretation of this?
I think the key to understand this algorithm it's the fact that swap/2 fails when the list is sorted - there is no match on empty list.
From here the necessity of the second bubbleSort/2 rule.

Prolog: Reverse every second list elements in a list

I have to write a program that will get lists in a list, and should reverse every second list, then return the result. Something like this:
doStuff([[1,2], [3,4], [5,6], [7,8]], R).
R = [[1,2], [4,3], [5,6], [8,7]]
This is what I have so far:
doStuff([],_).
doStuff([X,S|T],R):- reverse(S,Rev), add(X,Rev,R), doStuff(T,R).
doStuff([X|[]], R):- add(X,R,R).
reverse([X|Y],Z,W) :- reverse(Y,[X|Z],W).
reverse([],X,X).
add(X,[],X).
add(X,L,[X,L]).
My problem is that, in the second iteration the add function fails.
I'm also concerned about what will happen when the original list contains only one list at the end.
since you said that add/3 fails after the second iteration i assume that you used trace/0
anyway, here it is:
[trace] ?- doStuff([[1,2], [3,4], [5,6], [7,8]], R).
Call: (6) doStuff([[1, 2], [3, 4], [5, 6], [7, 8]], _G405) ? creep
Call: (7) lists:reverse([3, 4], _G496) ? creep
Exit: (7) lists:reverse([3, 4], [4, 3]) ? creep
Call: (7) add([1, 2], [4, 3], _G405) ? creep
Exit: (7) add([1, 2], [4, 3], [[1, 2], [4, 3]]) ? creep
Call: (7) doStuff([[5, 6], [7, 8]], [[1, 2], [4, 3]]) ? creep
Call: (8) lists:reverse([7, 8], _G514) ? creep
Exit: (8) lists:reverse([7, 8], [8, 7]) ? creep
Call: (8) add([5, 6], [8, 7], [[1, 2], [4, 3]]) ? creep
Fail: (8) add([5, 6], [8, 7], [[1, 2], [4, 3]]) ? creep
Redo: (7) doStuff([[5, 6], [7, 8]], [[1, 2], [4, 3]]) ? creep
Fail: (7) doStuff([[5, 6], [7, 8]], [[1, 2], [4, 3]]) ? creep
Redo: (6) doStuff([[1, 2], [3, 4], [5, 6], [7, 8]], _G405) ? creep
Fail: (6) doStuff([[1, 2], [3, 4], [5, 6], [7, 8]], _G405) ? creep
false.
so why does it fail? it's because of one of prolog's main characteristics
basically, a variable in prolog, once it takes a value, it can never change
this may sound kinda weird if you used imperative languages so far but consider that exactly the same thing happens in math.
For example, consider the following equations:
x+3=4
4-x=5
from the first we get that x=1
and from the second we get that x=-1
since x cannot be 1 and -1 we say that there is no x to satisfy the equations above;
not that x is -1 since that's the value of the second (and last) equation
exactly the same thing happens in yout program:
doStuff([X,S|T],R):- reverse(S,Rev), add(X,Rev,R), doStuff(T,R).
so the first time R is assigned a value and the doStuff/2 is call with a value for R.
obviously, this is not the correct value so doStuff/2 fails
so how can you fix this? look at the way you wrote [X,S|T] to separate the first two elements that you wanted to process. you only have to do exactly the same with the result:
write it like [XResult,SResult|Rest]
of course XResult will be simply X and SResult will be the reverse of S (Rev)
Rest will be what you get from the recursive call of doStuff/2
last but not least you should check the clauses that are called in the end.
you could check some stuff about lists and recursion

Resources