class Matrix

def *(m) # m is matrix or vector or number

m is matrix or vector or number

6 8
=> 2 4
Matrix[[2,4], [6,8]] * Matrix.identity(2)
Matrix multiplication.
def *(m) # m is matrix or vector or number
  case(m)
  when Numeric
    rows = @rows.collect {|row|
      row.collect {|e| e * m }
    }
    return new_matrix(rows, column_size)
  when Vector
    m = self.class.column_vector(m)
    r = self * m
    return r.column(0)
  when Matrix
    Matrix.Raise ErrDimensionMismatch if column_size != m.row_size
    rows = Array.new(row_size) {|i|
      Array.new(m.column_size) {|j|
        (0 ... column_size).inject(0) do |vij, k|
          vij + self[i, k] * m[k, j]
        end
      }
    }
    return new_matrix(rows, m.column_size)
  else
    return apply_through_coercion(m, __method__)
  end
end

def **(other)


48 99
=> 67 96
Matrix[[7,6], [3,9]] ** 2

Non integer exponents will be handled by diagonalizing the matrix.
Equivalent to multiplying the matrix by itself N times.
Matrix exponentiation.
def **(other)
  case other
  when Integer
    x = self
    if other <= 0
      x = self.inverse
      return self.class.identity(self.column_size) if other == 0
      other = -other
    end
    z = nil
    loop do
      z = z ? z * x : x if other[0] == 1
      return z if (other >>= 1).zero?
      x *= x
    end
  when Numeric
    v, d, v_inv = eigensystem
    v * self.class.diagonal(*d.each(:diagonal).map{|e| e ** other}) * v_inv
  else
    Matrix.Raise ErrOperationNotDefined, "**", self.class, other.class
  end
end

def +(m)


-4 12
=> 6 0
Matrix.scalar(2,5) + Matrix[[1,0], [-4,7]]
Matrix addition.
def +(m)
  case m
  when Numeric
    Matrix.Raise ErrOperationNotDefined, "+", self.class, m.class
  when Vector
    m = self.class.column_vector(m)
  when Matrix
  else
    return apply_through_coercion(m, __method__)
  end
  Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
  rows = Array.new(row_size) {|i|
    Array.new(column_size) {|j|
      self[i, j] + m[i, j]
    }
  }
  new_matrix rows, column_size
end

def -(m)


8 1
=> -8 2
Matrix[[1,5], [4,2]] - Matrix[[9,3], [-4,1]]
Matrix subtraction.
def -(m)
  case m
  when Numeric
    Matrix.Raise ErrOperationNotDefined, "-", self.class, m.class
  when Vector
    m = self.class.column_vector(m)
  when Matrix
  else
    return apply_through_coercion(m, __method__)
  end
  Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
  rows = Array.new(row_size) {|i|
    Array.new(column_size) {|j|
      self[i, j] - m[i, j]
    }
  }
  new_matrix rows, column_size
end

def /(other)


-3 -6
=> -7 1
Matrix[[7,6], [3,9]] / Matrix[[2,9], [3,1]]
Matrix division (multiplication by the inverse).
def /(other)
  case other
  when Numeric
    rows = @rows.collect {|row|
      row.collect {|e| e / other }
    }
    return new_matrix(rows, column_size)
  when Matrix
    return self * other.inverse
  else
    return apply_through_coercion(other, __method__)
  end
end

def ==(other)


Returns +true+ if and only if the two matrices contain equal elements.
def ==(other)
  return false unless Matrix === other &&
                      column_size == other.column_size # necessary for empty matrices
  rows == other.rows
end

def [](i, j)


Returns element (+i+,+j+) of the matrix. That is: row +i+, column +j+.
def [](i, j)
  @rows.fetch(i){return nil}[j]
end

def []=(i, j, v)

def []=(i, j, v)
  @rows[i][j] = v
end

def clone


There should be no good reason to do this since Matrices are immutable.
identical objects.
Returns a clone of the matrix, so that the contents of each do not reference
def clone
  new_matrix @rows.map(&:dup), column_size
end

def coerce(other)


See also Numeric#coerce.
type between the two operands of the operator.
numeric operations: it is intended to find a compatible common
This coercion mechanism is used by Ruby to handle mixed-type
The coerce method provides support for Ruby type coercion.
def coerce(other)
  case other
  when Numeric
    return Scalar.new(other), self
  else
    raise TypeError, "#{self.class} can't be coerced into #{other.class}"
  end
end

def collect(&block) # :yield: e

:yield: e

9 16
=> 1 4
Matrix[ [1,2], [3,4] ].collect { |e| e**2 }
elements of the matrix.
Returns a matrix that is the result of iteration of the given block over all
def collect(&block) # :yield: e
  return to_enum(:collect) unless block_given?
  rows = @rows.collect{|row| row.collect(&block)}
  new_matrix rows, column_size
end

def column(j) # :yield: e

:yield: e

iterated.
like an array). When a block is given, the elements of that vector are
Returns column vector number +j+ of the matrix as a Vector (starting at 0
def column(j) # :yield: e
  if block_given?
    return self if j >= column_size || j < -column_size
    row_size.times do |i|
      yield @rows[i][j]
    end
    self
  else
    return nil if j >= column_size || j < -column_size
    col = Array.new(row_size) {|i|
      @rows[i][j]
    }
    Vector.elements(col, false)
  end
end

def column_vectors


Returns an array of the column vectors of the matrix. See Vector.
def column_vectors
  Array.new(column_size) {|i|
    column(i)
  }
end

def conjugate


1 2 3
=> 1-2i -i 0
Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].conjugate
1 2 3
=> 1+2i i 0
Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
Returns the conjugate of the matrix.
def conjugate
  collect(&:conjugate)
end

def determinant


=> 45
Matrix[[7,6], [3,9]].determinant

Consider using exact types like Rational or BigDecimal instead.
because of their lack of precision.
Beware that using Float values can yield erroneous results

Returns the determinant of the matrix.
def determinant
  Matrix.Raise ErrDimensionMismatch unless square?
  m = @rows
  case row_size
    # Up to 4x4, give result using Laplacian expansion by minors.
    # This will typically be faster, as well as giving good results
    # in case of Floats
  when 0
    +1
  when 1
    + m[0][0]
  when 2
    + m[0][0] * m[1][1] - m[0][1] * m[1][0]
  when 3
    m0, m1, m2 = m
    + m0[0] * m1[1] * m2[2] - m0[0] * m1[2] * m2[1] \
    - m0[1] * m1[0] * m2[2] + m0[1] * m1[2] * m2[0] \
    + m0[2] * m1[0] * m2[1] - m0[2] * m1[1] * m2[0]
  when 4
    m0, m1, m2, m3 = m
    + m0[0] * m1[1] * m2[2] * m3[3] - m0[0] * m1[1] * m2[3] * m3[2] \
    - m0[0] * m1[2] * m2[1] * m3[3] + m0[0] * m1[2] * m2[3] * m3[1] \
    + m0[0] * m1[3] * m2[1] * m3[2] - m0[0] * m1[3] * m2[2] * m3[1] \
    - m0[1] * m1[0] * m2[2] * m3[3] + m0[1] * m1[0] * m2[3] * m3[2] \
    + m0[1] * m1[2] * m2[0] * m3[3] - m0[1] * m1[2] * m2[3] * m3[0] \
    - m0[1] * m1[3] * m2[0] * m3[2] + m0[1] * m1[3] * m2[2] * m3[0] \
    + m0[2] * m1[0] * m2[1] * m3[3] - m0[2] * m1[0] * m2[3] * m3[1] \
    - m0[2] * m1[1] * m2[0] * m3[3] + m0[2] * m1[1] * m2[3] * m3[0] \
    + m0[2] * m1[3] * m2[0] * m3[1] - m0[2] * m1[3] * m2[1] * m3[0] \
    - m0[3] * m1[0] * m2[1] * m3[2] + m0[3] * m1[0] * m2[2] * m3[1] \
    + m0[3] * m1[1] * m2[0] * m3[2] - m0[3] * m1[1] * m2[2] * m3[0] \
    - m0[3] * m1[2] * m2[0] * m3[1] + m0[3] * m1[2] * m2[1] * m3[0]
  else
    # For bigger matrices, use an efficient and general algorithm.
    # Currently, we use the Gauss-Bareiss algorithm
    determinant_bareiss
  end
end

def determinant_bareiss


intermediate results with better precision.
with smaller bignums (if any), while a matrix of Float will usually have
A matrix of Integers will have thus intermediate results that are also Integers,
Intermediate results are fraction free and of lower complexity.
It has the same computational cost order O(n^3) as standard Gaussian elimination.
Bareiss' multistep integer-preserving gaussian elimination.
Returns the determinant of the matrix, using

Private. Use Matrix#determinant
def determinant_bareiss
  size = row_size
  last = size - 1
  a = to_a
  no_pivot = Proc.new{ return 0 }
  sign = +1
  pivot = 1
  size.times do |k|
    previous_pivot = pivot
    if (pivot = a[k][k]) == 0
      switch = (k+1 ... size).find(no_pivot) {|row|
        a[row][k] != 0
      }
      a[switch], a[k] = a[k], a[switch]
      pivot = a[k][k]
      sign = -sign
    end
    (k+1).upto(last) do |i|
      ai = a[i]
      (k+1).upto(last) do |j|
        ai[j] =  (pivot * ai[j] - ai[k] * a[k][j]) / previous_pivot
      end
    end
  end
  sign * pivot
end

def determinant_e


deprecated; use Matrix#determinant
def determinant_e
  warn "#{caller(1)[0]}: warning: Matrix#determinant_e is deprecated; use #determinant"
  rank
end

def diagonal?


Raises an error if matrix is not square.
Returns +true+ is this is a diagonal matrix.
def diagonal?
  Matrix.Raise ErrDimensionMismatch unless square?
  each(:off_diagonal).all?(&:zero?)
end

def each(which = :all) # :yield: e

:yield: e

Matrix[ [1,2], [3,4] ].each(:strict_lower).to_a # => [3]
# => prints the numbers 1 to 4
Matrix[ [1,2], [3,4] ].each { |e| puts e }

* :upper: yields only elements on or above the diagonal
* :strict_upper: yields only elements above the diagonal
* :strict_lower: yields only elements below the diagonal
* :lower: yields only elements on or below the diagonal
* :off_diagonal: yields all elements except on the diagonal
* :diagonal: yields only elements on the diagonal
* :all (default): yields all elements
Elements can be restricted by passing an argument:
or returns an Enumerator is no block given.
Yields all elements of the matrix, starting with those of the first row,
def each(which = :all) # :yield: e
  return to_enum(:each, which) unless block_given?
  last = column_size - 1
  case which
  when :all
    block = Proc.new
    @rows.each do |row|
      row.each(&block)
    end
  when :diagonal
    @rows.each_with_index do |row, row_index|
      yield row.fetch(row_index){return self}
    end
  when :off_diagonal
    @rows.each_with_index do |row, row_index|
      column_size.times do |col_index|
        yield row[col_index] unless row_index == col_index
      end
    end
  when :lower
    @rows.each_with_index do |row, row_index|
      0.upto([row_index, last].min) do |col_index|
        yield row[col_index]
      end
    end
  when :strict_lower
    @rows.each_with_index do |row, row_index|
      [row_index, column_size].min.times do |col_index|
        yield row[col_index]
      end
    end
  when :strict_upper
    @rows.each_with_index do |row, row_index|
      (row_index+1).upto(last) do |col_index|
        yield row[col_index]
      end
    end
  when :upper
    @rows.each_with_index do |row, row_index|
      row_index.upto(last) do |col_index|
        yield row[col_index]
      end
    end
  else
    Matrix.Raise ArgumentError, "expected #{which.inspect} to be one of :all, :diagonal, :off_diagonal, :lower, :strict_lower, :strict_upper or :upper"
  end
  self
end

def each_with_index(which = :all) # :yield: e, row, column

:yield: e, row, column

# 4 at 1, 1
# 3 at 1, 0
# 2 at 0, 1
# 1 at 0, 0
# => Prints:
end
puts "#{e} at #{row}, #{col}"
Matrix[ [1,2], [3,4] ].each_with_index do |e, row, col|

Same as #each, but the row index and column index in addition to the element
def each_with_index(which = :all) # :yield: e, row, column
  return to_enum(:each_with_index, which) unless block_given?
  last = column_size - 1
  case which
  when :all
    @rows.each_with_index do |row, row_index|
      row.each_with_index do |e, col_index|
        yield e, row_index, col_index
      end
    end
  when :diagonal
    @rows.each_with_index do |row, row_index|
      yield row.fetch(row_index){return self}, row_index, row_index
    end
  when :off_diagonal
    @rows.each_with_index do |row, row_index|
      column_size.times do |col_index|
        yield row[col_index], row_index, col_index unless row_index == col_index
      end
    end
  when :lower
    @rows.each_with_index do |row, row_index|
      0.upto([row_index, last].min) do |col_index|
        yield row[col_index], row_index, col_index
      end
    end
  when :strict_lower
    @rows.each_with_index do |row, row_index|
      [row_index, column_size].min.times do |col_index|
        yield row[col_index], row_index, col_index
      end
    end
  when :strict_upper
    @rows.each_with_index do |row, row_index|
      (row_index+1).upto(last) do |col_index|
        yield row[col_index], row_index, col_index
      end
    end
  when :upper
    @rows.each_with_index do |row, row_index|
      row_index.upto(last) do |col_index|
        yield row[col_index], row_index, col_index
      end
    end
  else
    Matrix.Raise ArgumentError, "expected #{which.inspect} to be one of :all, :diagonal, :off_diagonal, :lower, :strict_lower, :strict_upper or :upper"
  end
  self
end

def eigensystem


(v * d * v_inv).round(5) == m # => true
v.inv == v_inv # => true
d.diagonal? # => true
v, d, v_inv = m.eigensystem
m = Matrix[[1, 2], [3, 4]]
Returns the Eigensystem of the matrix; see +EigenvalueDecomposition+.
def eigensystem
  EigenvalueDecomposition.new(self)
end

def elements_to_f

def elements_to_f
  warn "#{caller(1)[0]}: warning: Matrix#elements_to_f is deprecated, use map(&:to_f)"
  map(&:to_f)
end

def elements_to_i

def elements_to_i
  warn "#{caller(1)[0]}: warning: Matrix#elements_to_i is deprecated, use map(&:to_i)"
  map(&:to_i)
end

def elements_to_r

def elements_to_r
  warn "#{caller(1)[0]}: warning: Matrix#elements_to_r is deprecated, use map(&:to_r)"
  map(&:to_r)
end

def empty?


or the number of columns is 0.
Returns +true+ if this is an empty matrix, i.e. if the number of rows
def empty?
  column_size == 0 || row_size == 0
end

def eql?(other)

def eql?(other)
  return false unless Matrix === other &&
                      column_size == other.column_size # necessary for empty matrices
  rows.eql? other.rows
end

def hash


Returns a hash-code for the matrix.
def hash
  @rows.hash
end

def hermitian?

def hermitian?
  Matrix.Raise ErrDimensionMismatch unless square?
  each_with_index(:strict_upper).all? do |e, row, col|
    e == rows[col][row].conj
  end
end if 42.respond_to?(:conj)

def imaginary


0 0 0
=> 2i i 0
Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].imaginary
1 2 3
=> 1+2i i 0
Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
Returns the imaginary part of the matrix.
def imaginary
  collect(&:imaginary)
end

def index(*args)


Matrix[ [1,1], [1,1] ].index(1, :strict_lower) # => [1, 0]
Matrix[ [1,2], [3,4] ].index(&:even?) # => [0, 1]

It also accepts an optional +selector+ argument, see #each for details.
The index method is specialized to return the index as [row, column]

index(selector = :all) -> an_enumerator
index(selector = :all){ block } -> [row, column]
index(value, selector = :all) -> [row, column]
:call-seq:
def index(*args)
  raise ArgumentError, "wrong number of arguments(#{args.size} for 0-2)" if args.size > 2
  which = (args.size == 2 || SELECTORS.include?(args.last)) ? args.pop : :all
  return to_enum(:find_index, which, *args) unless block_given? || args.size == 1
  if args.size == 1
    value = args.first
    each_with_index(which) do |e, row_index, col_index|
      return row_index, col_index if e == value
    end
  else
    each_with_index(which) do |e, row_index, col_index|
      return row_index, col_index if yield e
    end
  end
  nil
end

def initialize(rows, column_size = rows[0].size)


Matrix.new is private; use Matrix.rows, columns, [], etc... to create.
def initialize(rows, column_size = rows[0].size)
  # No checking is done at this point. rows must be an Array of Arrays.
  # column_size must be the size of the first row, if there is one,
  # otherwise it *must* be specified and can be any integer >= 0
  @rows = rows
  @column_size = column_size
end

def inspect


Overrides Object#inspect
def inspect
  if empty?
    "#{self.class}.empty(#{row_size}, #{column_size})"
  else
    "#{self.class}#{@rows.inspect}"
  end
end

def inverse


0 -1
=> -1 1
Matrix[[-1, -1], [0, -1]].inverse
Returns the inverse of the matrix.
def inverse
  Matrix.Raise ErrDimensionMismatch unless square?
  self.class.I(row_size).send(:inverse_from, self)
end

def inverse_from(src) # :nodoc:

:nodoc:
def inverse_from(src) # :nodoc:
  last = row_size - 1
  a = src.to_a
  0.upto(last) do |k|
    i = k
    akk = a[k][k].abs
    (k+1).upto(last) do |j|
      v = a[j][k].abs
      if v > akk
        i = j
        akk = v
      end
    end
    Matrix.Raise ErrNotRegular if akk == 0
    if i != k
      a[i], a[k] = a[k], a[i]
      @rows[i], @rows[k] = @rows[k], @rows[i]
    end
    akk = a[k][k]
    0.upto(last) do |ii|
      next if ii == k
      q = a[ii][k].quo(akk)
      a[ii][k] = 0
      (k + 1).upto(last) do |j|
        a[ii][j] -= a[k][j] * q
      end
      0.upto(last) do |j|
        @rows[ii][j] -= @rows[k][j] * q
      end
    end
    (k+1).upto(last) do |j|
      a[k][j] = a[k][j].quo(akk)
    end
    0.upto(last) do |j|
      @rows[k][j] = @rows[k][j].quo(akk)
    end
  end
  self
end

def lower_triangular?


Returns +true+ is this is a lower triangular matrix.
def lower_triangular?
  each(:strict_upper).all?(&:zero?)
end

def lup


a.lup.solve([2, 5]) # => Vector[(1/1), (1/2)]
l * u == a * p # => true
p.permutation? # => true
u.upper_triangular? # => true
l.lower_triangular? # => true
l, u, p = a.lup
a = Matrix[[1, 2], [3, 4]]
Returns the LUP decomposition of the matrix; see +LUPDecomposition+.
def lup
  LUPDecomposition.new(self)
end

def minor(*param)


row or column is greater than row_size or column_size respectively.
row or column (-1 is the last element). Returns nil if the starting
Like Array#[], negative indices count backward from the end of the

0 5 0
=> 9 0 0
Matrix.diagonal(9, 5, -3).minor(0..1, 0..2)

* row_range, col_range
* start_row, nrows, start_col, ncols; OR
Returns a section of the matrix. The parameters are either:
def minor(*param)
  case param.size
  when 2
    row_range, col_range = param
    from_row = row_range.first
    from_row += row_size if from_row < 0
    to_row = row_range.end
    to_row += row_size if to_row < 0
    to_row += 1 unless row_range.exclude_end?
    size_row = to_row - from_row
    from_col = col_range.first
    from_col += column_size if from_col < 0
    to_col = col_range.end
    to_col += column_size if to_col < 0
    to_col += 1 unless col_range.exclude_end?
    size_col = to_col - from_col
  when 4
    from_row, size_row, from_col, size_col = param
    return nil if size_row < 0 || size_col < 0
    from_row += row_size if from_row < 0
    from_col += column_size if from_col < 0
  else
    Matrix.Raise ArgumentError, param.inspect
  end
  return nil if from_row > row_size || from_col > column_size || from_row < 0 || from_col < 0
  rows = @rows[from_row, size_row].collect{|row|
    row[from_col, size_col]
  }
  new_matrix rows, [column_size - from_col, size_col].min
end

def new_matrix(rows, column_size = rows[0].size) # :nodoc:

:nodoc:
def new_matrix(rows, column_size = rows[0].size) # :nodoc:
  self.class.send(:new, rows, column_size) # bypass privacy of Matrix.new
end

def normal?


Raises an error if matrix is not square.
Returns +true+ is this is a normal matrix.
def normal?
  Matrix.Raise ErrDimensionMismatch unless square?
  rows.each_with_index do |row_i, i|
    rows.each_with_index do |row_j, j|
      s = 0
      rows.each_with_index do |row_k, k|
        s += row_i[k] * row_j[k].conj - row_k[i].conj * row_k[j]
      end
      return false unless s == 0
    end
  end
  true
end if 42.respond_to?(:conj)

def orthogonal?


Raises an error if matrix is not square.
Returns +true+ is this is an orthogonal matrix
def orthogonal?
  Matrix.Raise ErrDimensionMismatch unless square?
  rows.each_with_index do |row, i|
    column_size.times do |j|
      s = 0
      row_size.times do |k|
        s += row[k] * rows[k][j]
      end
      return false unless s == (i == j ? 1 : 0)
    end
  end
  true
end

def permutation?


Raises an error if matrix is not square.
Returns +true+ is this is a permutation matrix
def permutation?
  Matrix.Raise ErrDimensionMismatch unless square?
  cols = Array.new(column_size)
  rows.each_with_index do |row, i|
    found = false
    row.each_with_index do |e, j|
      if e == 1
        return false if found || cols[j]
        found = cols[j] = true
      elsif e != 0
        return false
      end
    end
    return false unless found
  end
  true
end

def rank


=> 2
Matrix[[7,6], [3,9]].rank

Consider using exact types like Rational or BigDecimal instead.
because of their lack of precision.
Beware that using Float values can yield erroneous results
Returns the rank of the matrix.
def rank
  # We currently use Bareiss' multistep integer-preserving gaussian elimination
  # (see comments on determinant)
  a = to_a
  last_column = column_size - 1
  last_row = row_size - 1
  pivot_row = 0
  previous_pivot = 1
  0.upto(last_column) do |k|
    switch_row = (pivot_row .. last_row).find {|row|
      a[row][k] != 0
    }
    if switch_row
      a[switch_row], a[pivot_row] = a[pivot_row], a[switch_row] unless pivot_row == switch_row
      pivot = a[pivot_row][k]
      (pivot_row+1).upto(last_row) do |i|
         ai = a[i]
         (k+1).upto(last_column) do |j|
           ai[j] =  (pivot * ai[j] - ai[k] * a[pivot_row][j]) / previous_pivot
         end
       end
      pivot_row += 1
      previous_pivot = pivot
    end
  end
  pivot_row
end

def rank_e


deprecated; use Matrix#rank
def rank_e
  warn "#{caller(1)[0]}: warning: Matrix#rank_e is deprecated; use #rank"
  rank
end

def real


1 2 3
=> 1 0 0
Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].real
1 2 3
=> 1+2i i 0
Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
Returns the real part of the matrix.
def real
  collect(&:real)
end

def real?


Returns +true+ if all entries of the matrix are real.
def real?
  all?(&:real?)
end

def rect


m.rect == [m.real, m.imag] # ==> true for all matrices m

parts of the matrix
Returns an array containing matrices corresponding to the real and imaginary
def rect
  [real, imag]
end

def regular?


Returns +true+ if this is a regular (i.e. non-singular) matrix.
def regular?
  not singular?
end

def round(ndigits=0)


(see Float#round)
Returns a matrix with entries rounded to the given precision
def round(ndigits=0)
  map{|e| e.round(ndigits)}
end

def row(i, &block) # :yield: e

:yield: e

an array). When a block is given, the elements of that vector are iterated.
Returns row vector number +i+ of the matrix as a Vector (starting at 0 like
def row(i, &block) # :yield: e
  if block_given?
    @rows.fetch(i){return self}.each(&block)
    self
  else
    Vector.elements(@rows.fetch(i){return nil})
  end
end

def row_size


Returns the number of rows.
def row_size
  @rows.size
end

def row_vectors


Returns an array of the row vectors of the matrix. See Vector.
def row_vectors
  Array.new(row_size) {|i|
    row(i)
  }
end

def singular?


Returns +true+ is this is a singular matrix.
def singular?
  determinant == 0
end

def square?


Returns +true+ is this is a square matrix.
def square?
  column_size == row_size
end

def symmetric?


Raises an error if matrix is not square.
Returns +true+ is this is a symmetric matrix.
def symmetric?
  Matrix.Raise ErrDimensionMismatch unless square?
  each_with_index(:strict_upper) do |e, row, col|
    return false if e != rows[col][row]
  end
  true
end

def to_a


Returns an array of arrays that describe the rows of the matrix.
def to_a
  @rows.collect(&:dup)
end

def to_s


Overrides Object#to_s
def to_s
  if empty?
    "#{self.class}.empty(#{row_size}, #{column_size})"
  else
    "#{self.class}[" + @rows.collect{|row|
      "[" + row.collect{|e| e.to_s}.join(", ") + "]"
    }.join(", ")+"]"
  end
end

def trace


=> 16
Matrix[[7,6], [3,9]].trace
Returns the trace (sum of diagonal elements) of the matrix.
def trace
  Matrix.Raise ErrDimensionMismatch unless square?
  (0...column_size).inject(0) do |tr, i|
    tr + @rows[i][i]
  end
end

def transpose


2 4 6
=> 1 3 5
Matrix[[1,2], [3,4], [5,6]].transpose
5 6
3 4
=> 1 2
Matrix[[1,2], [3,4], [5,6]]
Returns the transpose of the matrix.
def transpose
  return self.class.empty(column_size, 0) if row_size.zero?
  new_matrix @rows.transpose, row_size
end

def unitary?


Raises an error if matrix is not square.
Returns +true+ is this is a unitary matrix
def unitary?
  Matrix.Raise ErrDimensionMismatch unless square?
  rows.each_with_index do |row, i|
    column_size.times do |j|
      s = 0
      row_size.times do |k|
        s += row[k].conj * rows[k][j]
      end
      return false unless s == (i == j ? 1 : 0)
    end
  end
  true
end if 42.respond_to?(:conj)

def upper_triangular?


Returns +true+ is this is an upper triangular matrix.
def upper_triangular?
  each(:strict_lower).all?(&:zero?)
end

def zero?


Returns +true+ is this is a matrix with only zero elements
def zero?
  all?(&:zero?)
end