   t = Time.now
   Enum.each(1..iters, fn(_) -> Matrix.multiply([[1,2,3],[4,5,6],[7,8,9]],[[1,2,3],[4,5,6],[7,8,9]]) end)
   IO.puts "elapsed time #{Time.now - t} secs for #{iters} iterations of a 3x3 x 3x3 matrix multiply"
-  a = Matrix.rand(1000,1000)
-  b = Matrix.rand(1000,1000)
+  a = Matrix.rand(100,100)
+  b = Matrix.rand(100,100)
   t = Time.now
-  Enum.each(1..10, fn(_) -> Matrix.multiply(a,b) end)
-  IO.puts "elapsed time #{Time.now - t} secs for #{10} iterations of a 1000x1000 x 1000x1000 matrix multiply"
+  iters = 100
+  Enum.each(1..iters, fn(_) -> Matrix.multiply(a,b) end)
+  IO.puts "elapsed time #{Time.now - t} secs for #{iters} iterations of a 100x100 x 100x100 matrix multiply"
 end

    end

    test "size of 3x2 matrix specifying which dimension" do
      assert Matrix.size([[1,2],[3,4],[5,6]],1) == 3
      assert Matrix.size([[1,2],[3,4],[5,6]],2) == 2
    end

    test "apply a function to every element" do

  end

  # vector sum
  def sum([h]) when is_list(h) do
    Enum.reduce(h, 0, fn(x,acc)->x+acc end)
  end

  def sum(a = [h | t]) when is_list(h) and is_list(t) and length(h)==1 do
    sum(transpose(a))
  end

  # vector product
  def prod([h]) when is_list(h) do
    Enum.reduce(h, 1, fn(x,acc)->x*acc end)
  end

  def prod(a = [h | t]) when is_list(h) and is_list(t) and length(h)==1 do
    prod(transpose(a))
  end

  # max of a row vector
  def max([h]) when is_list(h) do
    Enum.max(h)
  end

  # max of a column vector
  def max(a = [h | t]) when is_list(h) and is_list(t) and length(h)==1 do
    max(transpose(a))
  end

  # max of a matrix
  def max(a = [h | t]) when is_list(h) and is_list(t) do
    # this could probably be rewritten to be more efficient...
    transpose(Enum.map(transpose(a), &([Enum.max(&1)])))
  end

  # max of a matrix specifying dimension
  def max(a = [h | t], 1) when is_list(h) and is_list(t) do
    Enum.map(a, &([Enum.max(&1)]))
  end

  def max(a = [h | t], 2) when is_list(h) and is_list(t) do
    # default
    max(a)
  end

  # unrolls a matrix into a 1 x n vector
  # note: taking advantage of Enum.concat does a :lists.reverse which may be suboptimal
  def unroll(a = [h | _]) when is_list(h) do
    [Enum.concat(a)]
  end

  # transpose column vectors to row vector first
  def reshape(a = [h | t], rows, cols) when is_list(h) and is_list(t) and length(h)==1 and length(a) > 1 do
    reshape(transpose(a), rows, cols)
  end
  # reshape a vector into a matrix
  # note: taking advantage of Enum.split does two :lists.reverse'als and may be suboptimal
  def reshape([h], rows, cols) when is_list(h) and rows > 0 and cols > 0 do
    {first, rest} = Enum.split(h, cols)
    [first | reshape([rest], rows-1, cols)]
  end
  # end case(s)
  def reshape(_,rows,_) when rows == 0, do: []
  def reshape([], _, _), do: []


  def inverse(_matrix) do
    # oh shit. this rabbit hole goes DEEP. Will return (?) to this eventually. May have to call out to BLAS etc
