%% Doesn't check matrix sizes match but
%% not restricted to square matrices.
%%
%% Represent matrix as tuple of tuples.
%% Doesn't use destructive assignment so building a
%% matrix creates an awful lot of temporary lists.
%%
%% Usage: start from command line with
%% erlc multiply.erl
%% erl -noinput -s multiply main 1
-module(matrix).
-export([main/1]).
-import(lists, [reverse/1]).
sumprod(0, _, _, Sum, _, _) -> Sum;
sumprod(I, C, R, Sum, M1, M2) ->
NewSum = Sum + (element(I,element(R,M1)) * element(C,element(I,M2))),
sumprod(I-1, C, R, NewSum, M1, M2).
rowmult(_, 0, _, L, _, _) -> list_to_tuple(L);
rowmult(I, C, R, L, M1, M2) ->
SumProd = sumprod(I, C, R, 0, M1, M2),
rowmult(I, C-1, R, [SumProd|L], M1, M2).
mmult(_, _, 0, MM, _, _) -> list_to_tuple(MM);
mmult(I, C, R, MM, M1, M2) ->
NewRow = rowmult(I, C, R, [], M1, M2),
mmult(I, C, R-1, [NewRow|MM], M1, M2).
mmult(M1, M2) ->
Inner = size(M2), % could optimize more by hardcoding the sizes
NRows = size(M1),
mmult(Inner, NRows, NRows,[], M1, M2).
repeatmmult(1, M1, M2) -> mmult(M1, M2);
repeatmmult(NTimes, M1, M2) ->
mmult(M1, M2),
repeatmmult(NTimes-1, M1, M2).
mkrow(0, L, Count) -> {list_to_tuple(reverse(L)), Count};
mkrow(N, L, Count) -> mkrow(N-1, [Count|L], Count+1).
mkmatrix(0, _, _, M) -> list_to_tuple(reverse(M));
mkmatrix(NR, NC, Count, M) ->
{Row, NewCount} = mkrow(NC, [], Count),
mkmatrix(NR-1, NC, NewCount, [Row|M]).
mkmatrix(NR, NC) -> mkmatrix(NR, NC, 1, []).
main([Arg]) ->
NTimes = list_to_integer(atom_to_list(Arg)),
Size = 30,
M1 = mkmatrix(Size, Size),
M2 = mkmatrix(Size, Size),
MM = repeatmmult(NTimes, M1, M2),
Val1 = element(1,element(1, MM)),
Val2 = element(4,element(3, MM)), % get col 4 out of row 3
Val3 = element(3,element(4, MM)), % get col 3 out of row 4
Val4 = element(5,element(5, MM)),
io:fwrite("~w ~w ~w ~w~n", [Val1, Val2, Val3, Val4]),
halt(0).