我必须写一个谓词谓词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,只是一个猜测)。
在这里,我试图解释我的思考方式..但可能有一种更简单的方法。你觉得怎么样?
答案 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).