使用Prolog进行矩阵乘法

时间:2015-12-10 15:54:33

标签: matrix prolog

我必须写一个谓词谓词product/3,它接收两个矩阵,如果可能则返回矩阵乘法,否则失败。 (这意味着如果矩阵满足要求[n x p] [p x y],则返回带维[n x y]的乘法)

示例:

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,只是一个猜测)。

在这里,我试图解释我的思考方式..但可能有一种更简单的方法。你觉得怎么样?

1 个答案:

答案 0 :(得分: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:transpose的依赖性很容易删除:这里有一个替代方案' one-liner'基于第n / 3和库(yall)的定义

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