Generate lists with independent variables in Prolog - prolog

I am having a problem while creating a list which I will the use to fill. I am trying to create it with independent variables, so that I can then unify with a maplist with some other lists.
For this, I did:
length(Subs, Len),
maplist(=([_, _, _]), Subs),
however, this results in this:
Subs = [[_22998, _23020, _23042], [_22998, _23020, _23042], [_22998, _23020, _23042]].
And so, when I try to unify the next way:
maplist(nth1(1), Subs, Com1),
maplist(nth1(2), Subs, Perm_sub),
maplist(nth1(3), Subs, Com3).
with:
Perm_sub = [5, 7, 6],
Com1 = [P23, P34, P36],
Com3 = [1, 3, 2].
It fails, because 5 unifies with _22998, and thus collides with 7. Is there a simple, elegant way of doing what I intend, or do I have to create a new function to handle this, and if so, how do I do the function?

You can create an auxiliary predicate as following:
triple([_, _, _]).
And ask:
?- length(L, 3), maplist(triple, L).
L = [[_2404, _2410, _2416], [_2422, _2428, _2434], [_2440, _2446, _2452]].
Alternatively, you can use a lambda expression as following:
?- length(L, 3), maplist([[_,_,_]]>>true, L).
L = [[_7198, _7204, _7210], [_7276, _7282, _7288], [_7354, _7360, _7366]].
EDIT 10/05/2021
Notice that variables used in a term are shared with their environment (they are "global", not lambda bound) and, consequently, they persist through all calls of maplist. For example, in the following query, variable X is instantiated with 1 and, after that, its value will persist through the next calls.
?- trace, maplist(=(X), [1,Y,1]).
^ Call: (11) apply:maplist(=(_1882), [1, _1892, 1]) ? creep
Call: (12) apply:maplist_([1, _1892, 1], user: =(_1882)) ? creep
Call: (13) _1882=1 ? creep
Exit: (13) 1=1 ? creep
Call: (13) apply:maplist_([_1892, 1], user: =(1)) ? creep
Call: (14) 1=_1892 ? creep
Exit: (14) 1=1 ? creep
Call: (14) apply:maplist_([1], user: =(1)) ? creep
Call: (15) 1=1 ? creep
Exit: (15) 1=1 ? creep
Call: (15) apply:maplist_([], user: =(1)) ? creep
Exit: (15) apply:maplist_([], user: =(1)) ? creep
Exit: (14) apply:maplist_([1], user: =(1)) ? creep
Exit: (13) apply:maplist_([1, 1], user: =(1)) ? creep
Exit: (12) apply:maplist_([1, 1, 1], user: =(1)) ? creep
^ Exit: (11) apply:maplist(user: =(1), [1, 1, 1]) ? creep
X = Y, Y = 1.
On the other hand, variables used as predicate arguments are "local" and their instantiations do not persist from one call to another. For example:
?- [user].
| equal(_X).
| ^Z
% user://1 compiled 0.02 sec, 1 clauses
true.
?- trace, maplist(equal, [1,Y,1]).
^ Call: (11) apply:maplist(equal, [1, _1752, 1]) ? creep
Call: (12) apply:maplist_([1, _1752, 1], user:equal) ? creep
Call: (13) equal(1) ? creep
Exit: (13) equal(1) ? creep
Call: (13) apply:maplist_([_1752, 1], user:equal) ? creep
Call: (14) equal(_1752) ? creep
Exit: (14) equal(_1752) ? creep
Call: (14) apply:maplist_([1], user:equal) ? creep
Call: (15) equal(1) ? creep
Exit: (15) equal(1) ? creep
Call: (15) apply:maplist_([], user:equal) ? creep
Exit: (15) apply:maplist_([], user:equal) ? creep
Exit: (14) apply:maplist_([1], user:equal) ? creep
Exit: (13) apply:maplist_([_1752, 1], user:equal) ? creep
Exit: (12) apply:maplist_([1, _1752, 1], user:equal) ? creep
^ Exit: (11) apply:maplist(user:equal, [1, _1752, 1]) ? creep
true.

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.

Draw a trace of prolog

I am learning to use prolog with lists and apply the trace command and draw the paper trace myself, but I do not understand very well how the debug does it with the lists (without lists if it is). I have the following example program.
p([X],X).
p([X|L],Y):-p(L,Y).
q([X,X]).
and I apply the query
p(V,2),q(V).
and what I get the baby for console is this
Call: (9) p(_612, 2) ? creep
Exit: (9) p([2], 2) ? creep
Call: (9) q([2]) ? creep
Fail: (9) q([2]) ? creep
Redo: (9) p(_612, 2) ? creep
Call: (10) p(_902, 2) ? creep
Exit: (10) p([2], 2) ? creep
Exit: (9) p([_900, 2], 2) ? creep
Call: (9) q([_900, 2]) ? creep
Exit: (9) q([2, 2]) ? creep
V = [2, 2] ;
and then a loop to infinity, but that does not matter to me because I do not know how to get the solution of V = [2, 2];
Making the appropriate substitutions so that they unify I obtain for the literal p (V, 2)
[X] = L
2 = X
[X | L] = V
[2 | L] = V
So what I want is to know the value of V, so I would have [2, [2]] and that can be translated into [2, 2]?
Then I would have to check it for the second literal q (V) that unifies, so it is a valid solution. Would this be your reasoning?

Prolog checking the same fact twice

This is the knowledge database
student(jack,100,21,m).
takes(100,cs01).
takes(100,cs02).
takes(100,cs03).
teaches(doe,cs01).
course(cs01,ai).
course(cs02,cpp).
course(cs03,java).
isTaughtBy(Sname,Lname) :-
teaches(Lname,Mcode),
student(Sname,Scode,_,_),
takes(Scode,Mcode).
When running isTaughtBy(jack,doe) it returns true (like its supposed to) and false (for some reason, probably because jack takes multiple modules).
This is the trace:
[trace] ?- isTaughtBy(jack,doe).
Call: (8) isTaughtBy(jack, doe) ? creep
Call: (9) teaches(doe, _18526) ? creep
Exit: (9) teaches(doe, cs01) ? creep
Call: (9) student(jack, _18526, _18528, _18530) ? creep
Exit: (9) student(jack, 100, 21, m) ? creep
Call: (9) takes(100, cs01) ? creep
Exit: (9) takes(100, cs01) ? creep
Exit: (8) isTaughtBy(jack, doe) ? creep
true ;
Redo: (9) takes(100, cs01) ? creep
Fail: (9) takes(100, cs01) ? creep
Fail: (8) isTaughtBy(jack, doe) ? creep
false.
Why is it redoing takes(100,cs01) if it was already checked above? Why is it returning false even though its clearly defined in the database? What am i not understanding here? I just want it to return true or false if a student is taught by a lecturer on any of the modules they are taking.

Prolog methods not calling base case

I am trying to build a program that takes two integers (for example, 4 and 15) and returns the multiples of the first integer that divide into the second integer.
My program is as follows:
divisible(D,U,X):-
divisible_ext(D,U,D,X).
divisible_ext(D,U,D,X):-
U < D,
!.
divisible_ext(D,U,S,X):-
U > D,
D1 is D + S,
divisible_ext(D1,U,S,X1),
X is D.
As far as I am aware, my program should fail the base case with each call until the D value is greater than U (so with 4 and 15, 16 > 15). However in the trace, I can see that the base case is only called the first time, and then never again. Thus when D = 16, the U > D call fails and the entire program fails.
Why is the base case only being called once? Is there something I am not understanding about Prolog that I need to know, or is there a change to my code that I should make?
Edit: Here is my trace:
[trace] 20 ?- divisible(4,15,X).
Call: (7) divisible(4, 15, _G9543) ? creep
Call: (8) divisible_ext(4, 15, 4, _G9543) ? creep
Call: (9) 15<4 ? creep
Fail: (9) 15<4 ? creep
Redo: (8) divisible_ext(4, 15, 4, _G9543) ? creep
Call: (9) 15>4 ? creep
Exit: (9) 15>4 ? creep
Call: (9) _G9622 is 4+4 ? creep
Exit: (9) 8 is 4+4 ? creep
Call: (9) divisible_ext(8, 15, 4, _G9625) ? creep
Call: (10) 15>8 ? creep
Exit: (10) 15>8 ? creep
Call: (10) _G9625 is 8+4 ? creep
Exit: (10) 12 is 8+4 ? creep
Call: (10) divisible_ext(12, 15, 4, _G9628) ? creep
Call: (11) 15>12 ? creep
Exit: (11) 15>12 ? creep
Call: (11) _G9628 is 12+4 ? creep
Exit: (11) 16 is 12+4 ? creep
Call: (11) divisible_ext(16, 15, 4, _G9631) ? creep
Call: (12) 15>16 ? creep
Fail: (12) 15>16 ? creep
Fail: (11) divisible_ext(16, 15, 4, _G9631) ? creep
Fail: (10) divisible_ext(12, 15, 4, _G9628) ? creep
Fail: (9) divisible_ext(8, 15, 4, _G9625) ? creep
Fail: (8) divisible_ext(4, 15, 4, _G9543) ? creep
Fail: (7) divisible(4, 15, _G9543) ? creep
false.
Why is the base case only being called once?
The base case is
divisible_ext(D,U,D,X) :-
and the other case is
divisible_ext(D,U,S,X) :-
Notice that on the first call
Call: (8) divisible_ext(4, 15, 4, _G9543) ? creep
divisible_ext(D, U, D, X) :- <-- Base case
divisible_ext(D, U, S, X) :- <-- Other case
For the base case D = 4 for both D and
for the other case D = 4 and S = 4
so both predicates can be called.
Notice on the second call
Call: (9) divisible_ext(8, 15, 4, _G9625) ? creep
divisible_ext(D, U, D, X) :- <-- Base case
divisible_ext(D, U, S, X) :- <-- Other case
For the base case D = 8 and D = 4 and
for the other case D = 4 and S = 4
so the base can not be called because the first D is now 8 and second D is 4 which means the unification will not work and thus the predicate can not be called.

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.

Resources