I'm having a little trouble understanding list recursion and modification in Prolog. I'm trying to take a list of lists, then with each list, multiply each element in the list by the last element.
Here's a snippet of my code:
/*Find the last element of a list*/
lastelement(X,[X]).
lastelement(X,[_|L]) :- lastelement(X,L).
/*Multiply two lists together*/
multiplication(M1,M2,M1*M2).
/*Take a list, find the last element and multiply every part of that list by that element*/
/*Attach modified list to X*/
modifyL([],X) :- X is [].
modifyL([First|Tset],X) :- lastelement(Y,First),
multiplication(Y,First,MFirst),
modifyL([Tset],X),
append(X,MFirst,X).
When I try any list of lists, however, all I get is false. Can someone give me any pointers
on list recursion that could help further understand this problem?
modifyL([],X) :- X is [].
This doesn't do what you think, is is used to get the result of an arithmetic evaluation.
you can write
modifyL([],X) :- X = [].
or simply
modifyL([],[]).
When you work with a list, and you repeat the same process to each element of this list you can use maplist which is exactly design for that.
the template is maplist(Goal, L1 L2).
modify(L1, L2) :-
maplist(multiply_one_list,L1, L2).
multiply_one_list works with a list, you it can be written like that :
multiply_one_list(L_in, L_out) :-
% getting last argument
reverse(L_in, [Last | _]),
% multiply each element of the list by
% the last element, one more maplist !
maplist(multiply_one_element(Last), L_in, L_out).
multiply_one_element(Last, In, Out) :-
Out is In * Last.
Related
I have a certain list which is generated from a predicate and looks like this:
[a, b, c]
I also have a following predicate p/3 that could be applied to each element of my list:
?- p(a, NewList, Number).
and it will return:
NewList = [c, d],
Number = 2.
where NewList is a newly generated list from a element, and Number is the NewList length.
Problem:
I want to apply the p/3 predicate to all elements, and get
one list which consists of all elements from all NewLists aka all NewLists appended together
and the sum of all Numbers.
I tried to do it like this:
loop_list([Element|[]], NewList, Number) :-
p(Element, NewList, Number).
loop_list([Head|Tail], [Tmp|NewList], Number) :-
loop_list(Tail, Tmp, Number).
but failed.
It is often better to separate your concerns, and solve one task at once. You can use maplist/4 [swi-doc] here to call the predicate over all the elements in the list. This will then unify the third and the fourth element with the results of p/3.
Next we can make use of append/2 [swi-doc] to append lists together, and sumlist/2 [swi-doc] to sum the elements of a list together.
We thus can implement this as:
loop_list(Ls, Xs, Sum) :-
maplist(p, Ls, Xss, Items),
append(Xss, Xs),
sumlist(Items, Sum).
So I have the simple predicate defined as
pred(Info, List, Result) :-
maplist(pred_calculate(Info), List, Result).
pred_calculate returns a list of X elements after an operation on a element of list, so for example pred_calculate(Info, List, Result) would return something like [2,3,5]
I want to add all the results of applying the pred_calculate predicate to all the elements of List, the problem I'm running into is that at the moment it's adding all the results from pred_calculate as sublists instead of adding to the single main list only.
So at the moment Result returns
[[2,3,5],[5,7,8],[8,9,11]] when it should return only [2,3,5,5,7,8,8,9,11]
How would I go about changing it to fix this behaviour?
When using foldl/4 with append/3, you have to pass the arguments in the correct order to append, if the order of the items is important1:
pred(Info, List, Result) :-
maplist(pred_calculate(Info), List, List1),
foldl([A, B, C] >> append(B, A, C), List1, [], Result).
Also, flatten/2 would achieve the same result, i.e.:
pred(Info, List, Result) :-
maplist(pred_calculate(Info), List, List1),
flatten(List1, Result).
1: foldl(append, List1, [], Result) would give you [8,9,11,5,7,8,2,3,5] as result.
maplist calls pred_calculate(Info) on every corresponding element of List and Result. Perhaps maplist is not what you really want to use here if pred_calculate results in a list on each call since it's not a 1-1 correspondence. You have a 1-to-many and you want the many in one big, flat list. You could use flatten or fold as !joel76 suggests. Or, you could "manually" write your own maplist-like predicate which is very simple - just a basic list recursion and probably using append to achieve each step:
pred(Info, List, Result) :-
pred(Info, List, [], Result).
pred(Info, [], Result, Result).
pred(Info, [H|T], Acc, Result) :-
pred_calculate(Info, H, R),
append(Acc, R, Acc1),
pred(Info, T, Acc1, Result).
I'm new Prolog and I'm stuck at this point.
How can I get the Head of this sorted list?
mylist(List,First) :-
sort(List, Sorted),
mylist(Sorted,First).
mylist([H|_],H).
You unify the sorted list with [First|_]:
mylist(List,First) :-
sort(List,[First|_]).
So now Prolog will unify the right operand of sort/2 with [First|_]. This means that if you call with mylist([1,4,2,5],F), Prolog will call sort([1,4,2,5],[F|_]). Now Prolog will sort the list to [1,2,4,5] and unify [1,2,4,5] = [F|_]. Which succeeds since [1,2,4,5] = [1|[2,4,5]]. So F = 1 and the wildcard is [2,4,5].
Note that the predicate will only succeed, if the second argument of sort/1 is a list with at least one element.
You can also use that First to do further processing. If you need both a reference to the sorted list and its head you can use:
mylist(List,First) :-
sort(List,Sorted),
Sorted = [First|_],
%% further processing with Sorted and First.
I have two predicates in Prolog, the first one does return a correct dot product of two lists(vectors w/e) ... the second is when you take a list times a list of lists(matrix) which will return a list. The second one fails when I try to pass anything such as ([1,2],[[3,4],[5,6],[7,8]], X). Anyone well versed in Prolog see my mistake? I am kinda stuck since tracing and prolog itself just returns a fail all the time.
getDotProd([],[],0.0).
getDotProd([H1|T1],[H2|T2], N):-
getDotProd(T1,T2,N1),
N is N1 + (H1 * H2).
vecTimesMatrix(_,[[]],[]).
vecTimesMatrix([List], [MH|Mtail],[N]):-
N is getDotProd(List, MH, _),
vecTimesMatrix(List, Mtail, N).
Updated Code thus far now:
getDotProd([],[],0.0).
getDotProd([H1|T1],[H2|T2], N):-
getDotProd(T1,T2,N1),
N is N1 + (H1 * H2).
vecTimesMatrix([],[[]],[]).
vecTimesMatrix([List], [MH|Mtail],[N]):-
getDotProd(List, MH, N),
vecTimesMatrix(List, Mtail, N).
Your remaining problem is in your vecTimesMatrix predicate:
vecTimesMatrix([],[[]],[]).
vecTimesMatrix([List], [MH|Mtail],[N]):-
getDotProd(List, MH, N),
vecTimesMatrix(List, Mtail, N).
Issues:
In the second clause, the first argument is given as [List] which would imply a list of a single element (List). Subsequent calls to getDotProd and vecTimesMatrix in the clause indicate that this should simply be List.
In the second clause, the third argument is shown simply as a list of one argument: [N]. So the third argument never "builds" a list. Additionally, the recursive call to vecTimesMatrix has N as its third argument, and that argument had already been instantiated by the prior query to getDotProd as the dot product of the vector List and the vectory MH. Logically, the recursive call should be saying that the vector product of List with Mtail is the tail of the final product.
The base case assumes that the first argument reduces to [], but this is not so. List always remains as-is throughout the recursive process. So instead of [] you should have _ (it will keep its value, but you don't care about it in the base case).
The base case has as a second argument [[]], but that's not the correct form for an empty list. That's actually a list consisting of one element, that element being the empty list. In reality, even though the second argument is a "list of lists", the empty list is still [].
Putting it all together (and renaming predicates per de facto conventions using underscores rather than camel case):
get_dot_prod([], [], 0.0). % Dot product of empty vectors is 0.0
% (Dot prod of vectors of unequal length
% is not defined and will fail)
get_dot_prod([H1|T1], [H2|T2], N) :- % N is dot product of [H1|T1] [H2|T2] if...
get_dot_prod(T1, T2, N1), % N1 is dot product of T1 T2, and
N is N1 + (H1 * H2). % N is N1 + (H1*H2) [evaluated]
vec_times_matrix(_, [], []). % Product of any vector with
% empty matrix is empty
vec_times_matrix(List, [MH|Mtail], [N|Ntail]):-
% [N|Ntail] is List x [MH|Mtail] if...
get_dot_prod(List, MH, N), % N is dot product of List and MH, and
vec_times_matrix(List, Mtail, Ntail). % Ntail is List x Mtail
This will yield:
| ?- vec_times_matrix([1,2],[[1,0],[0,1]], M).
M = [1.0,2.0] ? a
no
| ?- vec_times_matrix([1,2],[[1,0],[0,1],[1,1]], M).
M = [1.0,2.0,3.0] ? a
(1 ms) no
I added the comments in the code above to illustrate, in a simple way, how to think of the prolog predicate logic, which aids in defining them. As was pointed out already, the prolog "predicate" doesn't act as a "function". It describes a logical relation between entities which will either succeed or fail.
Once you learn to think how prolog thinks (relationally), you'll find it more enjoyable. :)
There are several problems in your code. First, you define both getDotProd/4 and getDotProd/3 predicates. The first one is a typo. I.e. you base case for the getDotProd/3 predicate have a duplicated argument and it should be:
getDotProd([], [], 0).
Second, in the second predicate, vecTimesMatrix/3, you have a goal, a call to the built-in predicate is/2, that will cause an exception:
N is getDotProd(List, MH, _)
You cannot define your own functions on standard Prolog. You need to replace that goal with:
getDotProd(List, MH, N)
There are other problems but this should help you progress.
I have a problem with my prolog code. I need to reverse all atomic elements of list.
Example: [1,2,[3,4]] -> [[4,3],2,1]
My solution:
myReverse([], []).
myReverse([H|T], X) :- myReverse(T, RT), myAppend(RT, H, X).
But it only gives me: [[3,4],2,1]
I think, I need to use is_list function and recursive call list if it's not atomic... but I am stuck... do you guys know how to write it?
Nearly. Consider this solution:
myReverse([], []) :- !.
myReverse([H|T], X) :-
!,
myReverse(H, NewH),
myReverse(T, NewT),
append(NewT, [NewH], X).
myReverse(X, X).
The first clause is the base case, which includes a cut (!) to exclude choices left because of the last clause.
The second clause reverses the head H, which may be an atom or a list. If H is an atom, the recursive subgoal after the cut evaluates with the last clause, and atoms are passed through unchanged. If H is a list, it is evaluated with the second clause and all elements are reversed. The next subgoal does the same with the remainder of the list (the tail, T), then are finally concatenated using the built-in append/3. Note that the new head element NewH is singular, so needs to be added to a singleton list structure as [NewH] as per the definition of append/3 which operates on lists.
The last clause passes all other things (i.e., atoms, numbers, etc. - anything that isn't a list or a variable) through unchanged.
revall(L, Y) :-
revall(L, [], Y).
revall([], Y, Y).
revall([H|T], T2, Y) :-
is_list(H),!,
revall(H, Hr),
revall(T, [Hr|T2], Y).
revall([H|T], T2, Y) :-
revall(T, [H|T2], Y).
here without append