class Matrix < Array
  def initialize(ary)
    @d = (ary.size ** 0.5).to_i
    super ary
  end

  def +(other)
    Matrix.new map.with_index { |m, i| m + other[i] }
  end

  def *(other)
    Matrix.new size.times.map { |i|
      @d.times.map { |j| self[i / @d * @d + j] * other[i % @d + @d * j] }.reduce :+
    }
  end

  def /(scalar)
    Matrix.new map { |m| m / scalar }
  end

  def identity
    Matrix.new ([1] + [0] * @d) * (@d - 1) + [1]
  end

  def exponential
   series = (2..size * 2).map { |i| ([self] * i).reduce(:*) / (1..i).reduce(:*) }
   [self, series.reduce(:+), identity].reduce :+
  end
end

test = Matrix.new [
   0.0, -1.0,  3.0,  0.5,
   1.0,  0.0,  0.45, 0.1,
  -3.0, -0.45, 0.0,  0.4,
  -0.5, -0.1, -0.4,  0.0
]

test.exponential.each_slice(4) { |row| p row.map { |e| e.round 7 } }
