2015-12-10 89 views
2

我必须写谓词谓词product/3接收两个矩阵,并返回它们的矩阵乘法,如果可能或否则失败。 (这意味着如果矩阵fullfill要求[n x p] [p x y],然后返回其尺寸[n x y]倍增)矩阵乘法与Prolog

实施例:

product(M1, M2, R) 
    ?- product([[1,2],[3,4],[5,6]], [[1,1,1],[1,1,1]], M). 
    M = [[3, 3, 3], [7, 7, 7], [11, 11, 11]]; 
    No 

为此,我有两个代码的索引上的矩阵rowI和索引第n行第n列columnI(我解释他们如何在下面的代码中工作)。

%Predicate: rowI(M, I, RI) 
%Input  rowI([[1,2],[3,4],[5,6]], 2, RI). 
%   RI = [3,4]; 

rowI([H|_],1,H):-!. 
rowI([_|T],I,X) :- 
    I1 is I-1, 
    rowI(T,I1,X). 

%  columnJ(M, J, CJ) 
%Input columnJ([[1,2],[3,4],[5,6]], 1, CJ). 
%  CJ = [1,3,5]; 

columnJ([],_,[]). 
columnJ([H|T], I, [R|X]):- 
    rowI(H, I, R), 
    columnJ(T,I,X). 


product([H|T], M2, [R|X]):- 

    columnJ(M2, C, Z), 
    mult(H, Z , X), 
    product(T, M2 , X). 

我被抓住了M1(这将是每行)的头不知怎么想,然后在M2将乘法运算这份名单将是新行后乘以每个列。所以(C必须是一个从1开始到M2长度的计数器,然后mult我只是想把它与列表相乘(mult不定义在这一点上,只是猜测)。我试图解释我的思维方式......但可能有一个更简单的方法,你认为如何?

回答

3

紧凑的代码(借助更高阶的构造maplist和foldl) 我离开了目的表达式未评估,所以结果可以在更一般的上下文中重用:

:- module(matrix_multiply, 
    [matrix_multiply/3 
    ,dot_product/3 
    ]). 
:- use_module(library(clpfd), [transpose/2]). 

%% matrix_multiply(+X,+Y,-M) is det. 
% 
% X(N*P),Y(P*M),M(N*M) 
% 
matrix_multiply(X,Y,M) :- 
    transpose(Y,T), 
    maplist(row_multiply(T),X,M). 

row_multiply(T,X,M) :- 
    maplist(dot_product(X),T,M). 

dot_product([X|Xs],[T|Ts],M) :- 
    foldl(mul,Xs,Ts,X*T,M). 
mul(X,T,M,M+X*T). 

编辑

使用(保存在名为matrix_multiply.pl文件):

?- [matrix_multiply]. 
?- matrix_multiply([[1,2],[3,4],[5,6]], [[1,1,1],[1,1,1]],R),maplist(maplist(is),C,R). 
R = [[1*1+2*1, 1*1+2*1, 1*1+2*1], [3*1+4*1, 3*1+4*1, 3*1+4*1], [5*1+6*1, 5*1+6*1, 5*1+6*1]], 
C = [[3, 3, 3], [7, 7, 7], [11, 11, 11]]. 

数字评估明确,maplist(maplist(is),C,R)要求。 R持有符号表达式,C是值。

编辑

只是要注意从clpfd这种依赖性:调换是容易清除:这里是一个另类“的一行”的定义基于第n/3和图书馆(亚勒)

mat_transpose([R1|Rs],T) :- findall(V,(
    nth1(Col,R1,_), 
    maplist({Col}/[R,C]>>nth1(Col,R,C),[R1|Rs],V)),T).