2

I am thinking how to multiply all elements of two list with each other. Then I want to put all results in List3. For example,

List1 = [1,3,5].
List2 = [2,6,7]. 

List3should contain [1x2, 1x6, 1x7, 3x2, 3x6, 3x7, 5x2, 5x6, 5x7]. In the end;

List3 = [2, 6, 7, 6, 18, 21, 10, 30, 35].

Is it possible to do that? How to do that? I couldn't find a right way.

repeat
  • 18,496
  • 4
  • 54
  • 166
Shmn
  • 681
  • 1
  • 4
  • 22
  • 4
    Well, it is a Turing-complete language, so it must be possible –  May 19 '15 at 13:36
  • 1
    First, how could you multiply all elements of one list by one number ? Next, how could you use the former code to solve your problem ? – joel76 May 19 '15 at 13:42

5 Answers5

3

Here is a rather straight-forward solution using library(lambda)

product(Xs, Ys, Ps) :-
   maplist(Ys+\X^maplist({X,Ys}+\Y^YP^(YP=X*Y),Ys), Xs, PPs),
   append(PPs, Ps).

So we have an outer-loop for Xs and an inner loop for Ys.

?- product([1,2,3],[4,5,6],Ps).
   Ps = [1*4,1*5,1*6,2*4,2*5,2*6,3*4,3*5,3*6].

Replace (YP=X*Y) by (YP is X*Y) or (YP #= X*Y). Whatever you prefer.

false
  • 10,264
  • 13
  • 101
  • 209
3

Why not

prod(L1, L2, LP) :-
    bagof(P, X^Y^(member(X, L1), member(Y, L2), P is X * Y), LP).
joel76
  • 5,565
  • 1
  • 18
  • 22
  • "Why not": because it does not scale to constraints (in many implementations). – false May 20 '15 at 06:11
  • OK, I only SWI-Prolog ! – joel76 May 20 '15 at 06:45
  • 1
    In SWI, when replacing `is` by `#=`. Your definition with `prod([X],[Y],Zs)` correctly succeeds with `Zs = [_G1], X*Y #= _G1`, but incorrectly fails for `prod([X,X],[Y],Zs)`. These kinds of subtle errors make debugging a nightmare. – false May 20 '15 at 12:50
  • 2
    A maybe more convincing example: `prod([1,1],[2],Zs)` correctly succeeds with `Zs = [2,2]`. But `prod([1,1],[Y],Zs), Y = 2` while logically equivalent, now fails, because the first goal fails. – false May 20 '15 at 13:01
  • When I posted my code, I must say that I didn't think of all these problems ! I often forget that in Prolog, arguments can be unified or not before the call of the predicate. – joel76 May 20 '15 at 15:48
2

Use ! "Cross product"—shown here—is just one of many applications. Proceed like this:

:- meta_predicate xproduct(4,?,?,?).
xproduct(P_4,As) -->
   xproduct(P_4,As,As).

:- meta_predicate xproduct(4,?,?,?,?).
xproduct(P_4,As,Bs) -->
   xproduct_aux1(As,Bs,P_4).                % use 1st argument indexing for As

:- meta_predicate xproduct_aux1(?,?,4,?,?).
xproduct_aux1([]    ,_ , _ ) --> [].
xproduct_aux1([A|As],Bs,P_4) -->
   xproduct_aux2(Bs,[A|As],P_4).            % use 1st argument indexing for Bs

:- meta_predicate xproduct_aux2(?,?,4,?,?).
xproduct_aux2([],_,_) --> [].
xproduct_aux2([B|Bs],As,P_4) -->
   xproduct_(As,[B|Bs],P_4).

:- meta_predicate xproduct_(?,?,4,?,?).
xproduct_([],_,_) --> [].
xproduct_([A|As],Bs,P_4) -->
    xprod_(Bs,A,P_4),
    xproduct_(As,Bs,P_4).

:- meta_predicate xprod_(?,?,4,?,?).
xprod_([],_,_) --> [].
xprod_([B|Bs],A,P_4) -->
    call(P_4,A,B),
    xprod_(Bs,A,P_4).

Let's use and lambdas to run the query you provided in your question:

:- use_module([library(clpfd),library(lambda)]).

?- phrase(xproduct(\X^Y^[Z|Zs]^Zs^(Z #= X*Y),[1,3,5],[2,6,7]),Fs).
Fs = [2,6,7,6,18,21,10,30,35].

Above lambdas use explicitly; with phrase//1 we can also use them implicitly!

?- phrase(xproduct(\X^Y^phrase(([Z],{Z #= X*Y})),[1,3,5],[2,6,7]),Fs).
Fs = [2,6,7,6,18,21,10,30,35].

enables us to do very general queries. Thanks to @PauloMoura for his suggestion! Look!

?- phrase(xproduct(\X^Y^phrase(([Z],{Z #= X*Y})),As,Bs),
          [2,6,7,6,18,21,10,30,35]),
   maplist(labeling([]),[As,Bs]).
  As = [-2,-6,-7,-6,-18,-21,-10,-30,-35], Bs = [-1]
; As = [ 2, 6, 7, 6, 18, 21, 10, 30, 35], Bs = [ 1]
; As = [-1,-3,-5],                        Bs = [-2,-6,-7]
; As = [ 1, 3, 5],                        Bs = [ 2, 6, 7]
; As = [-1],                              Bs = [-2,-6,-7,-6,-18,-21,-10,-30,-35]
; As = [ 1],                              Bs = [ 2, 6, 7, 6, 18, 21, 10, 30, 35]
; false.
repeat
  • 18,496
  • 4
  • 54
  • 166
2

A simple solution not requiring any Prolog extensions (but, of course, loosing the potential benefits of using CLP(FD)) would be:

product(List1, List2, Product) :-
    % save a copy of the second list
    product(List1, List2, List2, Product).

product([], _, _, []).
product([X| Xs], List2, Rest2, Product) :-
    (   Rest2 == [] ->
        product(Xs, List2, List2, Product)
    ;   Rest2 = [Y| Ys],
        Z is X * Y,
        Product = [Z| Zs],
        product([X| Xs], List2, Ys, Zs)
    ).

This solution is tail-recursive and doesn't leave spurious choice-points.

Paulo Moura
  • 18,373
  • 3
  • 23
  • 33
  • 2
    The people helps who need helps, it will make a better world. Thanks for attention – Shmn May 19 '15 at 20:10
1

Well,First take a look on this question executing operation for each list element in swi-prolog and others to know how to do for-each operation on lists.
Second, here is the code:

prod(X,[],[]).
prod(X,[HEAD|TAIL],L) :-  prod(X,TAIL,L1), W is X * HEAD, L = [W|L1].

prod2([],Y,[]).
prod2([HEAD|TAIL],Y,L) :- prod(HEAD,Y,L1), prod2(TAIL,Y,L2), append(L1,L2,L).

output:

?- prod2([1,3,5] ,[2,6,7],G).
G = [2, 6, 7, 6, 18, 21, 10, 30, 35] .
Community
  • 1
  • 1
houssam
  • 1,823
  • 15
  • 27
  • 2
    This solution is not tail-recursive, requires relatively costly calls to `append/3`, doesn't take advantage of the first-argument indexing found on most Prolog systems, and leaves spurious choice-points. – Paulo Moura May 19 '15 at 18:48
  • @PauloMoura: you are right, but most beginners prefer simple readable code more than complex one. – houssam May 20 '15 at 05:31
  • Hmm, it is a "correct" solution but as @PauloMoura has pointed out, it has a lot of deficiencies. I won't even go into coding guidelines (if you do program in Prolog, take a look [here](http://arxiv.org/abs/0911.2899)). But since OP is probably not too interested in learning Prolog anyway, I guess taking your solution as "correct" does not do too much harm. –  May 20 '15 at 08:12