Project

General

Profile

Bug #1532 ยป a_matrix_creation.diff

marcandre (Marc-Andre Lafortune), 09/17/2009 02:03 PM

View differences:

lib/matrix.rb
35 35
# arithmetically and algebraically, and determining their mathematical properties (trace, rank,
36 36
# inverse, determinant).
37 37
#
38
# Note that although matrices should theoretically be rectangular, this is not
39
# enforced by the class.
38
# Note that matrices must be rectangular, otherwise an ErrDimensionMismatch is raised.
40 39
#
41
# Also note that the determinant of integer matrices may be incorrectly calculated unless you
40
# Also note that the determinant of integer matrices may be approximated unless you
42 41
# also <tt>require 'mathn'</tt>.  This may be fixed in the future.
43 42
#
44 43
# == Method Catalogue
......
108 107

  
109 108
  # instance creations
110 109
  private_class_method :new
110
  attr_reader :rows
111
  protected :rows
111 112

  
112 113
  #
113 114
  # Creates a matrix where each argument is a row.
......
116 117
  #          -1 66
117 118
  #
118 119
  def Matrix.[](*rows)
119
    new(:init_rows, rows, false)
120
    Matrix.rows(rows, false)
120 121
  end
121 122

  
122 123
  #
......
128 129
  #          -1 66
129 130
  #
130 131
  def Matrix.rows(rows, copy = true)
131
    new(:init_rows, rows, copy)
132
    rows = Matrix.convert_to_array(rows)
133
    rows.map! do |row|
134
      Matrix.convert_to_array(row, copy)
135
    end
136
    size = (rows[0] || []).size
137
    rows.each do |row|
138
      Matrix.Raise ErrDimensionMismatch, "element size differs (#{row.size} should be #{size})" unless row.size == size
139
    end
140
    new rows
132 141
  end
133 142

  
134 143
  #
......
138 147
  #          93 66
139 148
  #
140 149
  def Matrix.columns(columns)
141
    rows = (0 ... columns[0].size).collect {|i|
142
      (0 ... columns.size).collect {|j|
143
        columns[j][i]
144
      }
145
    }
146
    Matrix.rows(rows, false)
150
    Matrix.rows(columns, false).transpose
147 151
  end
148 152

  
149 153
  #
......
160 164
      row[j] = values[j]
161 165
      row
162 166
    }
163
    rows(rows, false)
167
    new rows
164 168
  end
165 169

  
166 170
  #
......
205 209
  #     => 4 5 6
206 210
  #
207 211
  def Matrix.row_vector(row)
208
    case row
209
    when Vector
210
      Matrix.rows([row.to_a], false)
211
    when Array
212
      Matrix.rows([row.dup], false)
213
    else
214
      Matrix.rows([[row]], false)
215
    end
212
    row = Matrix.convert_to_array(row)
213
    new [row]
216 214
  end
217 215

  
218 216
  #
......
224 222
  #        6
225 223
  #
226 224
  def Matrix.column_vector(column)
227
    case column
228
    when Vector
229
      Matrix.columns([column.to_a])
230
    when Array
231
      Matrix.columns([column])
232
    else
233
      Matrix.columns([[column]])
234
    end
225
    column = Matrix.convert_to_array(column)
226
    new [column].transpose
235 227
  end
236 228

  
237 229
  #
238
  # This method is used by the other methods that create matrices, and is of no
239
  # use to general users.
230
  # Matrix.new is private; use Matrix.rows, columns, [], etc... to create.
240 231
  #
241
  def initialize(init_method, *argv)
242
    self.send(init_method, *argv)
232
  def initialize(rows)
233
    # No checking is done at this point. rows must be an Array of Arrays.
234
    @rows = rows
243 235
  end
244 236

  
245
  def init_rows(rows, copy)
246
    if copy
247
      @rows = rows.collect{|row| row.dup}
248
    else
249
      @rows = rows
250
    end
251
    self
237
  def new(rows) # :nodoc:
238
    Matrix.send(:new, rows) # bypass privacy of Matrix.new
252 239
  end
253
  private :init_rows
240
  private :new
254 241

  
255 242
  #
256 243
  # Returns element (+i+,+j+) of the matrix.  That is: row +i+, column +j+.
......
276 263
  end
277 264

  
278 265
  #
279
  # Returns the number of columns.  Note that it is possible to construct a
280
  # matrix with uneven columns (e.g. Matrix[ [1,2,3], [4,5] ]), but this is
281
  # mathematically unsound.  This method uses the first row to determine the
282
  # result.
266
  # Returns the number of columns.
283 267
  #
284 268
  def column_size
285 269
    @rows[0].size
......
324 308
  #
325 309
  def collect(&block) # :yield: e
326 310
    rows = @rows.collect{|row| row.collect(&block)}
327
    Matrix.rows(rows, false)
311
    new(rows)
328 312
  end
329 313
  alias map collect
330 314

  
......
355 339
    rows = @rows[from_row, size_row].collect{|row|
356 340
      row[from_col, size_col]
357 341
    }
358
    Matrix.rows(rows, false)
342
    new(rows)
359 343
  end
360 344

  
361 345
  #--
......
377 361
  end
378 362

  
379 363
  #
380
  # Returns +true+ is this is a square matrix.  See note in column_size about this
381
  # being unreliable, though.
364
  # Returns +true+ is this is a square matrix.
382 365
  #
383 366
  def square?
384 367
    column_size == row_size
......
417 400
  #
418 401
  # Returns a clone of the matrix, so that the contents of each do not reference
419 402
  # identical objects.
403
  # There should be no good reason to do this since Matrices are immutable.
420 404
  #
421 405
  def clone
422
    Matrix.rows(@rows)
406
    new(@rows.map{|row| row.dup})
423 407
  end
424 408

  
425 409
  #
......
447 431
          e * m
448 432
        }
449 433
      }
450
      return Matrix.rows(rows, false)
434
      return new(rows)
451 435
    when Vector
452 436
      m = Matrix.column_vector(m)
453 437
      r = self * m
......
462 446
          end
463 447
        }
464 448
      }
465
      return Matrix.rows(rows, false)
449
      return new(rows)
466 450
    else
467 451
      x, y = m.coerce(self)
468 452
      return x * y
......
494 478
        self[i, j] + m[i, j]
495 479
      }
496 480
    }
497
    Matrix.rows(rows, false)
481
    new(rows)
498 482
  end
499 483

  
500 484
  #
......
522 506
        self[i, j] - m[i, j]
523 507
      }
524 508
    }
525
    Matrix.rows(rows, false)
509
    new(rows)
526 510
  end
527 511

  
528 512
  #
......
539 523
          e / other
540 524
        }
541 525
      }
542
      return Matrix.rows(rows, false)
526
      return new(rows)
543 527
    when Matrix
544 528
      return self * other.inverse
545 529
    else
......
838 822
  #        2 4 6
839 823
  #
840 824
  def transpose
841
    Matrix.columns(@rows)
825
    new @rows.transpose
842 826
  end
843 827
  alias t transpose
844 828

  
......
915 899
    "Matrix"+@rows.inspect
916 900
  end
917 901

  
902
  #
903
  # Converts the obj to an Array. If copy is set to true
904
  # a copy of obj will be made if necessary.
905
  #
906
  def Matrix.convert_to_array(obj, copy = false)
907
    case obj
908
    when Array
909
      copy ? obj.dup : obj
910
    when Vector
911
      obj.to_a
912
    else
913
      begin
914
        converted = obj.to_ary
915
      rescue Exception => e
916
        raise TypeError, "can't convert #{obj.class} into an Array (#{e.message})"
917
      end
918
      raise TypeError, "#{obj.class}#to_ary should return an Array" unless converted.is_a? Array
919
      converted
920
    end
921
  end
922

  
918 923
  # Private CLASS
919 924

  
920 925
  class Scalar < Numeric # :nodoc: