Class: Matrix

Inherits:
Object
  • Object
show all
Extended by:
ConversionHelper
Includes:
Enumerable, ExceptionForMatrix, CoercionHelper
Defined in:
lib/rubysl/matrix/matrix.rb

Overview

The Matrix class represents a mathematical matrix. It provides methods for creating matrices, operating on them arithmetically and algebraically, and determining their mathematical properties (trace, rank, inverse, determinant).

Method Catalogue

To create a matrix:

  • Matrix[*rows]

  • Matrix.[](*rows)

  • Matrix.rows(rows, copy = true)

  • Matrix.columns(columns)

  • Matrix.build(row_size, column_size, &block)

  • Matrix.diagonal(*values)

  • Matrix.scalar(n, value)

  • Matrix.identity(n)

  • Matrix.unit(n)

  • Matrix.I(n)

  • Matrix.zero(n)

  • Matrix.row_vector(row)

  • Matrix.column_vector(column)

To access Matrix elements/columns/rows/submatrices/properties:

  • [](i, j)

  • #row_size

  • #column_size

  • #row(i)

  • #column(j)

  • #collect

  • #map

  • #each

  • #each_with_index

  • #minor(*param)

Properties of a matrix:

  • #empty?

  • #real?

  • #regular?

  • #singular?

  • #square?

Matrix arithmetic:

  • *(m)

  • +(m)

  • -(m)

  • #/(m)

  • #inverse

  • #inv

  • **

Matrix functions:

  • #determinant

  • #det

  • #rank

  • #trace

  • #tr

  • #transpose

  • #t

Complex arithmetic:

  • conj

  • conjugate

  • imag

  • imaginary

  • real

  • rect

  • rectangular

Conversion to other data types:

  • #coerce(other)

  • #row_vectors

  • #column_vectors

  • #to_a

String representations:

  • #to_s

  • #inspect

Defined Under Namespace

Modules: CoercionHelper, ConversionHelper Classes: Scalar

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from CoercionHelper

coerce_to, coerce_to_int

Constructor Details

#initialize(rows, column_size = rows[0].size) ⇒ Matrix

Matrix.new is private; use Matrix.rows, columns, [], etc… to create.



277
278
279
280
281
282
283
# File 'lib/rubysl/matrix/matrix.rb', line 277

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

Instance Attribute Details

#column_sizeObject (readonly)

Returns the number of columns.



316
317
318
# File 'lib/rubysl/matrix/matrix.rb', line 316

def column_size
  @column_size
end

Class Method Details

.[](*rows) ⇒ Object

Creates a matrix where each argument is a row.

Matrix[ [25, 93], [-1, 66] ]
   =>  25 93
       -1 66


120
121
122
# File 'lib/rubysl/matrix/matrix.rb', line 120

def Matrix.[](*rows)
  Matrix.rows(rows, false)
end

.build(row_size, column_size = row_size) ⇒ Object

Creates a matrix of size row_size x column_size. It fills the values by calling the given block, passing the current row and column. Returns an enumerator if no block is given.

m = Matrix.build(2, 4) {|row, col| col - row }
  => Matrix[[0, 1, 2, 3], [-1, 0, 1, 2]]
m = Matrix.build(3) { rand }
  => a 3x3 matrix with random elements

Raises:

  • (ArgumentError)


165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/rubysl/matrix/matrix.rb', line 165

def Matrix.build(row_size, column_size = row_size)
  row_size = CoercionHelper.coerce_to_int(row_size)
  column_size = CoercionHelper.coerce_to_int(column_size)
  raise ArgumentError if row_size < 0 || column_size < 0
  return to_enum :build, row_size, column_size unless block_given?
  rows = row_size.times.map do |i|
    column_size.times.map do |j|
      yield i, j
    end
  end
  new rows, column_size
end

.column_vector(column) ⇒ Object

Creates a single-column matrix where the values of that column are as given in column.

Matrix.column_vector([4,5,6])
  => 4
     5
     6


249
250
251
252
# File 'lib/rubysl/matrix/matrix.rb', line 249

def Matrix.column_vector(column)
  column = convert_to_array(column)
  new [column].transpose, 1
end

.columns(columns) ⇒ Object

Creates a matrix using columns as an array of column vectors.

Matrix.columns([[25, 93], [-1, 66]])
   =>  25 -1
       93 66


150
151
152
# File 'lib/rubysl/matrix/matrix.rb', line 150

def Matrix.columns(columns)
  Matrix.rows(columns, false).transpose
end

.diagonal(*values) ⇒ Object

Creates a matrix where the diagonal elements are composed of values.

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


185
186
187
188
189
190
191
192
193
# File 'lib/rubysl/matrix/matrix.rb', line 185

def Matrix.diagonal(*values)
  size = values.size
  rows = (0 ... size).collect {|j|
    row = Array.new(size, 0)
    row[j] = values[j]
    row
  }
  new rows
end

.empty(row_size = 0, column_size = 0) ⇒ Object

Creates a empty matrix of row_size x column_size. At least one of row_size or column_size must be 0.

m = Matrix.empty(2, 0)
m == Matrix[ [], [] ]
  => true
n = Matrix.empty(0, 3)
n == Matrix.columns([ [], [], [] ])
  => true
m * n
  => Matrix[[0, 0, 0], [0, 0, 0]]


267
268
269
270
271
272
# File 'lib/rubysl/matrix/matrix.rb', line 267

def Matrix.empty(row_size = 0, column_size = 0)
  Matrix.Raise ArgumentError, "One size must be 0" if column_size != 0 && row_size != 0
  Matrix.Raise ArgumentError, "Negative size" if column_size < 0 || row_size < 0

  new([[]]*row_size, column_size)
end

.identity(n) ⇒ Object Also known as: unit, I

Creates an n by n identity matrix.

Matrix.identity(2)
  => 1 0
     0 1


212
213
214
# File 'lib/rubysl/matrix/matrix.rb', line 212

def Matrix.identity(n)
  Matrix.scalar(n, 1)
end

.row_vector(row) ⇒ Object

Creates a single-row matrix where the values of that row are as given in row.

Matrix.row_vector([4,5,6])
  => 4 5 6


236
237
238
239
# File 'lib/rubysl/matrix/matrix.rb', line 236

def Matrix.row_vector(row)
  row = convert_to_array(row)
  new [row]
end

.rows(rows, copy = true) ⇒ Object

Creates a matrix where rows is an array of arrays, each of which is a row of the matrix. If the optional argument copy is false, use the given arrays as the internal structure of the matrix without copying.

Matrix.rows([[25, 93], [-1, 66]])
   =>  25 93
       -1 66


132
133
134
135
136
137
138
139
140
141
142
# File 'lib/rubysl/matrix/matrix.rb', line 132

def Matrix.rows(rows, copy = true)
  rows = convert_to_array(rows)
  rows.map! do |row|
    convert_to_array(row, copy)
  end
  size = (rows[0] || []).size
  rows.each do |row|
    Matrix.Raise ErrDimensionMismatch, "row size differs (#{row.size} should be #{size})" unless row.size == size
  end
  new rows, size
end

.scalar(n, value) ⇒ Object

Creates an n by n diagonal matrix where each diagonal element is value.

Matrix.scalar(2, 5)
  => 5 0
     0 5


202
203
204
# File 'lib/rubysl/matrix/matrix.rb', line 202

def Matrix.scalar(n, value)
  Matrix.diagonal(*Array.new(n, value))
end

.zero(n) ⇒ Object

Creates an n by n zero matrix.

Matrix.zero(2)
  => 0 0
     0 0


226
227
228
# File 'lib/rubysl/matrix/matrix.rb', line 226

def Matrix.zero(n)
  Matrix.scalar(n, 0)
end

Instance Method Details

#*(m) ⇒ Object

Matrix multiplication.

Matrix[[2,4], [6,8]] * Matrix.identity(2)
  => 2 4
     6 8


531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
# File 'lib/rubysl/matrix/matrix.rb', line 531

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 = Matrix.column_vector(m)
    r = self * m
    return r.column(0)
  when Matrix
    Matrix.Raise ErrDimensionMismatch if column_size != m.row_size

    rows = (0 ... row_size).collect {|i|
      (0 ... m.column_size).collect {|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

#**(other) ⇒ Object

Matrix exponentiation. Currently implemented for integer powers only. Equivalent to multiplying the matrix by itself N times.

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


700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
# File 'lib/rubysl/matrix/matrix.rb', line 700

def ** (other)
  case other
  when Integer
    x = self
    if other <= 0
      x = self.inverse
      return Matrix.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
  else
    Matrix.Raise ErrOperationNotDefined, "**", self.class, other.class
  end
end

#+(m) ⇒ Object

Matrix addition.

Matrix.scalar(2,5) + Matrix[[1,0], [-4,7]]
  =>  6  0
     -4 12


566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
# File 'lib/rubysl/matrix/matrix.rb', line 566

def +(m)
  case m
  when Numeric
    Matrix.Raise ErrOperationNotDefined, "+", self.class, m.class
  when Vector
    m = Matrix.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 = (0 ... row_size).collect {|i|
    (0 ... column_size).collect {|j|
      self[i, j] + m[i, j]
    }
  }
  new_matrix rows, column_size
end

#-(m) ⇒ Object

Matrix subtraction.

Matrix[[1,5], [4,2]] - Matrix[[9,3], [-4,1]]
  => -8  2
      8  1


593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
# File 'lib/rubysl/matrix/matrix.rb', line 593

def -(m)
  case m
  when Numeric
    Matrix.Raise ErrOperationNotDefined, "-", self.class, m.class
  when Vector
    m = Matrix.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 = (0 ... row_size).collect {|i|
    (0 ... column_size).collect {|j|
      self[i, j] - m[i, j]
    }
  }
  new_matrix rows, column_size
end

#/(other) ⇒ Object

Matrix division (multiplication by the inverse).

Matrix[[7,6], [3,9]] / Matrix[[2,9], [3,1]]
  => -7  1
     -3 -6


620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
# File 'lib/rubysl/matrix/matrix.rb', line 620

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

#==(other) ⇒ Object

Returns true if and only if the two matrices contain equal elements.



495
496
497
498
# File 'lib/rubysl/matrix/matrix.rb', line 495

def ==(other)
  return false unless Matrix === other
  rows == other.rows
end

#[](i, j) ⇒ Object Also known as: element, component

Returns element (i,j) of the matrix. That is: row i, column j.



293
294
295
# File 'lib/rubysl/matrix/matrix.rb', line 293

def [](i, j)
  @rows.fetch(i){return nil}[j]
end

#[]=(i, j, v) ⇒ Object Also known as: set_element, set_component



299
300
301
# File 'lib/rubysl/matrix/matrix.rb', line 299

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

#cloneObject

Returns a clone of the matrix, so that the contents of each do not reference identical objects. There should be no good reason to do this since Matrices are immutable.



510
511
512
# File 'lib/rubysl/matrix/matrix.rb', line 510

def clone
  new_matrix @rows.map(&:dup), column_size
end

#coerce(other) ⇒ Object

The coerce method provides support for Ruby type coercion. This coercion mechanism is used by Ruby to handle mixed-type numeric operations: it is intended to find a compatible common type between the two operands of the operator. See also Numeric#coerce.



965
966
967
968
969
970
971
972
# File 'lib/rubysl/matrix/matrix.rb', line 965

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

#collect(&block) ⇒ Object Also known as: map

Returns a matrix that is the result of iteration of the given block over all elements of the matrix.

Matrix[ [1,2], [3,4] ].collect { |e| e**2 }
  => 1  4
     9 16


359
360
361
362
363
# File 'lib/rubysl/matrix/matrix.rb', line 359

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

#column(j) ⇒ Object

Returns column vector number j of the matrix as a Vector (starting at 0 like an array). When a block is given, the elements of that vector are iterated.



336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
# File 'lib/rubysl/matrix/matrix.rb', line 336

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 = (0 ... row_size).collect {|i|
      @rows[i][j]
    }
    Vector.elements(col, false)
  end
end

#column_vectorsObject

Returns an array of the column vectors of the matrix. See Vector.



986
987
988
989
990
# File 'lib/rubysl/matrix/matrix.rb', line 986

def column_vectors
  (0 ... column_size).collect {|i|
    column(i)
  }
end

#conjugateObject Also known as: conj

Returns the conjugate of the matrix.

Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
  => 1+2i   i  0
        1   2  3
Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].conjugate
  => 1-2i  -i  0
        1   2  3


911
912
913
# File 'lib/rubysl/matrix/matrix.rb', line 911

def conjugate
  collect(&:conjugate)
end

#determinantObject Also known as: det

Returns the determinant of the matrix.

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

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


734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
# File 'lib/rubysl/matrix/matrix.rb', line 734

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

#determinant_eObject Also known as: det_e

deprecated; use Matrix#determinant



816
817
818
819
# File 'lib/rubysl/matrix/matrix.rb', line 816

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

#each(&block) ⇒ Object

Yields all elements of the matrix, starting with those of the first row, or returns an Enumerator is no block given

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


372
373
374
375
376
377
378
# File 'lib/rubysl/matrix/matrix.rb', line 372

def each(&block) # :yield: e
  return to_enum(:each) unless block_given?
  @rows.each do |row|
    row.each(&block)
  end
  self
end

#each_with_index(&block) ⇒ Object

Yields all elements of the matrix, starting with those of the first row, along with the row index and column index, or returns an Enumerator is no block given

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


392
393
394
395
396
397
398
399
400
# File 'lib/rubysl/matrix/matrix.rb', line 392

def each_with_index(&block) # :yield: e, row, column
  return to_enum(:each_with_index) unless block_given?
  @rows.each_with_index do |row, row_index|
    row.each_with_index do |e, col_index|
      yield e, row_index, col_index
    end
  end
  self
end

#elements_to_fObject



999
1000
1001
1002
# File 'lib/rubysl/matrix/matrix.rb', line 999

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

#elements_to_iObject



1004
1005
1006
1007
# File 'lib/rubysl/matrix/matrix.rb', line 1004

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

#elements_to_rObject



1009
1010
1011
1012
# File 'lib/rubysl/matrix/matrix.rb', line 1009

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

#empty?Boolean

Returns true if this is an empty matrix, i.e. if the number of rows or the number of columns is 0.

Returns:

  • (Boolean)


456
457
458
# File 'lib/rubysl/matrix/matrix.rb', line 456

def empty?
  column_size == 0 || row_size == 0
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


500
501
502
503
# File 'lib/rubysl/matrix/matrix.rb', line 500

def eql?(other)
  return false unless Matrix === other
  rows.eql? other.rows
end

#hashObject

Returns a hash-code for the matrix.



517
518
519
# File 'lib/rubysl/matrix/matrix.rb', line 517

def hash
  @rows.hash
end

#imaginaryObject Also known as: imag

Returns the imaginary part of the matrix.

Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
  => 1+2i  i  0
        1  2  3
Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].imaginary
  =>   2i  i  0
        0  0  0


925
926
927
# File 'lib/rubysl/matrix/matrix.rb', line 925

def imaginary
  collect(&:imaginary)
end

#inspectObject

Overrides Object#inspect



1034
1035
1036
1037
1038
1039
1040
# File 'lib/rubysl/matrix/matrix.rb', line 1034

def inspect
  if empty?
    "Matrix.empty(#{row_size}, #{column_size})"
  else
    "Matrix#{@rows.inspect}"
  end
end

#inverseObject Also known as: inv

Returns the inverse of the matrix.

Matrix[[-1, -1], [0, -1]].inverse
  => -1  1
      0 -1


642
643
644
645
# File 'lib/rubysl/matrix/matrix.rb', line 642

def inverse
  Matrix.Raise ErrDimensionMismatch unless square?
  Matrix.I(row_size).send(:inverse_from, self)
end

#minor(*param) ⇒ Object

Returns a section of the matrix. The parameters are either:

  • start_row, nrows, start_col, ncols; OR

  • row_range, col_range

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

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



415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
# File 'lib/rubysl/matrix/matrix.rb', line 415

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
end

#rankObject

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

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


831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
# File 'lib/rubysl/matrix/matrix.rb', line 831

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
  rank = 0
  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

#rank_eObject

deprecated; use Matrix#rank



863
864
865
866
# File 'lib/rubysl/matrix/matrix.rb', line 863

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

#realObject

Returns the real part of the matrix.

Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]]
  => 1+2i  i  0
        1  2  3
Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].real
  =>    1  0  0
        1  2  3


939
940
941
# File 'lib/rubysl/matrix/matrix.rb', line 939

def real
  collect(&:real)
end

#real?Boolean

Returns true if all entries of the matrix are real.

Returns:

  • (Boolean)


463
464
465
# File 'lib/rubysl/matrix/matrix.rb', line 463

def real?
  all?(&:real?)
end

#rectObject Also known as: rectangular

Returns an array containing matrices corresponding to the real and imaginary parts of the matrix

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



949
950
951
# File 'lib/rubysl/matrix/matrix.rb', line 949

def rect
  [real, imag]
end

#regular?Boolean

Returns true if this is a regular (i.e. non-singular) matrix.

Returns:

  • (Boolean)


470
471
472
# File 'lib/rubysl/matrix/matrix.rb', line 470

def regular?
  not singular?
end

#row(i, &block) ⇒ Object

Returns row vector number i of the matrix as a Vector (starting at 0 like an array). When a block is given, the elements of that vector are iterated.



322
323
324
325
326
327
328
329
# File 'lib/rubysl/matrix/matrix.rb', line 322

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

#row_sizeObject

Returns the number of rows.



309
310
311
# File 'lib/rubysl/matrix/matrix.rb', line 309

def row_size
  @rows.size
end

#row_vectorsObject

Returns an array of the row vectors of the matrix. See Vector.



977
978
979
980
981
# File 'lib/rubysl/matrix/matrix.rb', line 977

def row_vectors
  (0 ... row_size).collect {|i|
    row(i)
  }
end

#singular?Boolean

Returns true is this is a singular matrix.

Returns:

  • (Boolean)


477
478
479
# File 'lib/rubysl/matrix/matrix.rb', line 477

def singular?
  determinant == 0
end

#square?Boolean

Returns true is this is a square matrix.

Returns:

  • (Boolean)


484
485
486
# File 'lib/rubysl/matrix/matrix.rb', line 484

def square?
  column_size == row_size
end

#to_aObject

Returns an array of arrays that describe the rows of the matrix.



995
996
997
# File 'lib/rubysl/matrix/matrix.rb', line 995

def to_a
  @rows.collect{|row| row.dup}
end

#to_sObject

Overrides Object#to_s



1021
1022
1023
1024
1025
1026
1027
1028
1029
# File 'lib/rubysl/matrix/matrix.rb', line 1021

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

#traceObject Also known as: tr

Returns the trace (sum of diagonal elements) of the matrix.

Matrix[[7,6], [3,9]].trace
  => 16


874
875
876
877
878
879
# File 'lib/rubysl/matrix/matrix.rb', line 874

def trace
  Matrix.Raise ErrDimensionMismatch unless square?
  (0...column_size).inject(0) do |tr, i|
    tr + @rows[i][i]
  end
end

#transposeObject Also known as: t

Returns the transpose of the matrix.

Matrix[[1,2], [3,4], [5,6]]
  => 1 2
     3 4
     5 6
Matrix[[1,2], [3,4], [5,6]].transpose
  => 1 3 5
     2 4 6


892
893
894
895
# File 'lib/rubysl/matrix/matrix.rb', line 892

def transpose
  return Matrix.empty(column_size, 0) if row_size.zero?
  new_matrix @rows.transpose, row_size
end