矩阵乘法与 Prolog

Sau*_*cia 4 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
Run Code Online (Sandbox Code Playgroud)

为此,我有两个代码,它们索引矩阵上的第 n 行rowI,索引第 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).
Run Code Online (Sandbox Code Playgroud)

我想以某种方式抓住M1(这将是每一行)的头部,然后乘以每一列M2,在添加乘法之后,这个列表将是新行。所以(C 必须是一个从 1 到长度的计数器M2,然后mult我只是想让它乘以列表。(此时没有定义 mult,只是一个猜测)。

在这里,我试图解释我的想法......但可能有一种更简单的方法。你怎么认为?

Cap*_*liC 5

紧凑的代码(借助高阶构造 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).
Run Code Online (Sandbox Code Playgroud)

编辑

用法(保存在名为 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]].
Run Code Online (Sandbox Code Playgroud)

数值计算由 明确要求,maplist(maplist(is),C,R)。R 保存符号表达式,C 保存值。

编辑

只是要注意 clpfd:transpose 的依赖很容易删除:这是一个基于 nth/3 和 library(yall) 的替代“单行”定义

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