2015-12-10 2 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-й столбец 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

Компактный код (с помощью конструкций и списков более высокого порядка) Я оставил цель выражения не оцениваются, поэтому результат может быть повторно использован в более общем контексте:

:- 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: транспонировать легко удалить: здесь альтернатива «один вкладыш» определение, основанное на п-й/3 и библиотеки (Yall)

mat_transpose([R1|Rs],T) :- findall(V,(
    nth1(Col,R1,_), 
    maplist({Col}/[R,C]>>nth1(Col,R,C),[R1|Rs],V)),T). 
Смежные вопросы