Prolog List Neighbour of a Element - list

I am having problems with list of prolog. I want to make this:
[1,2,3,4,5]
[5,6,9,12,10]
You take a number for example 3, and you do a plus operation with the neighbours so the operation is 2+3+4 = 9. For the first and the last element you pretend there is an imaginary 1 there.
I have this now:
sum_list([A,X,B|T], [Xs|Ts]):-
add(A,X,B,Xs),
sum_list([X,B|T], Ts).
I haven't consider the first and the last element. My problem is I don't know how to get the element before and the next and then how to move on.
Note: I not allow to use meta-predicates.
Thanks.

I'm not sure how you calculated the first 5. The last 10 would be 4 + 5 + implicit 1. But following that calculation, the first element of your result should be 4 instead of 5?
Anyways, that doesn't really matter in terms of writing this code. You are actually close to your desired result. There are of course multiple ways of tackling this problem, but I think the simplest one would be to write a small 'initial' case in which you already calculate the first sum and afterwards recursively calculate all of the other sums. We can then write a case in which only 2 elements are left to calculate the last 'special' sum:
% Initial case for easily distinguishing the first sum
initial([X,Y|T],[Sum|R]) :-
Sum is X+Y+1,
others([X,Y|T],R).
% Match on 2 last elements left
others([X,Y],[Sum|[]]) :-
Sum is X+Y+1.
% Recursively keep adding neighbours
others([X,Y,Z|T],[Sum|R]) :-
Sum is X+Y+Z,
others([Y,Z|T],R).
Execution:
?- initial([1,2],Result)
Result = [4,4]
?- initial([1,2,3,4,5],Result)
Result = [4, 6, 9, 12, 10]
Note that we now don't have any cases (yet) for an empty list or a list with just one element in it. This still needs to be covered if necessary.

Related

Define the predicate maxlist( List, Max) so that Max is the greatest number in the list of numbers List

Exercise 3.17 “ Prolog Programming for Artificial Intelligence” by
Ivan Btrako
I understand the max predicate, but I'm having trouble tracing the maxList one. I'm trying to write the logic in pseudocode to help me out
Take first and second elements and compare them and get the
maximum
Take that maximum and compare it with third element in
list and if it's bigger overwrite the maximum and repeat again till
list is empty.
I don't understand the solution given however, and I tried tracing it and failed. I'm having trouble mapping the MaxRest to the Max & with the base case. Also, I don't understand why prolog doesn't give an error when unifying [X,Y|Rest] with [Y|T]. Example [1,3,[7,2]] with [3|[7,2]].
max(X,Y,X):-
X>=Y.
max(X,Y,Y):-
X<Y.
maxlist( [X], X). %what does this line do?
maxlist( [X,Y|Rest], Max):-
maxlist( [Y|Rest], MaxRest),
max(X, MaxRest,Max).
Any help tracing would be greatly appreciated.
Since you understand max/3 this won't explain it.
maxlist( [X], X). %what does this line do?
maxlist( [X,Y|Rest], Max):-
maxlist( [Y|Rest], MaxRest),
max(X, MaxRest,Max).
This is a classic recursive list pattern that does the recursion before processing the item. The normal recursive list pattern with a tail-call is
process_list([H|T],R) :-
process_item(H,R),
process_list(T,R).
process_list([],R).
but here it is
process_list([H|T],R) :-
process_list(T,R),
process_item(H,R).
process_list([],R).
where the item is processed after recursing through the list.
Also this processes two items at a time, i.e.
[H1,H2|T]
because the compare needs two items.
This
maxlist( [X,Y|Rest], Max):-
maxlist( [Y|Rest], MaxRest),
is just taking the values off of the list and pushing them onto the stack so that when it backtracks it will have one value for the comparison, i.e. MaxRest which is the max of all the values that were in Rest and the current value which is X. You might think it should be Y, but when there is just one item in the list, the list is actually [Y|[]] which is really [Y] with matches with the pattern in this clause maxlist( [X], X)..
So what does maxlist( [X], X). do? A common base case for a list is just predicate([],R). for returning a list, but in this case the last value alone needs to be returned as a value, so this takes X out of the list in the first parameter and returns it as a value in the second parameter so that it becomes MaxRest which is the max value when there is only one item in the list. When max(X, MaxRest,Max) is executed it has a value for MaxRest return from backtracking, and X on the stack when deconstructing the list. The result is Max which is returned as the third parameter in maxlist( [X,Y|Rest], Max) which becomes the value for MaxRest upon backtracking again.
Ask questions if that doesn't make sense.
I don't understand why Prolog doesn't give an error when unifying
[X,Y|Rest] with [Y|Rest].
Example [1,3,[7,2]] with [3|[7,2]]
Actually
?- [1,3,[7,2]] = [3|[7,2]].
false.
so while your example does give an error, it is not what is being done with
[X,Y|Rest] and [Y|Rest]
Start with the list [1,2,3,4] and unify it with[X,Y|Rest]
?- [1,2,3,4] = [X,Y|Rest].
X = 1,
Y = 2,
Rest = [3, 4].
Notice that [Y|Rest] would then be [2|[3,4]].
?- [1,2,3,4] = [X,Y|Rest],A = [Y|Rest].
X = 1,
Y = 2,
Rest = [3, 4],
A = [2, 3, 4].
Don't try an unify [X,Y|Rest] with [Y|Rest] but instead unify Rest with Rest and Y with Y, X is stored on the stack but not passed to next level of the stackframe.
If you really want to understand list then use this to see them
?- write_term([1,2,3,4],[dotlists(true)]).
.(1,.(2,.(3,.(4,[]))))
true.
If you have Version 4 of the book see Figure 3.1 on page 61.
Prolog predicates define relations in terms of logic that says that the head of the clause is true if (:-) the body is true. This helps you properly read a predicate:
max(X,Y,X):-
X>=Y.
This says that:
X is the maximum of X and Y if X >= Y is true.
You can similarly read the clause for max(X,Y,Y).
Now look at:
maxlist( [X], X).
Here, we're defining maxlist to mean the maximum value of a list. This particular clause says that:
X is the maximum value of the list [X].
There are no if conditions (:-) in this case since no other conditions are necessary to establish this rule.
Then there is the recursive clause:
maxlist( [X,Y|Rest], Max):-
maxlist( [Y|Rest], MaxRest),
max(X, MaxRest,Max).
This says that:
Max is the maximum value of list [X,Y|Rest] if MaxRest is the maximum of list [Y|Rest] and Max is the maximum value of X and MaxRest.
This recursive clause and the prior base case clause completely define maxlist. If you read through that carefully, it should seem completely logical.
I don't understand why prolog doesn't give an error when unifying [X,Y|Rest] with [Y|T]
I don't understand this comment. Nowhere in your code does Prolog attempt to unify these two terms. Your example terms of [1,3,[7,2]] and [3|[7,2]] would not unify because the first is a list of three elements: 1, 3, and [7,2], whereas the other is a list of 3 elements: 3, 7, and 2. For two lists to be unifiable, it not only needs to be the same length, but each corresponding term in the list must be unifiable.
What would then make [X,Y|Rest] and [Y|T] unifiable? You can write [X,Y|Rest] as [X|[Y|Rest]], which makes it easy to see that these are unifiable if the following are true:
X = Y,
[Y|Rest] = T
In other words, the lists have to have (a) at least two elements, and (b) the first two elements are the same.

Prolog list consecutive pairs

If I have a list [1,2,3,4,5], how can I get consecutive pairs and perform an operation on them? For example, I want to get (1,2) and perform doSomething on them. In the next iteration, I want to get (2,3), and so on. This is what I have so far:
listpairs([H1,H2|T]):-doSomething(H1,H2), listpairs([H2,H3|T]).
I can do the first iteration but I'm stuck when comparing H2 and H3.
Firstly, if you've got [1,2,3,4,5], then [H1,H2|T] sets H1 = 1, H2 = 2, T = [3,4,5]. H1 and H2 are the two numbers you want to work on. [H2|T] = [2,3,4,5] makes the list that you can proceed to calculate on. (It starts with 2,3 after all, so recursing on it will give you the two next numbers you want.)
So your recursive case should be:
listpairs([H1,H2|T]) :- doSomething(H1,H2), listpairs([H2|T]).
I.e.: Take H1 and H2 out, do something with them, then put H2 back and recurse.
Secondly, you need a base case for only having one element left:
listpairs([H]).
If you omit this, you'll never reach a base case if the list has e.g. 5 elements, since we always put 1 back. (I.e., the list you recurse on will never be empty.)
instead of an explicit 'loop', you could use this idiomatic approach:
forall(append(_,[X,Y|_],List), doSomething(X,Y)).

Summing the first value in each tuple in a list over a specific range in Python

My question is based on an earlier question and I can't find to figure out (nor find) the subsequent step I need.
Say I do have the same list of tuples, namely:
[(0, 1), (2, 3), (5, 7), (2, 1)]
Also I wish to find the sum of the first values in each pair, which could be done by the simple pythonic:
sum([pair[0] for pair in list_of_pairs])
as provided by David Z. However, in my case I only wish to sum from the first first value up until a following first value, say the first value at index N = 2.
Thus, only calculate the sum of:
0 + 2 + 5
I have been trying things like:
sum([pair[0] for pair in list_of_pairs[:N])
but without success. Can anyone provide me with an elegant solution?
you were very close to the solution
This works for me :
N=2
sum([pair[0] for pair in list_of_pairs[0:N+1]])
If you wants from middle then you can do this :
N=3
M=1
print sum([pair[0] for pair in list_of_pairs[M:N+1]])

Merge alternate elements from two lists in Prolog

I need to write a Prolog predicate mergealt(X,Y,Z) that succeeds if the list Z is a merger of alternate elements from the lists X and Y.
The input and output will like below:
?- mergealt([1,2,3,4],[6,7,8],Z).
Z = [1, 7, 3] .
?- mergealt([1,2,3,4],[6,7,8,9],Z).
Z = [1, 7, 3, 9] .
?- mergealt([1,2,3,4],[6,7,8,9,10],Z).
Z = [1, 7, 3, 9] .
I don't really understand recursion. How can I get started on this problem?
Prolog can be considered the 'flagman' of declarative languages.
So try to describe your problem, top down:
mergealt(X, Y, Z) :-
'take first element from X and put it in Z',
'discard first element from Y',
'mergealt rest-of-X and rest-of-Y, but exchange them'.
First step can't be accomplished if there are no elements in X.
This fact highlights the recursion termination case. Originally, Prolog didn't used if then else, instead alternatives are stated as different rules:
mergealt([], _Y, []).
Here you can see that pattern matching on first argument it's the key to distinguish alternatives, and contextually, Z get bound to an empty list. Y is unused, so it's marked as anonymus place holder, just to avoid a warning.
Then this simpler case suggests that we should use pattern matching to accomplish those verbose descriptions. See if you can complete the procedure with these guidelines:
mergealt([X|Xs], Y, [X|Zs]) :-
% take first element from X and put it in Z : done in the head
% discard first element from Y : see below
% mergealt rest-of-X and rest-of-Y, but exchange them'. : make your recursive call
discard_first_element([_|Rest], Rest).
% why is this necessary? do you see where it fails if we don't specify this case?
discard_first_element([], []).
Notice that the result always starts with the first element of the first list.
This means that, if the first list is empty, you know the answer right away.
Also notice that, if it isn't empty, we already know the first item of the result, so we need to use mergealt to compute the rest. But "the rest" will have the second item of the second list as the first item of the result, and as we said above, that means that a call to mergealt to compute it would have to have that be the first item of the first list (yeah, this is the tricky part).

Prolog list adding

--the question has been edited--
Using this data, I need to create a list:
team(milan,1).
team(napoli,2).
team(lazio,3).
team(roma,4).
team(inter,4).
team(juventus,5).
So, given a query like:
check([milan,lazio,roma,inter]).
make a new list with their respective team number.
X=[1,3,4,4]
What I'm trying to do is creating a list, adding elements one at a time.
check([H|T]) :-
team(H,R),
append([R],_, X),
check(T).
Could someone help me complete this?
You need to find all the team numbers for which the name of the team is a member of the list of team names that you are interested in:
?- findall(Number, (
team(Name, Number),
member(Name, [milan, lazio, roma, inter])), Numbers).
Numbers = [1, 3, 4, 4].
To return the numbers in a given order, just apply member/2 before team/2, in this case member/2 generates names (in the given order), and team/2 maps them to numbers:
?- findall(Number, (
member(Name, [lazio, milan, inter]),
team(Name, Number)), Numbers).
Numbers = [3, 1, 4].
A lot of time since I used Prolog but an answer -more or less- would look like:
check([]) :- true.
check([X]) :- team(X,_).
check([X,Y]) :- team(X,N), team(Y,M), N < M.
check([X,Y|T]) :- check(X,Y), check([Y|T]).
See this question for a very similar problem.
From what you say you might be better off making a list and then sorting it. That way you'd know the list is in order. Of course it's tricky in that you are sorting on the team ranks, not the alphabetic order of their names.
But the question you asked is how to check the list is in sorted order, so let's do it.
check([ ]). % just in case an empty list is supplied
check([_]). % singleton lists are also in sort order
check([H1,H2|T]) :-
team(H1,R1),
team(H2,R2),
R1 <= R2,
check([H2|T]).
Note that the recursion reduces lists with at least two items by one, so the usual termination case will be getting down to a list of length one. That's the only tricky part of this check.
Added in response to comment/question edit:
Sure, it's good to learn a variety of simple "design patterns" when you are getting going with Prolog. In this case we want to "apply" a function to each item of a list and build a new list that contains the images.
mapTeamRank([ ],[ ]). % image of empty list is empty
mapTeamRank([H|T],[R|S]) :-
team(H,R),
mapTeamRank(T,S).
So now you have a predicate that will turn a list of teams LT into the corresponding list of ranks LR, and you can "check" this for sorted order by calling msort(LR,LR):
check(LT) :-
mapTeamRank(LT,LR),
msort(LR,LR).