Why does my min() function in Prolog not work? - debugging

This is my min() function in Prolog that should find the smallest element in a list of numbers. My idea was to test that the Result is smaller or equal to every element in the list. The head of the list is removed until it is empty. When this point is reached, the set in result was correct.
min([], Result).
min([Head|Tail], Result) :-
Result =< Head,
min(Tail, Result).
When consulting this file in SWI-Prolog, it can test if a value is the minimal element with min([5, 3, 7, 6], 3) which returns true. But min([5, 3, 7, 6], X) does not find a value for X but just returns true.
How can I make it find the value for X?

If you turn tracing on you can see what's wrong with your script.
1 ?- trace.
true.
Original version:
/** Version 0 */
min([], Result).
min([Head|Tail], Result) :-
Result =< Head,
min(Tail, Result).
Output:
[trace] 2 ?- min([5,3,7,6],X).
Call: (6) min([5, 3, 7, 6], _G4129) ? creep
Call: (7) _G4129=<5 ? creep
ERROR: =</2: Arguments are not sufficiently instantiated
Exception: (7) _G4129=<5 ? creep
You're trying to compare an unistantiated variable with 5. Solution: swap lines in the script so that the variable is instantiated before the comparison.
/** Version 1 */
min([], Result).
min([Head|Tail], Result) :-
min(Tail, Result),
Result =< Head.
Output:
[trace] 5 ?- min([5,3,7,6],X).
Call: (6) min([5, 3, 7, 6], _G517) ? creep
Call: (7) min([3, 7, 6], _G517) ? creep
Call: (8) min([7, 6], _G517) ? creep
Call: (9) min([6], _G517) ? creep
Call: (10) min([], _G517) ? creep
Exit: (10) min([], _G517) ? creep
Call: (10) _G517=<6 ? creep
ERROR: =</2: Arguments are not sufficiently instantiated
Exception: (10) _G517=<6 ?
[trace] 102 ?- min([5,3,7,6],X).
Call: (6) min([5, 3, 7, 6], _G3067) ? creep
Call: (7) min([3, 7, 6], _G3067) ? creep
Call: (8) min([7, 6], _G3067) ? creep
Call: (9) min([6], _G3067) ? creep
Call: (10) min([], _G3067) ? creep
Exit: (10) min([], _G3067) ? creep
Call: (10) _G3067=<6 ? creep
ERROR: =</2: Arguments are not sufficiently instantiated
Exception: (10) _G3067=<6 ?
This way the script goes a bit further but when computing the minimum of the tail it reaches a comparison with an unistantiated variable again. Solution: change min([], Result). to min([Result], Result).
/** version 2 */
min([Result], Result).
min([Head|Tail], Result) :-
min(Tail, Result),
Result =< Head.
Output:
[trace] 8 ?- min([5,3,7,6],3).
Call: (6) min([5, 3, 7, 6], 3) ? creep
Call: (7) min([3, 7, 6], 3) ? creep
Call: (8) min([7, 6], 3) ? creep
Call: (9) min([6], 3) ? creep
Call: (10) min([], 3) ? creep
Fail: (10) min([], 3) ? creep
Fail: (9) min([6], 3) ? creep
Fail: (8) min([7, 6], 3) ? creep
Fail: (7) min([3, 7, 6], 3) ? creep
Fail: (6) min([5, 3, 7, 6], 3) ? creep
false.
The program now only returns false. This is because you only consider the case the minimum of the tail is smaller than or equal than the head. This program will only return a correct result when the input list is sorted decreasingly (so that the minimum of the tail is smaller than the head, recursively).
[trace] 10 ?- min([5,4,3,2],X).
Call: (6) min([5, 4, 3, 2], _G2469) ? creep
Call: (7) min([4, 3, 2], _G2469) ? creep
Call: (8) min([3, 2], _G2469) ? creep
Call: (9) min([2], _G2469) ? creep
Exit: (9) min([2], 2) ? creep
Call: (9) 2=<3 ? creep
Exit: (9) 2=<3 ? creep
Exit: (8) min([3, 2], 2) ? creep
Call: (8) 2=<4 ? creep
Exit: (8) 2=<4 ? creep
Exit: (7) min([4, 3, 2], 2) ? creep
Call: (7) 2=<5 ? creep
Exit: (7) 2=<5 ? creep
Exit: (6) min([5, 4, 3, 2], 2) ? creep
X = 2 .
So you need to take care of the case when the minimum of the tail is strictly greater than the head by adding the clause:
min([Head|Tail], Result) :-
min(Tail, R1),
Head < R1,
Result is Head.
And here's the final version:
/** version 3 */
min([Result], Result).
min([Head|Tail], Result) :-
min(Tail, Result),
Result =< Head.
min([Head|Tail], Result) :-
min(Tail, R1),
Head < R1,
Result is Head.
(turn tracing off with nodebug.)

The min of an empty list can't be set.
You can just write
min([X], X).
hoping that X is an integer ; I assume it is !
then
min([Head|Tail], Result) :-
% you fetch the min of the rest of the list
min(Tail, R1),
(Head < R1
-> Result = Head
; Result = R1).

My SWI-Prolog reports
?- min([5, 3, 7, 6], X).
ERROR: user://1:18:
=</2: Arguments are not sufficiently instantiated
which makes sense as the first X =< 3 is performed with unbound X. To make the predicate work, you need to follow the definition of minimum, which is not defined for empty lists:
min([X], X).
min([X|L], Min) :-
L = [_|_], % non-empty tail; could be replaced by a cut
min(L, MinL),
Min is min(X, MinL).
(Note that the final line backs off to the built-in min, which is evaluated by is.)
Alternatively, you can take minima of pairs of elements, giving
min([X], X).
min([X,Y|L], Min) :-
MinXY is min(X, Y),
min([MinXY|L], Min).
This version is tail-recursive.

It couldn't possibly have returned true there. X =< 3 causes "ERROR: =</2: Arguments are not sufficiently instantiated". Perhaps you used #=< for comparison, but with it X #=< 3 just succeeds, without instantiating X in any way. So X would get passed unchanged, and min([], X) would just finally succeed - exactly what you've observed.
Your code is wrong in another way too. min([5, 3, 7, 6], 0) succeeds too, and it shouldn't.
others provided you with recursive solutions. For an iterative one, we typically add another, accumulating argument, and pass the Result down the chain unchanged to receive the final value from the accumulator for us:
min([H|T], Result):- min(T,H,Result).
min([], Result, Result).
min([Head|Tail], M, Result) :-
M =< Head -> min(Tail, M, Result)
; min(Tail, Head, Result).
Empty list has no minimum value. An argument list's head is used as initial value for the minimum.

Related

Prolog how to add element in a list if is in a list

I m trying to do a list member(member/2) with my own predicate.
starting this example
?-app([a,r,t],[t,s,m,n,a],L3).
L3=[a,t]
I tried to do similar exercises so I did this with prolog:
app([],_,[]).
app([H|T],[H1,T1],[H|L1]):- H is H1, L1 is H,! ,app(T,T1,L1).
app([_H|T],L,L2):- app(T,L,L2).
and all working regular, but the value in a list will be overwritten during the execution, in fact, the trace is :
trace, app([3,2],[3,5],X).
Call: (9) app([3, 2], [3, 5], _7426) ? creep
Call: (10) 3 is 3 ? creep
Exit: (10) 3 is 3 ? creep
Call: (10) _7736 is 3 ? creep
Exit: (10) 3 is 3 ? creep
Call: (10) app([2], 5, 3) ? creep
Call: (11) app([], 5, 3) ? creep
Fail: (11) app([], 5, 3) ? creep
Fail: (10) app([2], 5, 3) ? creep
Fail: (9) app([3, 2], [3, 5], _7426) ? creep
false.
I tried to make a modify on the base case in this way:
app([],_,_N).
but the output is every wrong:
trace, app([3,2],[3,5],X).
Call: (9) app([3, 2], [3, 5], _7426) ? creep
Call: (10) 3 is 3 ? creep
Exit: (10) 3 is 3 ? creep
Call: (10) _7736 is 3 ? creep
Exit: (10) 3 is 3 ? creep
Call: (10) app([2], 5, 3) ? creep
Call: (11) app([], 5, 3) ? creep
Exit: (11) app([], 5, 3) ? creep
Exit: (10) app([2], 5, 3) ? creep
Exit: (9) app([3, 2], [3, 5], [3|3]) ? creep
X = [3|3].
where I m wrong?
I think you're trying to do a sublist/2 predicate:
%! sublist(Sub, List)
% is true if Sub is a list that occurs in
% some position in List
sublist(Sub, List) :-
% first partition off some tail of the list
append(_Prefix, Tail, List),
% then get some prefix of the tail, this is a sublist
append(Sub, _TailTail, Tail).
There's more ways to do this, but I think append/3 is simple to
understand. This is a different problem from member/2, which is finding elements in a list, here our problem is to carve up a list into chunks, hence the very different implementation than you see in member/2. You'll often find in Prolog the first step to a solution is to define the problem well. Good luck in your Prolog learning.

Maximum Subarray (Kadane's algorithm) - Tail recursion

i am trying to implement Kadane's Algorithm in Prolog.
One of the requirements is a tail call (recursion).
I have tried many possibilities but without success.
Here is my code:
max_sum(L, S) :-
S is 0,
H is 0,
max_sum(L, H, S).
max_sum([], S, S).
max_sum([X | L], H, S) :-
( H + X < 0 -> NewH is 0; NewH is H + X),
( S < H + X -> NewS is NewH; NewS is S),
length(L, N),
( N < 1 -> max_sum(L, NewS, NewS); max_sum(L, NewH, NewS)).
NewH, NewS are temp values (we cant assign a value twice in Prolog right?).
Can i ask for a hint?
Edit:
[trace] ?- max_sum([1, 2, 3], S).
Call: (7) max_sum([1, 2, 3], _G8907) ? creep
Call: (8) _G8907 is 0 ? creep
Exit: (8) 0 is 0 ? creep
Call: (8) _G8991 is 0 ? creep
Exit: (8) 0 is 0 ? creep
Call: (8) max_sum([1, 2, 3], 0, 0) ? creep
Call: (9) 0+1<0 ? creep
Fail: (9) 0+1<0 ? creep
Redo: (8) max_sum([1, 2, 3], 0, 0) ? creep
Call: (9) _G8994 is 0+1 ? creep
Exit: (9) 1 is 0+1 ? creep
Call: (9) 0<0+1 ? creep
Exit: (9) 0<0+1 ? creep
Call: (9) _G8997 is 1 ? creep
Exit: (9) 1 is 1 ? creep
Call: (9) length([2, 3], _G8998) ? creep
Exit: (9) length([2, 3], 2) ? creep
Call: (9) 2<1 ? creep
Fail: (9) 2<1 ? creep
Redo: (8) max_sum([1, 2, 3], 0, 0) ? creep
Call: (9) max_sum([2, 3], 1, 1) ? creep
Call: (10) 1+2<0 ? creep
Fail: (10) 1+2<0 ? creep
Redo: (9) max_sum([2, 3], 1, 1) ? creep
Call: (10) _G9000 is 1+2 ? creep
Exit: (10) 3 is 1+2 ? creep
Call: (10) 1<1+2 ? creep
Exit: (10) 1<1+2 ? creep
Call: (10) _G9003 is 3 ? creep
Exit: (10) 3 is 3 ? creep
Call: (10) length([3], _G9004) ? creep
Exit: (10) length([3], 1) ? creep
Call: (10) 1<1 ? creep
Fail: (10) 1<1 ? creep
Redo: (9) max_sum([2, 3], 1, 1) ? creep
Call: (10) max_sum([3], 3, 3) ? creep
Call: (11) 3+3<0 ? creep
Fail: (11) 3+3<0 ? creep
Redo: (10) max_sum([3], 3, 3) ? creep
Call: (11) _G9006 is 3+3 ? creep
Exit: (11) 6 is 3+3 ? creep
Call: (11) 3<3+3 ? creep
Exit: (11) 3<3+3 ? creep
Call: (11) _G9009 is 6 ? creep
Exit: (11) 6 is 6 ? creep
Call: (11) length([], _G9010) ? creep
Exit: (11) length([], 0) ? creep
Call: (11) 0<1 ? creep
Exit: (11) 0<1 ? creep
Call: (11) max_sum([], 6, 6) ? creep
Exit: (11) max_sum([], 6, 6) ? creep
Exit: (10) max_sum([3], 3, 3) ? creep
Exit: (9) max_sum([2, 3], 1, 1) ? creep
Exit: (8) max_sum([1, 2, 3], 0, 0) ? creep
Exit: (7) max_sum([1, 2, 3], 0) ? creep
In Call(11) i have a good result (6) from this simple example. How can I end the function at this point without returning? It is my problem.
Result from this code is S = 0, not S = 6.
Final edit (working code):
max_sum(L, S) :-
max_sum(L, 0, 0, S).
max_sum([], _, S, S).
max_sum([X | L], H, F, S) :-
NewH is max(0, H + X),
(F < H + X -> NewF is NewH; NewF is F),
max_sum(L, NewH, NewF, S).
Where:
S - final result,
F - maximum_so_far,
H - maximum_ending_here,
X - head of list,
L - list,
NewH, NewF - temp values.
Thanks for the help :)
This question is, in fact, a duplicate of
"Finding the maximum sublist in Prolog".
There is a bounty is offered for it, so it cannot be flagged as a duplicate.
I propose using my previous solution—it is based on clpfd and runs with SWI-Prolog.
I propose a slightly altered version of the solution proposed by #repeat:
:- use_module(library(clpfd)).
zs_max([Z|Zs], MSF) :-
zs_max_(Zs, Z, Z, MSF).
zs_max_([], _, MSF, MSF).
zs_max_([Z|Zs], MEH0, MSF0, MSF) :-
max(Z, MEH0+Z) #= MEH1,
max(MSF0, MEH1) #= MSF1,
zs_max_(Zs, MEH1, MSF1, MSF).
First, the sample queries from the original solution that yield the same results:
?- zs_max([-2,1,-3,4,-1,2,1,-5,4], Max).
Max = 6
?- zs_max([-2,3,4,-5,8,-12,100,-101,7], Max).
Max = 100
However this version is more general, in that it works with arbitrary values (as suggested by #false in the comment to solution). This is accomplished by starting with the value of the first element of the list instead of 0. Thus the following query yields a different result:
?- zs_max([-2,-3,-4], X).
X = -2
?- zs_maxmum([-2,-3,-4], X).
X = 0
Another difference is that the empty list has no solution:
?- zs_max([], X).
no
?- zs_maxmum([], X).
X = 0
I think this behaviour is more reasonable, as the empty list has no sublist and hence no sums of sublists from which to choose a maximum. However, if desired, a special case for the empty list can be easily added:
zs_max([], replaceThisWithAReasonableValue).
the standard way is to add an output parameter, that gets unified when the recursion stops. Something like
max_sum(L, S) :-
max_sum(L, 0, 0, S).
max_sum([], _, S, S).
...
Then, your code is way more complex than needed: both versions listed on Wikipedia don't require any test, or length/2 computation.
Try to simplify it leaving just the computation (you can use for instance Max_ending_here is max(0, H + X), and the tail recursive call.

how to trace a predicate in prolog?

This is a predicate that get permutations of a list. Can somebody explain to me how to trace this predicate? I am using SWI.
perm([H|T],L) :- perm(T,P) , insert(H,P,L).
perm([],[]).
insert(X,L,[X|L]).
insert(X,[H|T],[H|T1]) :- insert(X,T,T1).
Here's an example of using trace in SWI Prolog.
Entering the code:
?- [user].
|: perm([H|T],L) :- perm(T,P) , insert(H,P,L).
|: perm([],[]).
|:
|: insert(X,L,[X|L]).
|: insert(X,[H|T],[H|T1]) :- insert(X,T,T1).
|: % user://1 compiled 0.01 sec, 6 clauses
true.
Running a trace. Press "Enter" at the question marks ? to "creep" (take a step):
?- trace.
true.
[trace] ?- perm([1,2,3], L).
Call: (6) perm([1, 2, 3], _G366) ? creep
Call: (7) perm([2, 3], _G445) ? creep
Call: (8) perm([3], _G445) ? creep
Call: (9) perm([], _G445) ? creep
Exit: (9) perm([], []) ? creep
Call: (9) insert(3, [], _G446) ? creep
Exit: (9) insert(3, [], [3]) ? creep
Exit: (8) perm([3], [3]) ? creep
Call: (8) insert(2, [3], _G449) ? creep
Exit: (8) insert(2, [3], [2, 3]) ? creep
Exit: (7) perm([2, 3], [2, 3]) ? creep
Call: (7) insert(1, [2, 3], _G366) ? creep
Exit: (7) insert(1, [2, 3], [1, 2, 3]) ? creep
Exit: (6) perm([1, 2, 3], [1, 2, 3]) ? creep
L = [1, 2, 3]
As you might expect, this trace shows that perm calls itself recursively until it gets to the empty tail ([]) of the input list [1,2,3]. It then shows calls to insert which follow those recursive calls, along with the arguments occurring in those calls. The _Gnnn variables are uninstantiated arguments on a Call that gets instantiated in the clause which you see on the Exit.

Making a reverse list

I have the following codes. Trying to make a reverse list. but it doesnt work.
reverse([],[H|T]).
reverse([H|T],Z) :- reverse(T,[H|Z]).
I run this in prolog and I get this:
1 ?- trace, reverse([1,2,3],X).
Call: (7) reverse([1, 2, 3], _G396) ? creep
Call: (8) reverse([2, 3], [1|_G396]) ? creep
Call: (9) reverse([3], [2, 1|_G396]) ? creep
Call: (10) reverse([], [3, 2, 1|_G396]) ? creep
Exit: (10) reverse([], [3, 2, 1|_G396]) ? creep
Exit: (9) reverse([3], [2, 1|_G396]) ? creep
Exit: (8) reverse([2, 3], [1|_G396]) ? creep
Exit: (7) reverse([1, 2, 3], _G396) ? creep
true.
this should give me [3,2,1], instead of [1,2,3]. what is going wrong here??
When a list is empty, its reverse is empty.
So
reverse([], []).
In another case, you append the first element of the list at the end of the revese of the rest of the list. so :
reverse([H|T],Z) :-
reverse(T,Z1),
append(Z1, [H], Z).
You almost got it right. What you need is an "accumulator" which collects the result so far and passes it to the return variable at the end of the recursion:
reverse([],Z,Z).
reverse([H|T],Z,Acc) :- reverse(T,Z,[H|Acc]).
Otherwise the reversed list is forgotten as the function returns from the recursive calls. You need to instantiate the accumulator with an empty list when you call reverse/3:
?- reverse([1,2,3],X,[]).
If you do the trace you will see that the second argument does not get instantiated until your original list is empty.

Given [1,2,3] in prolog get back [6,5,3] by reverse accumalation

Q. Given [1,2,3] in Prolog get back [6,5,3] by reverse accumulation
I have the start code:
accumalate([H],[H]).
accumalate([H1 | H2], [Hnew, H2]),
Hnew is H1 + H2.
....
I am looking for basic Prolog solution.
We are not here to do you homework for you. So the best we can do is provide you with some tips. So ask yourself these questions:
What are the base cases here (for which inputs is the output immediate)?
You have accumulate([N], [N])., but what about empty lists?
In what order must the additions be performed?
More specifically, which elements must be added first?
Other than that, I can tell you that you can solve this using three clauses. No other predicates required. Good luck!
Bonus: you may want to define the head of the recursive clause as follows:
accumulate([N|T], [N1,N2|T2]).
Here is my take:
accumulate([],[]).
accumulate([H|T], [H1|T1]):-
sum([H|T],H1),
accumulate(T,T1).
sum([],0).
sum([H|T],Y):-
sum(T,Y1),
Y is H + Y1.
You can of course use a built-in sumlist/2 in place of the hand-crafted sum/2 if you prefer that.
Once you are done with the basic implementation , Try solving this problem in O(n) time. The idea is to start from the first element and keep on adding it to a secondary list till your original list is empty. The secondary list is the reverse list which you need.
If you append the two lists in your recursive step, you will end up having a O(N^2) complexity.
ac([], 0, []).
ac([H|T], ST, [ST|Res]) :-
ac(T, X, Res),
ST is H + X.
accum(List, Res) :-
ac(List, _, Res).
[trace] ?- accum([1,2,3], X).
Call: (6) accum([1, 2, 3], _G376) ? creep
Call: (7) ac([1, 2, 3], _G458, _G376) ? creep
Call: (8) ac([2, 3], _G461, _G454) ? creep
Call: (9) ac([3], _G464, _G457) ? creep
Call: (10) ac([], _G467, _G460) ? creep
Exit: (10) ac([], 0, []) ? creep
Call: (10) _G459 is 3+0 ? creep
Exit: (10) 3 is 3+0 ? creep
Exit: (9) ac([3], 3, [3]) ? creep
Call: (9) _G456 is 2+3 ? creep
Exit: (9) 5 is 2+3 ? creep
Exit: (8) ac([2, 3], 5, [5, 3]) ? creep
Call: (8) _G453 is 1+5 ? creep
Exit: (8) 6 is 1+5 ? creep
Exit: (7) ac([1, 2, 3], 6, [6, 5, 3]) ? creep
Exit: (6) accum([1, 2, 3], [6, 5, 3]) ? creep
X = [6, 5, 3].

Resources