Array in elixir

Hi, I found this code, could you explain what it does and how it does it for each line.

I know that it creates a 100x100 matrix and multiplies it, but I would like a more detailed explanation of what each thing means.

defmodule Matrix do

  def transpose([[x | xs] | xss]) do
    [[x | (for [h | _] <- xss, do: h)] | transpose([xs | (for [_ | t] <- xss, do: t)])]
  end
  def transpose([[] | xss]), do: transpose(xss)
  def transpose([]), do: []

 def multiply(a = [x | _],b = [y | _]) when is_list(a) and is_list(b) and is_list(x) and is_list(y) do
    multiply([], a, transpose(b))
  end

  def multiply(_, []), do: []
  def multiply(a, b = [h | t]) when is_number(a) and is_list(b) and is_list(h) do
    [Enum.map(h, &(&1*a)) | multiply(a, t)]
  end
  def multiply(b = [h | _], a) when is_number(a) and is_list(b) and is_list(h) do
    multiply(a, b)
  end
  def multiply(result, [], []), do: result
  def multiply(result, [a | rest_a], [b | rest_b]) when not is_list(a) and not is_list(b), do: multiply(a*b+result, rest_a, rest_b)

  def multiply(result, [first_row_a | rest_a], b) when is_list(first_row_a) do
    [Enum.reverse(Enum.reduce(b, [], fn(col_b,acc) -> [multiply(0, first_row_a, col_b) | acc] end)) | multiply(result, rest_a, b)]
  end
  def multiply(result, [], _), do: result

def rand(rows, cols) do
    Enum.map(0..rows-1, fn _ ->
      for _ <- 0..cols-1, do: :random.uniform
    end)
  end

defmodule Time do
    def now, do: ({msecs, secs, musecs} = :erlang.timestamp; ((msecs*1000000 + secs)*1000000 + musecs)/1000000)
  end

end

a = Matrix.rand(100,100)
b = Matrix.rand(100,100)
t = Time.now
iters = 100
Enum.each(1..iters, fn(_) -> Matrix.multiply(a,b) end)
1 Like

Hello; my 2 non-exhaustive cents.

In the last line the code multiplies two 100x100 random matrix, a and b, for a hundred times.

t is set to the current time, to start timing the operation (benchmarking), but the code is missing a second time measure, after the 100 iterations, to actually make use of t, and make sense of the 100 repetition of

Enum.each(1..iters... 

Then we should go on and read the multiply/2 functions to understand its recursive implementation through multiply/3 (and how it uses the recursive transpose/1 function)

I’d start from the end-cases:

def multiply(_, []), do: []

here it looks that multiplying anything for an empty list the result is always an empty list, no need to process more.

def multiply(result, [], []), do: result

here when the function is called with some result list, and two empty list, it looks we got to the end of computation, and the function returns the final result.

def multiply(result, [], _), do: result

same here, but the function is ignoring the third argument: if results are present and the second list is empty, returns the result.

So… now i’d look at the entry-points for Matrix.multiply(a, b), it seems this one:

def multiply(a = [x | _],b = [y | _]) when is_list(a) and is_list(b) and is_list(x) and is_list(y) do
    multiply([], a, transpose(b))
end

which invokes the multiply/3 recursive function with a first empty list as result accumulator, the a matrix, and the b matrix transposed.

(Here you would like to step in the transpose/1 function to understand its recursive implementation too). … [to be continued]

P.S. >>> see a much more informed discussion about Arrays <<<