58 lines
1.6 KiB
Erlang
58 lines
1.6 KiB
Erlang
%% Multiplies two matrices. Usage example:
|
|
%% $ matrix:multiply([[1,2,3],[4,5,6]], [[4,4],[0,0],[1,4]])
|
|
%% If the dimentions are incompatible, an error is thrown.
|
|
%%
|
|
%% The erl shell may encode the lists output as strings. In order to prevent such
|
|
%% behaviour, BEFORE running matrix:multiply, run shell:strings(false) to disable
|
|
%% auto-encoding. When finished, run shell:strings(true) to reset the defaults.
|
|
|
|
-module(matrix).
|
|
-export([multiply/2]).
|
|
|
|
transpose([[]|_]) ->
|
|
[];
|
|
transpose(B) ->
|
|
[lists:map(fun hd/1, B) | transpose(lists:map(fun tl/1, B))].
|
|
|
|
|
|
red(Pair, Sum) ->
|
|
X = element(1, Pair), %gets X
|
|
Y = element(2, Pair), %gets Y
|
|
X * Y + Sum.
|
|
|
|
%% Mathematical dot product. A x B = d
|
|
%% A, B = 1-dimension vector
|
|
%% d = scalar
|
|
dot_product(A, B) ->
|
|
lists:foldl(fun red/2, 0, lists:zip(A, B)).
|
|
|
|
|
|
%% Exposed function. Expected result is C = A x B.
|
|
multiply(A, B) ->
|
|
%% First transposes B, to facilitate the calculations (It's easier to fetch
|
|
%% row than column wise).
|
|
multiply_internal(A, transpose(B)).
|
|
|
|
|
|
%% This function does the actual multiplication, but expects the second matrix
|
|
%% to be transposed.
|
|
multiply_internal([Head | Rest], B) ->
|
|
% multiply each row by Y
|
|
Element = multiply_row_by_col(Head, B),
|
|
|
|
% concatenate the result of this multiplication with the next ones
|
|
[Element | multiply_internal(Rest, B)];
|
|
|
|
multiply_internal([], B) ->
|
|
% concatenating and empty list to the end of a list, changes nothing.
|
|
[].
|
|
|
|
|
|
multiply_row_by_col(Row, [Col_Head | Col_Rest]) ->
|
|
Scalar = dot_product(Row, Col_Head),
|
|
|
|
[Scalar | multiply_row_by_col(Row, Col_Rest)];
|
|
|
|
multiply_row_by_col(Row, []) ->
|
|
[].
|