Multiplying two lists in prolog - list

I am currently working with prolog and want to multiply two lists together but in a certian way. For example:
[1,2,3] and [4,5,6] are my two lists.
I want to preform the following actions:
(1*4)+(2*5)+(3*6) = 32
Such that the first element of each list is multiplied to each other then added with the second elements multiplied together etc.
Is this possible to go in Prolog?
I know in other languages you can do a recursive function with takes the head of the list and the tail (the rest of the entries). This allows for a simple multiplication but I do not think that is possible in prolog?

Using built-ins:
mult(X, Y, Z) :- Z is X * Y.
sum_prod(A, B, SumProd) :-
maplist(mult, A, B, Prods),
sumlist(Prods, SumProd). % In GNU Prolog this is sum_list
Using simple recursion:
sum_prod([A|As], [B|Bs], SumProd) :-
sum_prod(As, Bs, SP),
SumProd is SP + A*B.
sum_prod([], [], 0).
Using tail recursion:
sum_prod(A, B, SumProd) :-
sum_prod(A, B, 0, SumProd).
sum_prod([A|As], [B|Bs], Acc, SumProd) :-
Acc1 is Acc + A*B,
sum_prod(As, Bs, Acc1, SumProd).
sum_prod([], [], Acc, Acc).

If all items of your lists are integers and your Prolog implementation offers clpfd, you can simply use the
clpfd built-in predicate scalar_product/4, like this:
?- scalar_product([1,2,3],[4,5,6],#=,Product).
Product = 32.
Edit:
You may also be interested in the related question "Prolog: Multiplying 2 lists with 1 of them not instantiated?", particularly in this answer.

as an alternative to 'hand coded' loops, using library(aggregate) and nth1/3:
sum_prod(A,B,S) :-
aggregate(sum(M), I^X^Y^(nth1(I,A,X), nth1(I,B,Y), M is X*Y), S).

Related

How to simplify algebra equations represented as list of list

With Prolog I want to simplify algebra expression represented as as list of list:
algebra equation
f = 3x+2
list of list
[[3,1],[2,0]]
3 and 2 are coefficients
1 and 0 are exponents
That should be obvious.
I am looking for some tips or suggestions on how to code the simplifications for this example:
f = 3x+2x+1+2
[[3,1],[2,1],[1,0],[2,0]]
simplified:
f = 5x+3
[[5,1],[3,0]]
I have tried some built in functions but did not get the proper idea about how to use them.
One liner, similar to what's proposed by joel76:
simplify(I,O) :-
bagof([S,E],L^(bagof(C,member([C,E],I),L),sum_list(L,S)),O).
The inner bagof collects C (coefficients) given E (exponents), the resulting list L is summed into S, and paired with E becomes [S,E], an element (monomial) of O.
If you omit the universal quantification specifier (that is L^) you get single monomials on backtracking.
You can solve your problem in this way:
simplify(_,_,S,S,[]):- !.
simplify(L,I,Sum,NTot,[[I,S]|T]):-
Sum =< NTot,
findall(X,member([X,I],L),LO),
length(LO,N),
S1 is Sum + N,
sum_list(LO,S),
I1 is I+1,
simplify(L,I1,S1,NTot,T).
write_function([]).
write_function([[D,V]|T]):-
write(' + '),write(V),write('x^'),write(D),
write_function(T).
test:-
L = [[3,1],[2,1],[1,0],[2,0]],
length(L,N),
simplify(L,0,0,N,LO),
LO = [[D,V]|T],
write('f='),write(V),write('x^'),write(D),
write_function(T).
The main predicate is simplify/5 which uses findall/3 to find all the coefficients with the same degree and then sums them using sum_list/2. Then you can write the result in a fancy way using write_function/1.
In SWI-Prolog You can use aggregate :
pred(>, [_,X], [_,Y]) :- X > Y.
pred(<, [_,X], [_,Y]) :- X < Y.
pred(=, [_,X], [_,X]).
simplify(In, Out) :-
aggregate(set([S,X]), aggregate(sum(P), member([P,X], In), S), Temp),
predsort(pred, Temp, Out).
For example :
?- simplify([[3,1],[2,1],[1,0],[2,0]], Out).
Out = [[5, 1], [3, 0]] ;
false.

Give as a solution every different number in a list of lists

I need to do a predicate, select(ListOfLists, X) that returns as a solution every different number in a list of lists, starting with the numbers that are alone in a list, for example:
select([[1,2,3],[1,2],[4],[3]],X).
Would return:
X = 4 ;
X = 3 ;
X = 2 ;
X = 1
Order doesn't matter as long as the numbers that are alone in the list are shown first.
To do this, first I coded 2 other predicates, which are:
%OrderedList is Lists ordered by size.
orderListsBySize(Lists, OrderedLists).
Example: orderListsBySize([[1,2],[6],[3,4,5]], L). ->L = [[6], [1,2], [3,4,5]]
And
%ListsWithoutX is Lists without the X elements
removeFromLists(X, Lists, ListsWithoutX).
Example: removeFromLists(1,[[1,2],[3],[4,1,5]],L). -> L = [[2],[3],[4,5]]
Both predicates work.
Then, to do the select(ListOfLists, X) predicate, I tried the following:
select([[X|[]]|_], X). select(L1,S) :-
orderListsBySize(L1, [[X|XS]|LS]),
length(XS, A),
A == 0,
select([[X|[]]|M], S),
removeFromLists(X, [XS|LS], M).
select([[X|_]|_], X).
But it doesn't work.
It's not a hard exercise to do in other languages, the problem is that it's still hard for me to understand how prolog works. I appreaciate any help, thanks!
You could start with:
select2(ListOfLists,Element):-
length(List,_Len),
member(List,ListOfLists),
member(Element,List).
Which will return all the answers, but then get stuck in a loop looking for ever bigger lists.
This can be averted using the :-use_module(library(clpfd)). and defining a fd_length/2 which wont keep looking for bigger lists then exist in the list of lists.
fd_length(L, N) :-
N #>= 0,
fd_length(L, N, 0).
fd_length([], N, N0) :-
N #= N0.
fd_length([_|L], N, N0) :-
N1 is N0+1,
N #>= N1,
fd_length(L, N, N1).
select(ListOfLists,Element):-
maplist(length,ListOfLists,Lengths),
sort(Lengths,SortedLength),
last(SortedLength,Biggest),
Biggest #>= Len,
fd_length(List,Len),
member(List,ListOfLists),
member(Element,List).
Example Query:
?-select([[1,2,3],[1,2],[4],[3]],X).
X = 4
X = 3
X = 1
X = 2
X = 1
X = 2
X = 3
false
If you want unique solutions, you could enclose in a setof/3 and then call member/2 again.

Prolog program won't compute variable answer?

This should be an easy fix, but I can't seem to tackle this, and it's getting frustrating. I've coded a program which computes or verifies that two lists are related because the elements of the second list are all incremented by one from the elements of the first list. This works when two lists are given, but not when it needs to compute a list.
Code is as follows:
inc([], []).
inc([X|XS],[Y|YS]) :-
Y =:= X+1,
inc(XS,YS).
ERROR: =:=/2: Arguments are not sufficiently instantiated
Any help would be greatly appreciated!
Your problem is essentially that =:=/2 is for testing rather than establishing bindings, though is/2 still doesn't really do what you want. For instance, while 2 is 1 + 1 is true, 2 is X+1 will not result in X being bound to 1, because is/2 expects there to be just one variable or value on the left and one expression on the right, and it does not behave "relationally" like the rest of Prolog. If you want arithmetic that behaves this way, you should check out clpfd; looking at the complexity it adds is a good explanation for why things are the way they are.
Fortunately, you don't need all of arithmetic to solve your problem. The succ/2 builtin will do exactly what you need, and bonus, you get a one line solution:
inc(X, Y) :- maplist(succ, X, Y).
In use:
?- inc([1,2,3], [2,3,4]).
true.
?- inc([1,2,3], X).
X = [2, 3, 4].
?- inc(X, [1,2,3]).
X = [0, 1, 2].
Your code also works fine if you use succ/2 instead of =:=/2:
inc([], []).
inc([X|XS],[Y|YS]) :-
succ(X, Y),
inc(XS,YS).
This must be the "easy fix" you suspected. :)
I'm not sure what #mbratch is referring to about there being "too many variables" for one predicate. I suspect this is a misunderstanding of Prolog on their part, perhaps a holdover from other languages where a function can return one value or something. There is no technical limitation here; predicates can take as many ground or nonground arguments and bind as many of them as you want; the limiting factor is your creativity.
Similarly, I don't think "asymmetry" is a meaningful concept here. It's quite normal to define predicates that have just a single instantiation pattern, but it's also normal and preferable to make predicates that are flexible about instantiation—you can't know ahead of time what uses may be needed in the future. You might think to yourself that an instantiation pattern that destroys information might preclude the inverse instantiation pattern, but in practice, frequently you can turn it into a generator instead.
To give a trite example, append/3's name seems to imply this pattern:
?- append([1,2], [3,4], X).
X = [1,2,3,4]
That's a perfectly good use, but so is:
?- append(X, Y, [1,2,3,4]).
This is a non-deterministic instantiation pattern and will produce five solutions:
X = [], Y = [1,2,3,4]
X = [1], Y = [2,3,4]
X = [1,2], Y = [3,4]
X = [1,2,3], Y = [4]
X = [1,2,3,4], Y = []
This seems to stand in contradiction to some of #mbratch's ideas, but there's no explicit testing for ground/nonground in the usual definition of append/3, because it isn't necessary, and likewise with the second calling pattern you get two "return values" from one input. SWI source:
append([], L, L).
append([H|T], L, [H|R]) :-
append(T, L, R).
Edit: Negative numbers. I forgot that succ/2 is defined only on positive integers. We can apply #mbratch's technique and still get a tidy solution with the desired properties:
isucc(X, Y) :- var(X), X is Y-1.
isucc(X, Y) :- Y is X+1.
inc(X, Y) :- maplist(isucc, X, Y).
In action:
?- inc(X, [-1,2]).
X = [-2, 1] ;
false.
Edit: Using clp(fd) (via #mat):
fdsucc(X,Y) :- Y #= X + 1.
inc(X, Y) :- maplist(fdsucc, X, Y).
This generates even for the most general query:
?- inc(X, Y).
X = Y, Y = [] ;
X = [_G467],
Y = [_G476],
_G467+1#=_G476 ;
X = [_G610, _G613],
Y = [_G622, _G625],
_G610+1#=_G622,
_G613+1#=_G625 ;
X = [_G753, _G756, _G759],
Y = [_G768, _G771, _G774],
_G753+1#=_G768,
_G756+1#=_G771,
_G759+1#=_G774
...
The utility of this is questionable, but presumably since you're using clp(fd) you'll eventually impose other constraints and get something useful.
inc([],[]).
inc([X|XS],[Y|YS]) :-
nonvar(X),
Z is X + 1,
Y = Z,
inc(XS,YS), !.
inc([X|XS],[Y|YS]) :-
nonvar(Y),
Z is Y - 1,
X = Z,
inc(XS,YS), !.
Here we need to get a real computation for the addition, then attempt instantiation with =. The predicate had to be split to deal with the case where X was not instantiated, versus when Y wasn't. The ! at the end of each is to prevent it from trying for more solutions after it has found one through one of the two similar paths.

Prolog-Multiplying a list with a list of lists

I'm trying to simulate a product of a matrix with a vector using these two predicates:
eva([], [], []).
eva([A|A1], [W], [Res|R1]) :-
vectormultiplication(A, W, Res),
eva(A1, W, R1).
vectormultiplication([A], [W], [A*W]).
vectormultiplication([A|A1], [W|W1], [A*W|Out1]) :-
vectormultiplication(A1, W1, Out1).
Where the [A|A1] in eva is a matrix (or a list of lists), [W] is a vector (a list),and [Res|R1] is the resulting product. vectormultiplication is supposed to go multiply each list in the list with the vector W. However, this strategy just produces a false response. Is there anything apparent that I'm doing wrong here that prevents me from getting the desired product? I'm currently using SWI Prolog version 5.10
you have 2 other problems apart that evidenced by Daniel (+1): here a cleaned up source
eva([], _, []). % here [] was wrong
eva([A|A1], W, [Res|R1]) :- % here [W] was wrong
vectormultiplication(A, W, Res),
eva(A1, W, R1).
vectormultiplication([A], [W], [M]) :-
M is A*W.
vectormultiplication([A|A1], [W|W1], [M|Out1]) :-
M is A*W,
vectormultiplication(A1, W1, Out1).
test:
?- eva([[1,2],[3,5]],[5,6],R).
R = [[5, 12], [15, 30]]
when handling lists, it's worth to use maplist if available
eva(A, W, R) :-
maplist(vectormultiplication1(W), A, R).
vectormultiplication1(W, A, M) :-
maplist(mult, A, W, M).
mult(A, W, M) :-
M is A*W.
Note I changed the order of arguments of vectormultiplication1, because the vector is a 'constant' in that loop, and maplist append arguments to be 'unrolled'.
Well, your first problem is that you think A*W is going to do anything by itself. In Prolog, that's just going to create the expression A*W, no different from *(A,W) or foo(A, W)--without is/2 involved, no actual arithmetic reduction will take place. That's the only real problem I see in a quick glance.

Prolog sum all the number in the list.

How to sum all odd positioned elements in a list
example [1,2,3,4,5,6,7,8,9] = 25
odd([],0].
odd([Z],Z).
odd([X,Y|T], Sum+1):- odd(T,Sum).
but it return me 1+3+5+7+9.
In prolog you have to use the is operator when you want to evaluate arithmetic expressions. Since you use the + symbol outside of an arithmetic scope it is not interpreted specially. This appears to be homework, so I'll give a simplified example:
add(A, B, C) :- C is A + B.
The code above adds A and B and stores the result in C.
What you construct when you write Sum+1 is a term with functor '+'/2 and arguments Sum and 1.
In Prolog, when you want to calculate a sum, you need to use the predicate is/2.
In your code, you should also add cuts to remove unnecessary choicepoints, and add X to the rest of the sum, not 1:
odd([],0) :- !.
odd([Z],Z) :- !.
odd([X,_|T],Sum):- odd(T,Sum0), Sum is Sum0+X.
Using an accumulator would allow you to make the code tail-recursive...
Get a list with the odd elements, then sum that list:
divide([], [], []).
divide([H|T], [H|L1], L2) :- divide(T, L2, L1).
sum(L, Sum) :- sum(L, 0, Sum).
sum([], Acu, Acu).
sum([H|T], Acu, Acu1) :-
Acu2 is Acu + H,
sum(T, Acu2, Acu1).
sum_odd(L, Sum) :-
divide(L, Odds, _),
sum(Odds, Sum).
:- sum_odd([1,2,5,6,8,9,1], Sum), writeln(Sum).
sum([],0).
sum([H|T],N) :-
sum(T,M), N is H + M.