Prolog unification and optimization - list

I want to write merge function which merges two lists , i can do that by writing two (merge) predicates, one where element H1 =< H2 and other where H1 > H2 but however i want to write with if-the-else condition but then unification fails and i don't know how to do it. Here is my code:
merge([H1|T1],[H2|T2],List):-
(
H1 =< H2 ->
NewList = [H1|List],
merge(T1,[H2|T2],NewList)
;
NewList = [H2|List],
merge([H1|T1],T2,NewList)
).
merge([],L,L).
merge(L,[],L).
I know what is the problem and if i write two merge-predicates i can avoid it but i don't know how to do it here , i'm stucked :(
Pattern matching fails here :

You're actually pretty close. Look at this trace:
?- trace, merge([1,3,5,6], [2,4,7,8], X).
Call: (9) merge([1, 3, 5, 6], [2, 4, 7, 8], _6684) ? creep
Call: (10) 1=<2 ? creep
Exit: (10) 1=<2 ? creep
Call: (10) _7050=[1|_6684] ? creep
Exit: (10) [1|_6684]=[1|_6684] ? creep
Call: (10) merge([3, 5, 6], [2, 4, 7, 8], [1|_6684]) ? creep
Call: (11) 3=<2 ? creep
Fail: (11) 3=<2 ? creep
Redo: (10) merge([3, 5, 6], [2, 4, 7, 8], [1|_6684]) ? creep
Call: (11) _7062=[2, 1|_6684] ? creep
Exit: (11) [2, 1|_6684]=[2, 1|_6684] ? creep
Call: (11) merge([3, 5, 6], [4, 7, 8], [2, 1|_6684]) ? creep
Call: (12) 3=<4 ? creep
Exit: (12) 3=<4 ? creep
Call: (12) _7074=[3, 2, 1|_6684] ? creep
Exit: (12) [3, 2, 1|_6684]=[3, 2, 1|_6684] ? creep
Call: (12) merge([5, 6], [4, 7, 8], [3, 2, 1|_6684]) ? creep
Call: (13) 5=<4 ? creep
Fail: (13) 5=<4 ? creep
Redo: (12) merge([5, 6], [4, 7, 8], [3, 2, 1|_6684]) ? creep
Call: (13) _7086=[4, 3, 2, 1|_6684] ? creep
Exit: (13) [4, 3, 2, 1|_6684]=[4, 3, 2, 1|_6684] ? creep
Call: (13) merge([5, 6], [7, 8], [4, 3, 2, 1|_6684]) ? creep
Call: (14) 5=<7 ? creep
Exit: (14) 5=<7 ? creep
Call: (14) _7098=[5, 4, 3, 2, 1|_6684] ? creep
Exit: (14) [5, 4, 3, 2, 1|_6684]=[5, 4, 3, 2, 1|_6684] ? creep
Call: (14) merge([6], [7, 8], [5, 4, 3, 2, 1|_6684]) ? creep
Call: (15) 6=<7 ? creep
Exit: (15) 6=<7 ? creep
Call: (15) _7110=[6, 5, 4, 3, 2, 1|_6684] ? creep
Exit: (15) [6, 5, 4, 3, 2, 1|_6684]=[6, 5, 4, 3, 2, 1|_6684] ? creep
At this moment in the depth of the recursion, you almost have the solution. Then it starts to go awry:
Call: (15) merge([], [7, 8], [6, 5, 4, 3, 2, 1|_6684]) ? creep
Fail: (15) merge([], [7, 8], [6, 5, 4, 3, 2, 1|_6684]) ? creep
Redo: (14) merge([6], [7, 8], [5, 4, 3, 2, 1|_6684]) ? creep
Fail: (14) merge([6], [7, 8], [5, 4, 3, 2, 1|_6684]) ? creep
Redo: (13) merge([5, 6], [7, 8], [4, 3, 2, 1|_6684]) ? creep
Fail: (13) merge([5, 6], [7, 8], [4, 3, 2, 1|_6684]) ? creep
Redo: (12) merge([5, 6], [4, 7, 8], [3, 2, 1|_6684]) ? creep
Fail: (12) merge([5, 6], [4, 7, 8], [3, 2, 1|_6684]) ? creep
Redo: (11) merge([3, 5, 6], [4, 7, 8], [2, 1|_6684]) ? creep
Fail: (11) merge([3, 5, 6], [4, 7, 8], [2, 1|_6684]) ? creep
Redo: (10) merge([3, 5, 6], [2, 4, 7, 8], [1|_6684]) ? creep
Fail: (10) merge([3, 5, 6], [2, 4, 7, 8], [1|_6684]) ? creep
Redo: (9) merge([1, 3, 5, 6], [2, 4, 7, 8], _6684) ? creep
Fail: (9) merge([1, 3, 5, 6], [2, 4, 7, 8], _6684) ? creep
So what's wrong with your code? Two things mainly: you're building the result reversed (not uncommon) and you don't have a good way to pass it back. Arranging for a result variable is certainly one way to handle these problems, similarly to what Luai figured out:
merge(X,Y,Z) :- merge(X, Y, [], Z).
merge([H1|T1],[H2|T2],List,NewList):-
(
H1 =< H2 ->
merge(T1,[H2|T2],[H1|List],NewList)
;
merge([H1|T1],T2,[H2|List],NewList)
).
merge([],R,LRev,Res) :- reverse(LRev, L), append(L,R,Res).
merge(R,[],LRev,Res) :- reverse(LRev, L), append(L,R,Res).
Or you will have to figure out another way to do it, such as by passing down the tail of the list, like this:
merge2([H1|T1], [H2|T2], MT) :-
(H1 =< H2 ->
MT=[H1|MT2],
merge2(T1, [H2|T2], MT2)
;
MT=[H2|MT2],
merge2([H1|T1], T2, MT2)
).
merge2([], T2, T2).
merge2(T2, [], T2).
I would favor this approach, personally.

You think of recursion the wrong way. The third parameter is the outcome of the merge.
Here you use:
merge([H1|T1],[H2|T2],List):-
(
H1 =< H2 ->
NewList = [H1|List],
merge(T1,[H2|T2],NewList)
;
NewList = [H2|List],
merge([H1|T1],T2,NewList)
).
merge([],L,L).
merge(L,[],L).
In other words you are not prepending the output of the recursive call, you are in fact expecting the recursive output to start with H1 and/or H2 and then pop that element from the result and pass the remainder (the tail of the list) as outcome.
So a quick fix is to reverse that:
merge([H1|T1],[H2|T2],List):-
(
H1 =< H2 ->
List = [H1|NewList],
merge(T1,[H2|T2],NewList)
;
List = [H2|NewList],
merge([H1|T1],T2,NewList)
).
merge([],L,L).
merge(L,[],L).
Now we notice however that there is some duplicate code, so we can rewrite it to:
merge([H1|T1],[H2|T2],[Min|NewList]):-
(
H1 =< H2 ->
Min = H1,
merge(T1,[H2|T2],NewList)
;
Min = H2,
merge([H1|T1],T2,NewList)
).
merge([],L,L).
merge(L,[],L).
But personally, I find a two-clause solution more elegant:
merge([H1|T1],[H2|T2],[H1|T3]) :-
H1 =< H2,
merge(T1,[H2|T2],T3).
merge([H1|T1],[H2|T2],[H2|T3]) :-
H1 > H2,
merge([H1|T1],T2,T3).
merge([],L,L).
merge(L,[],L).

There should be a better way but this is also one option.
merge(List1,List2,Result):-
merge(List1,List2,[],Result).
merge([],L,X,Result):-
append(X,L,Result).
merge(L,[],X,Result):-
append(X,L,Result).
merge([H1|T1],[H2|T2],Acc,Result):-
(
H1 =< H2 ->
apend(Acc,H1,NewList),
merge(T1,[H2|T2],NewList,Result)
;
apend(Acc,H2,NewList),
merge([H1|T1],T2,NewList,Result)
).
%i think prolog implementation of append/3 does not work with empty list so i implemented here.
apend([],X,[X]).
apend([H|T],X,[H|T2]):-
apend(T,X,T2).

Related

Prolog basic exercise with lists gives stack size error

I'm starting to learn prolog, and I'm stuck with this problem, it would be really helpful if someone could tell me what I'm doing wrong and why is it wrong so I can learn.
Exercise
Write a predicate that follows the syntax:
supr_bigger(Elem,List,Result)
where Result is the list List, but with all of the elements bigger than Elem deleted.
Code
supr_bigger(_,[],[]).
supr_bigger(Elem,[X|Y],R) :- X =< Elem,
insert(X,R,R1),
supr_bigger(Elem,Y,R1).
supr_bigger(Elem,[X|Y],R) :- X > Elem, supr_bigger(Elem,Y,R).
insert(Z,L1,L2) :- choose(Z,L2,L1).
choose(X,[X|L],L).
choose(X,[Y|L1],[Y|L2]) :- choose(X,L1,L2).
When I try to test the code above, this error shows up:
?- supr_bigger(3,[3,2,5,4,1,2,6],R).
ERROR: Stack limit (1,0Gb) exceeded
ERROR: Stack sizes: local: 2Kb, global: 0,9Gb, trail: 0Kb
ERROR: Stack depth: 16, last-call:13%, Choice points: 11
A lot of thanks in advance.
You can use predicate trace/1 to find out what is wrong with your code:
?- trace, supr_bigger(3, [3,2,1,4], R).
Call: (11) supr_bigger(3, [3, 2, 1, 4], _4526) ? creep
Call: (12) 3=<3 ? creep
Exit: (12) 3=<3 ? creep
Call: (12) insert(3, _4526, _5168) ? creep
Call: (13) choose(3, _5210, _4526) ? creep
Exit: (13) choose(3, [3|_4526], _4526) ? creep
Exit: (12) insert(3, _4526, [3|_4526]) ? creep
Call: (12) supr_bigger(3, [2, 1, 4], [3|_4526]) ? creep
Call: (13) 2=<3 ? creep
Exit: (13) 2=<3 ? creep
Call: (13) insert(2, [3|_4526], _5482) ? creep
Call: (14) choose(2, _5524, [3|_4526]) ? creep
Exit: (14) choose(2, [2, 3|_4526], [3|_4526]) ? creep
Exit: (13) insert(2, [3|_4526], [2, 3|_4526]) ? creep
Call: (13) supr_bigger(3, [1, 4], [2, 3|_4526]) ? creep
Call: (14) 1=<3 ? creep
Exit: (14) 1=<3 ? creep
Call: (14) insert(1, [2, 3|_4526], _5796) ? creep
Call: (15) choose(1, _5838, [2, 3|_4526]) ? creep
Exit: (15) choose(1, [1, 2, 3|_4526], [2, 3|_4526]) ? creep
Exit: (14) insert(1, [2, 3|_4526], [1, 2, 3|_4526]) ? creep
Call: (14) supr_bigger(3, [4], [1, 2, 3|_4526]) ? creep
Call: (15) 4=<3 ? creep
Fail: (15) 4=<3 ? creep
Redo: (14) supr_bigger(3, [4], [1, 2, 3|_4526]) ? creep
Call: (15) 4>3 ? creep
Exit: (15) 4>3 ? creep
Call: (15) supr_bigger(3, [], [1, 2, 3|_4526]) ? creep
Fail: (15) supr_bigger(3, [], [1, 2, 3|_4526]) ?
As you can observe, when the input list is empty (call 15), the output list actually contains all the elements that should have been selected. However, the base clause in the recusive definition of supr_bigger/3 cannot be applied in this case, since lists [] (clause's third argument) and [1, 2, 3|_4526] (goal's third argument) do not match.
To solve the problem, you could modify your code to:
Close the open list [1, 2, 3|_4526], transforming it into [1, 2, 3].
Add a new argument to collect the final result.
But, since your code has many other problems, it's better to try a simpler approach:
supr_bigger(_, [], []).
supr_bigger(B, [X|Xs], [X|Ys]) :- X =< B, supr_bigger(B, Xs, Ys).
supr_bigger(B, [X|Xs], Ys) :- X > B, supr_bigger(B, Xs, Ys).
Example:
?- supr_bigger(3, [3,2,1,4], R).
R = [3, 2, 1] ;
false.
To eliminate spurious choice points, you can do as follows
supr_bigger(B, L, R) :-
best_supr_bigger(L, B, R).
best_supr_bigger([], _, []).
best_supr_bigger([X|Xs], B, R) :-
( X =< B
-> R = [X|Ys]
; R = Ys ),
best_supr_bigger(Xs, B, Ys).
Example:
?- supr_bigger(3, [3,2,1,4], R).
R = [3, 2, 1].

Prolog Count Occurrences in 2 lists

I want to compare 2 list, for each element.
Count the number of equal elements.
Im so close, please help me:
%list vs list%
count2([],[],0).
count2([H1|T1],[H2|T2],S):-
count(H1,[H2|T2],N),
count2(T1,[H2|T2],M),
S is N+M.
%1 element vs 1 list%
count(_, [], 0).
count(X, [X | T], N) :-
!, count(X, T, N1),
N is N1 + 1.
count(X, [_ | T], N) :-
count(X, T, N).
A test:
1 ?- count2([2],[1,2,3],S).
false.
Trace:
2 ?- count2([2],[1,2,3],S).
Redo: (5) read_history(h, '!h', [trace, end_of_file], '~! ?- ', _G154, _G155) ? creep
Correct to: "count2([2],[1,2,3],S)"?
Please answer 'y' or 'n'? yes
Call: (7) count2([2], [1, 2, 3], _G306) ? creep
Call: (8) count(2, [1, 2, 3], _G631) ? creep
Call: (9) count(2, [2, 3], _G631) ? creep
Call: (10) count(2, [3], _G631) ? creep
Call: (11) count(2, [], _G631) ? creep
Exit: (11) count(2, [], 0) ? creep
Exit: (10) count(2, [3], 0) ? creep
Call: (10) _G632 is 0+1 ? creep
Exit: (10) 1 is 0+1 ? creep
Exit: (9) count(2, [2, 3], 1) ? creep
Exit: (8) count(2, [1, 2, 3], 1) ? creep
Call: (8) count2([], [1, 2, 3], _G637) ? creep
Fail: (8) count2([], [1, 2, 3], _G637) ? creep
Redo: (11) count(2, [], _G631) ? creep
Fail: (11) count(2, [], _G631) ? creep
Fail: (10) count(2, [3], _G631) ? creep
Fail: (9) count(2, [2, 3], _G631) ? creep
Fail: (8) count(2, [1, 2, 3], _G631) ? creep
Fail: (7) count2([2], [1, 2, 3], _G306) ? creep
false.
(Returns the solution, but I have a problem with recursion)
Requested output #1:
?- count2([2],[1,2,3],S).
S = 1.
(2 is 1 time in the list).
Requested output #2:
?- count2([1,2],[1,2,3],S).
S = 2
(1 is 1 time in the list).
(2 is 1 time in the list).
Total = 2 equal elements.
A simpler solution would be to recurse on elements of the main list and check whether each element is a member of your test list:
count(_, [], 0).
count(Xs, [H|T], C) :-
( member(H, Xs)
-> C #= C1 + 1
; C1 = C
),
count(Xs, T, C1).
Answer:
count2([],[_|_],0).
count2([H1|T1],[H2|T2],S):-
count(H1,[H2|T2],N),
count2(T1,[H2|T2],M),
S is N+M.
count(_, [], 0).
count(X, [X | T], N) :-
!, count(X, T, N1),
N is N1 + 1.
count(X, [_ | T], N) :-
count(X, T, N).
Solved!

Prolog: Append complex terms in a list

I'm new with Prolog and I have a problem that I don't understand why.
I have a predicate (maybe wrong) that is to split a list in two lists. Something like that:
divide([],[],[]).
divide([PrimerEdificio|RestoEdificios], ListaA, ListaB) :-
divide(RestoEdificios, ListaParcialA, ListaParcialB),
append([PrimerEdificio], ListaParcialA, ListaA),
length(RestoEdificios, LongitudResto),
length(ListaA, LongitudA),
LongitudA > LongitudResto.
divide([PrimerEdificio|RestoEdificios], ListaA, ListaB) :-
length(RestoEdificios, LongitudResto),
length(ListaA, LongitudA),
LongitudA =< LongitudResto.
append(RestoEdificios, [], ListaB).
When I try to append the terms into the list (case 2) the variable is not being instantiated but if I do directly in console it works fine. Here debug:
[trace] 1 ?- divide([ed(3,5,6), ed(4,5,6), ed(5,6,7)], X, Y).
Call: (7) divide([ed(3, 5, 6), ed(4, 5, 6), ed(5, 6, 7)], _G3026, _G3027) ? creep
Call: (8) divide([ed(4, 5, 6), ed(5, 6, 7)], _G3140, _G3141) ? creep
Call: (9) divide([ed(5, 6, 7)], _G3140, _G3141) ? creep
Call: (10) divide([], _G3140, _G3141) ? creep
Exit: (10) divide([], [], []) ? creep
Call: (10) append([ed(5, 6, 7)], [], _G3144) ? creep
Exit: (10) append([ed(5, 6, 7)], [], _G3144) ? creep
I would hope that _G3144 (last sentence) is instantiated to [ed(5, 6, 7)].
Any help?

Why does using [H|T] as a parameter instead of a normal variable cause my predicate to fail?

I'm creating a predicate to remove a specified element from a list so remove(Xs,X,Ys) should hold if Ys is the result of removing all occurrences
of X from Xs. My initial failing predicate is shown below:
remove([],_,[]).
remove([H1|T1],H1,[H2|T2]) :- % e.g. [2,3] , 2, [3]
remove(T1,H1,[H2|T2]). % remove first head -> [3], 2, [3]
remove([H1|T1],Y,[H1|T2]) :- % heads match e.g. [1,2,3], 2, [1,3]
H1\==Y,
remove(T1,Y,T2). % remove heads -> [2,3], 2, [3]
This was failing but then I noticed that I had a redundant [H2|Y2] where I could have just used a variable e.g. Ys. I made this change thinking that it would still fail but instead it starting working. The working code is shown below:
remove([],_,[]).
remove([H1|T1],H1,Ys) :- % e.g. [2,3] , 2, [3]
remove(T1,H1,Ys). % remove first head -> [3], 2, [3]
remove([H1|T1],Y,[H1|T2]) :- % heads match e.g. [1,2,3], 2, [1,3]
H1\==Y,
remove(T1,Y,T2). % remove heads -> [2,3], 2, [3]
Can someone explain why changing [H2|T2] to Ys made it work?
Somewhere in the progression of the query, the pattern, remove([H|T], H, []) is coming up which will match the head of the second clause of your second version, remove([H1|T1], H1, Ys), but will not match the head of the second clause of your first version, remove([H1|T1], H1, [H2|T2]).
If you run trace on the query, remove([1, 2, 3, 2], 2, [1, 3]) using your first program version, you get:
Call: (6) remove([1, 2, 3, 2], 2, [1, 3]) ? creep
Call: (7) 1\==2 ? creep
Exit: (7) 1\==2 ? creep
Call: (7) remove([2, 3, 2], 2, [3]) ? creep
Call: (8) remove([3, 2], 2, [3]) ? creep
Call: (9) 3\==2 ? creep
Exit: (9) 3\==2 ? creep
Call: (9) remove([2], 2, []) ? creep
Fail: (9) remove([2], 2, []) ? creep <---- NOTE THIS FAILURE! (no clause match)
Fail: (8) remove([3, 2], 2, [3]) ? creep
Redo: (7) remove([2, 3, 2], 2, [3]) ? creep
Fail: (7) remove([2, 3, 2], 2, [3]) ? creep
Fail: (6) remove([1, 2, 3, 2], 2, [1, 3]) ? creep
The case remove([2], 2, []) will not match the second clause of your first implementation:
remove([H1|T1], H1, [H2|T2])...
So H1 = 2, T1 = [], but [H2|T2] is not unifiable with [].
But it will match the second clause of your second implementation:
remove([H1|T1], H1, Ys).
Here you get, H1 = 2, T1 = [], and Ys = []. Here it is in the trace for your second version:
[trace] ?- remove([1,2,3,2],2,[1,3]).
Call: (6) remove([1, 2, 3, 2], 2, [1, 3]) ? creep
Call: (7) 1\==2 ? creep
Exit: (7) 1\==2 ? creep
Call: (7) remove([2, 3, 2], 2, [3]) ? creep
Call: (8) remove([3, 2], 2, [3]) ? creep
Call: (9) 3\==2 ? creep
Exit: (9) 3\==2 ? creep
Call: (9) remove([2], 2, []) ? creep <---- SUCCESS! (2nd clause match)
Call: (10) remove([], 2, []) ? creep <---- SUCCESS!
Exit: (10) remove([], 2, []) ? creep
Exit: (9) remove([2], 2, []) ? creep
Exit: (8) remove([3, 2], 2, [3]) ? creep
Exit: (7) remove([2, 3, 2], 2, [3]) ? creep
Exit: (6) remove([1, 2, 3, 2], 2, [1, 3]) ? creep

SWI-Prolog: Sum-List

I'm starting with Prolog, and i'm a bit confused...
I have a simple program:
sum(0, []).
sum(Total, [Head|Tail]) :- sum(Sum, Tail), Total is Head + Sum.
When i debug, i can see that Prolog first splits the list with Head and Tail, so the result is 0 + empty list, and AFTER THAT it starts to sum the numbers and adds it again to the list.
Can someone explain why it doesn't come to Total is Head + Sum.
first and then splits the list to Head and Tail again?
EDIT: Here is the trace:
[trace] ?- sum(X, [1,2,3]).
Call: (6) sum(_G345, [1, 2, 3]) ? creep
Call: (7) sum(_G424, [2, 3]) ? creep
Call: (8) sum(_G424, [3]) ? creep
Call: (9) sum(_G424, []) ? creep
Exit: (9) sum(0, []) ? creep
Call: (9) _G430 is 3+0 ? creep
Exit: (9) 3 is 3+0 ? creep
Exit: (8) sum(3, [3]) ? creep
Call: (8) _G433 is 2+3 ? creep
xit: (8) 5 is 2+3 ? creep
Exit: (7) sum(5, [2, 3]) ? creep
Call: (7) _G345 is 1+5 ? creep
Exit: (7) 6 is 1+5 ? creep
Exit: (6) sum(6, [1, 2, 3]) ? creep
X = 6.
Your definition puts addition on the stack. The optimization that avoids putting away the addition would be a special case of a general technique known as tail recursion.
The following definition can use tail recursion:
sum(X,L):-sum(0,L,X).
sum(X,[],X).
sum(N, [Head|Tail],Y) :- N1 is Head + N, sum(N1,Tail,Y).
It introduces an accumulator for the values of the partial sum and carries it with the tail of the list. Here is the trace of the execution of the sum(X,[1,2,3]) query.
?- trace, sum(S,[1,2,3]),notrace,nodebug.
Call: (7) sum(_G584, [1, 2, 3]) ? creep
Call: (8) sum(0, [1, 2, 3], _G584) ? creep
^ Call: (9) _G792 is 1+0 ? creep
^ Exit: (9) 1 is 1+0 ? creep
Call: (9) sum(1, [2, 3], _G584) ? creep
^ Call: (10) _G795 is 2+1 ? creep
^ Exit: (10) 3 is 2+1 ? creep
Call: (10) sum(3, [3], _G584) ? creep
^ Call: (11) _G798 is 3+3 ? creep
^ Exit: (11) 6 is 3+3 ? creep
Call: (11) sum(6, [], _G584) ? creep
Exit: (11) sum(6, [], 6) ? creep
Exit: (10) sum(3, [3], 6) ? creep
Exit: (9) sum(1, [2, 3], 6) ? creep
Exit: (8) sum(0, [1, 2, 3], 6) ? creep
Exit: (7) sum(6, [1, 2, 3]) ? creep
S = 6 .
Here is another version doing that. I have been using concept mapping software to help in designing code, I cannot do complicated stuff in my head.
sum(A, [], A).
sum(Total, [Head|Tail], AuxNum) :-
Sum is Head+AuxNum,
sum(Total, Tail, Sum).
1 ?- trace,sum(Total,[1,2,3],0).
Call: (7) sum(_G2090, [1, 2, 3], 0) ? creep
Call: (8) _G2221 is 1+0 ? creep
Exit: (8) 1 is 1+0 ? creep
Call: (8) sum(_G2090, [2, 3], 1) ? creep
Call: (9) _G2224 is 2+1 ? creep
Exit: (9) 3 is 2+1 ? creep
Call: (9) sum(_G2090, [3], 3) ? creep
Call: (10) _G2227 is 3+3 ? creep
Exit: (10) 6 is 3+3 ? creep
Call: (10) sum(_G2090, [], 6) ? creep
Exit: (10) sum(6, [], 6) ? creep
Exit: (9) sum(6, [3], 3) ? creep
Exit: (8) sum(6, [2, 3], 1) ? creep
Exit: (7) sum(6, [1, 2, 3], 0) ? creep
Total = 6.