Project

General

Profile

Bug #1532 ยป matrix.patch

marcandre (Marc-Andre Lafortune), 05/29/2009 04:18 AM

View differences:

lib/matrix.rb (working copy)
1 1
#--
2 2
#   matrix.rb -
3 3
#   	$Release Version: 1.0$
4
#   	$Revision: 1.13 $
4
#   	$Revision: 1.14 $
5 5
#       Original Version from Smalltalk-80 version
6 6
#          on July 23, 1985 at 8:37:17 am
7 7
#       by Keiju ISHITSUKA
......
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.
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
......
50 49
# * <tt> Matrix.columns(columns)        </tt>
51 50
# * <tt> Matrix.diagonal(*values)       </tt>
52 51
# * <tt> Matrix.scalar(n, value)        </tt>
53
# * <tt> Matrix.scalar(n, value)        </tt>
54 52
# * <tt> Matrix.identity(n)             </tt>
55 53
# * <tt> Matrix.unit(n)                 </tt>
56 54
# * <tt> Matrix.I(n)                    </tt>
......
102 100
# * <tt> #inspect                       </tt>
103 101
#
104 102
class Matrix
105
  @RCS_ID='-$Id: matrix.rb,v 1.13 2001/12/09 14:22:23 keiju Exp keiju $-'
103
  @RCS_ID='-$Id: matrix.rb,v 1.14 2009/05/28 00:00:00 keiju Exp keiju $-'
106 104

  
107
#  extend Exception2MessageMapper
108 105
  include ExceptionForMatrix
109 106

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

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

  
123 122
  #
124 123
  # Creates a matrix where +rows+ is an array of arrays, each of which is a row
125
  # to the matrix.  If the optional argument +copy+ is false, use the given
124
  # of the matrix.  If the optional argument +copy+ is false, use the given
126 125
  # arrays as the internal structure of the matrix without copying.
127 126
  #   Matrix.rows([[25, 93], [-1, 66]])
128 127
  #      =>  25 93
129 128
  #          -1 66
129
  #
130 130
  def Matrix.rows(rows, copy = true)
131
    new(:init_rows, rows, copy)
131
    rows = Matrix.convert_to_array(rows)
132
    rows.map! do |row|
133
      Matrix.convert_to_array(row, copy)
134
    end
135
    size = (rows[0] || []).size
136
    rows.each do |row|
137
      Matrix.Raise ErrDimensionMismatch, "element size differs (#{row.size} should be #{size})" unless row.size == size
138
    end
139
    new rows, size
132 140
  end
133 141

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

  
150 152
  #
......
156 158
  #
157 159
  def Matrix.diagonal(*values)
158 160
    size = values.size
159
    rows = (0 .. size  - 1).collect {|j|
161
    rows = (0 ... size).collect {|j|
160 162
      row = Array.new(size).fill(0, 0, size)
161 163
      row[j] = values[j]
162 164
      row
163 165
    }
164
    rows(rows, false)
166
    new rows
165 167
  end
166 168

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

  
219 215
  #
......
225 221
  #        6
226 222
  #
227 223
  def Matrix.column_vector(column)
228
    case column
229
    when Vector
230
      Matrix.columns([column.to_a])
231
    when Array
232
      Matrix.columns([column])
233
    else
234
      Matrix.columns([[column]])
235
    end
224
    column = Matrix.convert_to_array(column)
225
    new column.map{|elem| [elem]}, 1
236 226
  end
237 227

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

  
246
  def init_rows(rows, copy)
247
    if copy
248
      @rows = rows.collect{|row| row.dup}
249
    else
250
      @rows = rows
251
    end
252
    self
239
  #
240
  # Use to bypass privacy of Matrix.new
241
  #
242
  def new(rows, column_size = rows[0].size)
243
    Matrix.send(:new, rows, column_size)
253 244
  end
254
  private :init_rows
245
  private :new
255 246

  
256 247
  #
257 248
  # Returns element (+i+,+j+) of the matrix.  That is: row +i+, column +j+.
258 249
  #
259 250
  def [](i, j)
260
    @rows[i][j]
251
    (@rows[i] || [])[j]
261 252
  end
262 253
  alias element []
263 254
  alias component []
......
277 268
  end
278 269

  
279 270
  #
280
  # Returns the number of columns.  Note that it is possible to construct a
281
  # matrix with uneven columns (e.g. Matrix[ [1,2,3], [4,5] ]), but this is
282
  # mathematically unsound.  This method uses the first row to determine the
283
  # result.
271
  # Returns the number of columns.
284 272
  #
285
  def column_size
286
    @rows[0].size
287
  end
273
  attr_reader :column_size
288 274

  
289 275
  #
290 276
  # Returns row vector number +i+ of the matrix as a Vector (starting at 0 like
291 277
  # an array).  When a block is given, the elements of that vector are iterated.
292 278
  #
293
  def row(i) # :yield: e
294
    if block_given?
295
      for e in @rows[i]
296
        yield e
279
  def row(i, &block) # :yield: e
280
    if row = @rows[i]
281
      if block_given?
282
        row.each(&block)
283
      else
284
        Vector.elements(row, false)
297 285
      end
298 286
    else
299
      Vector.elements(@rows[i])
287
      if block_given?
288
        self
289
      else
290
        nil
291
      end
300 292
    end
301 293
  end
302 294

  
......
307 299
  #
308 300
  def column(j) # :yield: e
309 301
    if block_given?
310
      0.upto(row_size - 1) do |i|
302
      row_size.times do |i|
311 303
        yield @rows[i][j]
312
      end
304
      end unless j >= column_size
305
      self
313 306
    else
314
      col = (0 .. row_size - 1).collect {|i|
307
      return nil if j >= column_size
308
      col = (0 ... row_size).collect {|i|
315 309
        @rows[i][j]
316 310
      }
317 311
      Vector.elements(col, false)
......
325 319
  #     => 1  4
326 320
  #        9 16
327 321
  #
328
  def collect # :yield: e
329
    rows = @rows.collect{|row| row.collect{|e| yield e}}
330
    Matrix.rows(rows, false)
322
  def collect(&block) # :yield: e
323
    return to_enum(:collect) unless block_given?
324
    rows = @rows.collect{|row| row.collect(&block)}
325
    new(rows)
331 326
  end
332 327
  alias map collect
333 328

  
......
350 345
      size_col = param[1].end - from_col
351 346
      size_col += 1 unless param[1].exclude_end?
352 347
    when 4
353
      from_row = param[0]
354
      size_row = param[1]
355
      from_col = param[2]
356
      size_col = param[3]
348
      from_row, size_row, from_col, size_col = param
357 349
    else
358 350
      Matrix.Raise ArgumentError, param.inspect
359 351
    end
360

  
352
    return nil if from_row > row_size || from_col > column_size
361 353
    rows = @rows[from_row, size_row].collect{|row|
362 354
      row[from_col, size_col]
363 355
    }
364
    Matrix.rows(rows, false)
356
    new(rows, column_size - from_col)
365 357
  end
366 358

  
367 359
  #--
......
383 375
  end
384 376

  
385 377
  #
386
  # Returns +true+ is this is a square matrix.  See note in column_size about this
387
  # being unreliable, though.
378
  # Returns +true+ is this is a square matrix.
388 379
  #
389 380
  def square?
390 381
    column_size == row_size
......
399 390
  #
400 391
  def ==(other)
401 392
    return false unless Matrix === other
402

  
403
    other.compare_by_row_vectors(@rows)
393
    @rows == other.rows
404 394
  end
395

  
405 396
  def eql?(other)
406 397
    return false unless Matrix === other
407

  
408
    other.compare_by_row_vectors(@rows, :eql?)
398
    @rows.eql? other.rows
409 399
  end
410 400

  
411 401
  #
412
  # Not really intended for general consumption.
413
  #
414
  def compare_by_row_vectors(rows, comparison = :==)
415
    return false unless @rows.size == rows.size
416

  
417
    0.upto(@rows.size - 1) do |i|
418
      return false unless @rows[i].send(comparison, rows[i])
419
    end
420
    true
421
  end
422

  
423
  #
424 402
  # Returns a clone of the matrix, so that the contents of each do not reference
425 403
  # identical objects.
404
  # There should be no good reason to do this since Matrices are immutable.
426 405
  #
427 406
  def clone
428
    Matrix.rows(@rows)
407
    new(@rows.map{|row| row.dup}, column_size)
429 408
  end
430 409

  
431 410
  #
432 411
  # Returns a hash-code for the matrix.
433 412
  #
434 413
  def hash
435
    value = 0
436
    for row in @rows
437
      for e in row
438
        value ^= e.hash
439
      end
440
    end
441
    return value
414
    @rows.hash
442 415
  end
443 416

  
444 417
  #--
......
459 432
          e * m
460 433
        }
461 434
      }
462
      return Matrix.rows(rows, false)
435
      return new(rows, column_size)
463 436
    when Vector
464 437
      m = Matrix.column_vector(m)
465 438
      r = self * m
......
467 440
    when Matrix
468 441
      Matrix.Raise ErrDimensionMismatch if column_size != m.row_size
469 442

  
470
      rows = (0 .. row_size - 1).collect {|i|
471
        (0 .. m.column_size - 1).collect {|j|
443
      rows = (0 ... row_size).collect {|i|
444
        (0 ... m.column_size).collect {|j|
472 445
          vij = 0
473
          0.upto(column_size - 1) do |k|
446
          column_size.times do |k|
474 447
            vij += self[i, k] * m[k, j]
475 448
          end
476 449
          vij
477 450
        }
478 451
      }
479
      return Matrix.rows(rows, false)
452
      return new(rows, m.column_size)
480 453
    else
481 454
      x, y = m.coerce(self)
482 455
      return x * y
......
503 476

  
504 477
    Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
505 478

  
506
    rows = (0 .. row_size - 1).collect {|i|
507
      (0 .. column_size - 1).collect {|j|
479
    rows = (0 ... row_size).collect {|i|
480
      (0 ... column_size).collect {|j|
508 481
        self[i, j] + m[i, j]
509 482
      }
510 483
    }
511
    Matrix.rows(rows, false)
484
    new(rows, column_size)
512 485
  end
513 486

  
514 487
  #
......
531 504

  
532 505
    Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
533 506

  
534
    rows = (0 .. row_size - 1).collect {|i|
535
      (0 .. column_size - 1).collect {|j|
507
    rows = (0 ... row_size).collect {|i|
508
      (0 ... column_size).collect {|j|
536 509
        self[i, j] - m[i, j]
537 510
      }
538 511
    }
539
    Matrix.rows(rows, false)
512
    new(rows, column_size)
540 513
  end
541 514

  
542 515
  #
......
553 526
          e / other
554 527
        }
555 528
      }
556
      return Matrix.rows(rows, false)
529
      return new(rows, column_size)
557 530
    when Matrix
558 531
      return self * other.inverse
559 532
    else
......
578 551
  # Not for public consumption?
579 552
  #
580 553
  def inverse_from(src)
581
    size = row_size - 1
554
    size = row_size
582 555
    a = src.to_a
583 556

  
584
    for k in 0..size
557
    for k in 0...size
585 558
      i = k
586 559
      akk = a[k][k].abs
587
      ((k+1)..size).each do |j|
560
      ((k+1)...size).each do |j|
588 561
        v = a[j][k].abs
589 562
        if v > akk
590 563
          i = j
......
598 571
      end
599 572
      akk = a[k][k]
600 573

  
601
      for i in 0 .. size
574
      for i in 0 ... size
602 575
        next if i == k
603 576
        q = a[i][k].quo(akk)
604 577
        a[i][k] = 0
605 578

  
606
	for j in (k + 1).. size
579
        for j in (k + 1)... size
607 580
          a[i][j] -= a[k][j] * q
608 581
        end
609
        for j in 0..size
582
        for j in 0...size
610 583
          @rows[i][j] -= @rows[k][j] * q
611 584
        end
612 585
      end
613 586

  
614
      for j in (k + 1).. size
587
      for j in (k + 1)...size
615 588
        a[k][j] = a[k][j].quo(akk)
616 589
      end
617
      for j in 0..size
590
      for j in 0...size
618 591
        @rows[k][j] = @rows[k][j].quo(akk)
619 592
      end
620 593
    end
......
630 603
  #        48 99
631 604
  #
632 605
  def ** (other)
606
    Matrix.Raise ErrDimensionMismatch unless square?
633 607
    if other.kind_of?(Integer)
634 608
      x = self
635 609
      if other <= 0
636
        x = self.inverse
637 610
        return Matrix.identity(self.column_size) if other == 0
611
        x = self.inverse
638 612
        other = -other
639 613
      end
640 614
      z = x
......
662 636

  
663 637
  #
664 638
  # Returns the determinant of the matrix.  If the matrix is not square, the
665
  # result is 0. This method's algorism is Gaussian elimination method
639
  # result is 0. This method's algorithm is Gaussian elimination method
666 640
  # and using Numeric#quo(). Beware that using Float values, with their
667 641
  # usual lack of precision, can affect the value returned by this method.  Use
668 642
  # Rational values or Matrix#det_e instead if this is important to you.
669 643
  #
670 644
  #   Matrix[[7,6], [3,9]].determinant
671
  #     => 63.0
645
  #     => 45.0
672 646
  #
673 647
  def determinant
674 648
    return 0 unless square?
675 649

  
676
    size = row_size - 1
650
    size = row_size
677 651
    a = to_a
678 652

  
679 653
    det = 1
680
    k = 0
681
    loop do
654
    for k in 0...size do
682 655
      if (akk = a[k][k]) == 0
683 656
        i = k
684 657
        loop do
685
          return 0 if (ii += 1) > size
658
          return 0 if (i += 1) >= size
686 659
          break unless a[i][k] == 0
687 660
        end
688 661
        a[i], a[k] = a[k], a[i]
......
690 663
        det *= -1
691 664
      end
692 665

  
693
      for i in k + 1 .. size
666
      for i in k + 1 ... size
694 667
        q = a[i][k].quo(akk)
695
        (k + 1).upto(size) do |j|
668
        for j in k + 1 ... size
696 669
          a[i][j] -= a[k][j] * q
697 670
        end
698 671
      end
699 672
      det *= akk
700
      break unless (k += 1) <= size
701 673
    end
702 674
    det
703 675
  end
......
705 677

  
706 678
  #
707 679
  # Returns the determinant of the matrix.  If the matrix is not square, the
708
  # result is 0. This method's algorism is Gaussian elimination method.
709
  # This method uses Euclidean algorism. If all elements are integer,
680
  # result is 0. This method's algorithm is Gaussian elimination method.
681
  # This method uses Euclidean algorithm. If all elements are integer,
710 682
  # really exact value. But, if an element is a float, can't return
711 683
  # exact value.
712 684
  #
......
716 688
  def determinant_e
717 689
    return 0 unless square?
718 690

  
719
    size = row_size - 1
691
    size = row_size
720 692
    a = to_a
721 693

  
722 694
    det = 1
723
    k = 0
724
    loop do
695
    for k in 0...size
725 696
      if a[k][k].zero?
726 697
        i = k
727 698
        loop do
728
          return 0 if (i += 1) > size
699
          return 0 if (i += 1) >= size
729 700
          break unless a[i][k].zero?
730 701
        end
731 702
        a[i], a[k] = a[k], a[i]
732 703
        det *= -1
733 704
      end
734 705

  
735
      for i in (k + 1)..size
706
      for i in (k + 1)...size
736 707
        q = a[i][k].quo(a[k][k])
737
        k.upto(size) do |j|
708
        for j in k...size do
738 709
          a[i][j] -= a[k][j] * q
739 710
        end
740 711
        unless a[i][k].zero?
......
744 715
        end
745 716
      end
746 717
      det *= a[k][k]
747
      break unless (k += 1) <= size
748 718
    end
749 719
    det
750 720
  end
......
769 739
      a_row_size = row_size
770 740
    end
771 741
    rank = 0
772
    k = 0
773
    loop do
742
    for k in 0...a_column_size
774 743
      if (akk = a[k][k]) == 0
775 744
        i = k
776 745
        exists = true
777 746
        loop do
778
          if (i += 1) > a_column_size - 1
747
          if (i += 1) >= a_column_size
779 748
            exists = false
780 749
            break
781 750
          end
......
788 757
          i = k
789 758
          exists = true
790 759
          loop do
791
            if (i += 1) > a_row_size - 1
760
            if (i += 1) >= a_row_size
792 761
              exists = false
793 762
              break
794 763
            end
795 764
            break unless a[k][i] == 0
796 765
          end
797 766
          if exists
798
            k.upto(a_column_size - 1) do |j|
767
            for j in k...a_column_size do
799 768
              a[j][k], a[j][i] = a[j][i], a[j][k]
800 769
            end
801 770
            akk = a[k][k]
......
805 774
        end
806 775
      end
807 776

  
808
      for i in (k + 1)..(a_row_size - 1)
777
      for i in (k + 1)...a_row_size
809 778
        q = a[i][k].quo(akk)
810
	for j in (k + 1)..(a_column_size - 1)
779
        for j in (k + 1)...a_column_size
811 780
          a[i][j] -= a[k][j] * q
812 781
        end
813 782
      end
814 783
      rank += 1
815
      break unless (k += 1) <= a_column_size - 1
816 784
    end
817 785
    return rank
818 786
  end
819 787

  
820 788
  #
821 789
  # Returns the rank of the matrix. This method uses Euclidean
822
  # algorism. If all elements are integer, really exact value. But, if
790
  # algorithm. If all elements are integer, really exact value. But, if
823 791
  # an element is a float, can't return exact value.
824 792
  #
825 793
  #   Matrix[[7,6], [3,9]].rank
......
830 798
    a_column_size = column_size
831 799
    a_row_size = row_size
832 800
    pi = 0
833
    (0 ... a_column_size).each do |j|
801
    a_column_size.times do |j|
834 802
      if i = (pi ... a_row_size).find{|i0| !a[i0][j].zero?}
835 803
        if i != pi
836 804
          a[pi], a[i] = a[i], a[pi]
......
858 826
  #     => 16
859 827
  #
860 828
  def trace
829
    Matrix.Raise ErrDimensionMismatch unless square?
861 830
    tr = 0
862
    0.upto(column_size - 1) do |i|
831
    column_size.times do |i|
863 832
      tr += @rows[i][i]
864 833
    end
865 834
    tr
......
877 846
  #        2 4 6
878 847
  #
879 848
  def transpose
880
    Matrix.columns(@rows)
849
    new @rows.transpose, row_size
881 850
  end
882 851
  alias t transpose
883 852

  
......
901 870
  # Returns an array of the row vectors of the matrix.  See Vector.
902 871
  #
903 872
  def row_vectors
904
    rows = (0 .. row_size - 1).collect {|i|
873
    rows = (0 ... row_size).collect {|i|
905 874
      row(i)
906 875
    }
907 876
    rows
......
911 880
  # Returns an array of the column vectors of the matrix.  See Vector.
912 881
  #
913 882
  def column_vectors
914
    columns = (0 .. column_size - 1).collect {|i|
883
    columns = (0 ... column_size).collect {|i|
915 884
      column(i)
916 885
    }
917 886
    columns
......
921 890
  # Returns an array of arrays that describe the rows of the matrix.
922 891
  #
923 892
  def to_a
924
    @rows.collect{|row| row.collect{|e| e}}
893
    @rows.collect{|row| row.dup}
925 894
  end
926 895

  
927 896
  def elements_to_f
......
944 913
  # Overrides Object#to_s
945 914
  #
946 915
  def to_s
947
    "Matrix[" + @rows.collect{|row|
948
      "[" + row.collect{|e| e.to_s}.join(", ") + "]"
949
    }.join(", ")+"]"
916
    if row_size == 0 && column_size > 0
917
      "Matrix.columns([" + (["[]"] * column_size).join(", ") + "])"
918
    else
919
      "Matrix[" + @rows.collect{|row|
920
        "[" + row.collect{|e| e.to_s}.join(", ") + "]"
921
      }.join(", ")+"]"
922
    end
950 923
  end
951 924

  
952 925
  #
953 926
  # Overrides Object#inspect
954 927
  #
955 928
  def inspect
929
    return to_s if row_size == 0 && column_size > 0
956 930
    "Matrix"+@rows.inspect
957 931
  end
958 932

  
933
  #
934
  # Converts the obj to an Array. If copy is set to true
935
  # a copy of obj will be made if necessary.
936
  #
937
  def Matrix.convert_to_array(obj, copy = false)
938
    case obj
939
    when Array
940
      copy ? obj.dup : obj
941
    when Vector
942
      obj.to_a
943
    else
944
      begin
945
        converted = obj.to_ary
946
      rescue Exception => e
947
        raise TypeError, "can't convert #{obj.class} into an Array (#{e.message})"
948
      end
949
      raise TypeError, "#{obj.class}#to_ary should return an Array" unless converted.is_a? Array
950
      converted
951
    end
952
  end
953

  
959 954
  # Private CLASS
960 955

  
961 956
  class Scalar < Numeric # :nodoc:
......
1013 1008
      when Vector
1014 1009
        Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix"
1015 1010
      when Matrix
1016
	self * other.inverse
1011
        self * other.inverse
1017 1012
      else
1018 1013
        x, y = other.coerce(self)
1019 1014
        x.quo(y)
......
1082 1077
  #INSTANCE CREATION
1083 1078

  
1084 1079
  private_class_method :new
1085

  
1080
  attr_reader :elements
1081
  protected :elements
1086 1082
  #
1087 1083
  # Creates a Vector from a list of elements.
1088 1084
  #   Vector[7, 4, ...]
1089 1085
  #
1090 1086
  def Vector.[](*array)
1091
    new(:init_elements, array, copy = false)
1087
    new array
1092 1088
  end
1093 1089

  
1094 1090
  #
......
1096 1092
  # whether the array itself or a copy is used internally.
1097 1093
  #
1098 1094
  def Vector.elements(array, copy = true)
1099
    new(:init_elements, array, copy)
1095
    new Matrix.convert_to_array(array, copy)
1100 1096
  end
1101 1097

  
1102 1098
  #
1103 1099
  # For internal use.
1104 1100
  #
1105
  def initialize(method, array, copy)
1106
    self.send(method, array, copy)
1101
  def initialize(array)
1102
    @elements = array
1107 1103
  end
1108 1104

  
1109
  #
1110
  # For internal use.
1111
  #
1112
  def init_elements(array, copy)
1113
    if copy
1114
      @elements = array.dup
1115
    else
1116
      @elements = array
1117
    end
1118
  end
1119

  
1120 1105
  # ACCESSING
1121 1106

  
1122 1107
  #
......
1150 1135
  # Iterate over the elements of this vector and +v+ in conjunction.
1151 1136
  #
1152 1137
  def each2(v) # :yield: e1, e2
1138
    return to_enum(:each2, v) unless block_given?
1153 1139
    Vector.Raise ErrDimensionMismatch if size != v.size
1154
    0.upto(size - 1) do |i|
1140
    size.times do |i|
1155 1141
      yield @elements[i], v[i]
1156 1142
    end
1157 1143
  end
......
1161 1147
  # in conjunction.
1162 1148
  #
1163 1149
  def collect2(v) # :yield: e1, e2
1150
    return to_enum(:collect2, v) unless block_given?
1164 1151
    Vector.Raise ErrDimensionMismatch if size != v.size
1165
    (0 .. size - 1).collect do |i|
1152
    (0 ... size).collect do |i|
1166 1153
      yield @elements[i], v[i]
1167 1154
    end
1168 1155
  end
......
1176 1163
  #
1177 1164
  def ==(other)
1178 1165
    return false unless Vector === other
1179

  
1180
    other.compare_by(@elements)
1166
    @elements == other.elements
1181 1167
  end
1182 1168
  def eql?(other)
1183 1169
    return false unless Vector === other
1184

  
1185
    other.compare_by(@elements, :eql?)
1170
    @elements.eql? other.elements
1186 1171
  end
1187 1172

  
1188 1173
  #
1189
  # For internal use.
1190
  #
1191
  def compare_by(elements, comparison = :==)
1192
    @elements.send(comparison, elements)
1193
  end
1194

  
1195
  #
1196 1174
  # Return a copy of the vector.
1197 1175
  #
1198 1176
  def clone
......
1285 1263
  #
1286 1264
  # Like Array#collect.
1287 1265
  #
1288
  def collect # :yield: e
1289
    els = @elements.collect {|v|
1290
      yield v
1291
    }
1266
  def collect(&block) # :yield: e
1267
    return to_enum(:collect) unless block_given?
1268
    els = @elements.collect(&block)
1292 1269
    Vector.elements(els, false)
1293 1270
  end
1294 1271
  alias map collect
......
1296 1273
  #
1297 1274
  # Like Vector#collect2, but returns a Vector instead of an Array.
1298 1275
  #
1299
  def map2(v) # :yield: e1, e2
1300
    els = collect2(v) {|v1, v2|
1301
      yield v1, v2
1302
    }
1276
  def map2(v, &block) # :yield: e1, e2
1277
    return to_enum(:map2, v) unless block_given?
1278
    els = collect2(v, &block)
1303 1279
    Vector.elements(els, false)
1304 1280
  end
1305 1281

  
......
1376 1352
  end
1377 1353
end
1378 1354

  
1379

  
1380 1355
# Documentation comments:
1381 1356
#  - Matrix#coerce and Vector#coerce need to be documented