2015-12-10 88 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).