Fix up Rubinius specific library specs.
[rbx.git] / lib / matrix.rb
blob7850a3fbdac802198ecd6591541cd98113a6c4aa
1 #!/usr/local/bin/ruby
2 #--
3 #   matrix.rb - 
4 #       $Release Version: 1.0$
5 #       $Revision: 1.11 $
6 #       $Date: 1999/10/06 11:01:53 $
7 #       Original Version from Smalltalk-80 version
8 #          on July 23, 1985 at 8:37:17 am
9 #       by Keiju ISHITSUKA
10 #++
12 # = matrix.rb
14 # An implementation of Matrix and Vector classes.
16 # Author:: Keiju ISHITSUKA
17 # Documentation:: Gavin Sinclair (sourced from <i>Ruby in a Nutshell</i> (Matsumoto, O'Reilly)) 
19 # See classes Matrix and Vector for documentation. 
23 require "e2mmap.rb"
25 module ExceptionForMatrix # :nodoc:
26   extend Exception2MessageMapper
27   def_e2message(TypeError, "wrong argument type %s (expected %s)")
28   def_e2message(ArgumentError, "Wrong # of arguments(%d for %d)")
29   
30   def_exception("ErrDimensionMismatch", "\#{self.name} dimension mismatch")
31   def_exception("ErrNotRegular", "Not Regular Matrix")
32   def_exception("ErrOperationNotDefined", "This operation(%s) can\\'t defined")
33 end
36 # The +Matrix+ class represents a mathematical matrix, and provides methods for creating
37 # special-case matrices (zero, identity, diagonal, singular, vector), operating on them
38 # arithmetically and algebraically, and determining their mathematical properties (trace, rank,
39 # inverse, determinant).
41 # Note that although matrices should theoretically be rectangular, this is not
42 # enforced by the class.
44 # Also note that the determinant of integer matrices may be incorrectly calculated unless you
45 # also <tt>require 'mathn'</tt>.  This may be fixed in the future.
47 # == Method Catalogue
49 # To create a matrix:
50 # * <tt> Matrix[*rows]                  </tt>
51 # * <tt> Matrix.[](*rows)               </tt>
52 # * <tt> Matrix.rows(rows, copy = true) </tt>
53 # * <tt> Matrix.columns(columns)        </tt>
54 # * <tt> Matrix.diagonal(*values)       </tt>
55 # * <tt> Matrix.scalar(n, value)        </tt>
56 # * <tt> Matrix.scalar(n, value)        </tt>
57 # * <tt> Matrix.identity(n)             </tt>
58 # * <tt> Matrix.unit(n)                 </tt>
59 # * <tt> Matrix.I(n)                    </tt>
60 # * <tt> Matrix.zero(n)                 </tt>
61 # * <tt> Matrix.row_vector(row)         </tt>
62 # * <tt> Matrix.column_vector(column)   </tt>
64 # To access Matrix elements/columns/rows/submatrices/properties: 
65 # * <tt>  [](i, j)                      </tt>
66 # * <tt> #row_size                      </tt>
67 # * <tt> #column_size                   </tt>
68 # * <tt> #row(i)                        </tt>
69 # * <tt> #column(j)                     </tt>
70 # * <tt> #collect                       </tt>
71 # * <tt> #map                           </tt>
72 # * <tt> #minor(*param)                 </tt>
74 # Properties of a matrix:
75 # * <tt> #regular?                      </tt>
76 # * <tt> #singular?                     </tt>
77 # * <tt> #square?                       </tt>
79 # Matrix arithmetic:
80 # * <tt>  *(m)                          </tt>
81 # * <tt>  +(m)                          </tt>
82 # * <tt>  -(m)                          </tt>
83 # * <tt> #/(m)                          </tt>
84 # * <tt> #inverse                       </tt>
85 # * <tt> #inv                           </tt>
86 # * <tt>  **                            </tt>
88 # Matrix functions:
89 # * <tt> #determinant                   </tt>
90 # * <tt> #det                           </tt>
91 # * <tt> #rank                          </tt>
92 # * <tt> #trace                         </tt>
93 # * <tt> #tr                            </tt>
94 # * <tt> #transpose                     </tt>
95 # * <tt> #t                             </tt>
97 # Conversion to other data types:
98 # * <tt> #coerce(other)                 </tt>
99 # * <tt> #row_vectors                   </tt>
100 # * <tt> #column_vectors                </tt>
101 # * <tt> #to_a                          </tt>
103 # String representations:
104 # * <tt> #to_s                          </tt>
105 # * <tt> #inspect                       </tt>
107 class Matrix
108   
109 #  extend Exception2MessageMapper
110   include ExceptionForMatrix
111   
112   # instance creations
113   private_class_method :new
114   
115   #
116   # Creates a matrix where each argument is a row.
117   #   Matrix[ [25, 93], [-1, 66] ]
118   #      =>  25 93
119   #          -1 66
120   #
121   def Matrix.[](*rows)
122     new(:init_rows, rows, false)
123   end
124   
125   #
126   # Creates a matrix where +rows+ is an array of arrays, each of which is a row
127   # to the matrix.  If the optional argument +copy+ is false, use the given
128   # arrays as the internal structure of the matrix without copying.
129   #   Matrix.rows([[25, 93], [-1, 66]])
130   #      =>  25 93
131   #          -1 66
132   def Matrix.rows(rows, copy = true)
133     new(:init_rows, rows, copy)
134   end
135   
136   #
137   # Creates a matrix using +columns+ as an array of column vectors.
138   #   Matrix.columns([[25, 93], [-1, 66]])
139   #      =>  25 -1
140   #          93 66
141   #
142   #
143   def Matrix.columns(columns)
144     rows = (0 .. columns[0].size - 1).collect {
145       |i|
146       (0 .. columns.size - 1).collect {
147         |j|
148         columns[j][i]
149       }
150     }
151     Matrix.rows(rows, false)
152   end
153   
154   #
155   # Creates a matrix where the diagonal elements are composed of +values+.
156   #   Matrix.diagonal(9, 5, -3)
157   #     =>  9  0  0
158   #         0  5  0
159   #         0  0 -3
160   #
161   def Matrix.diagonal(*values)
162     size = values.size
163     rows = (0 .. size  - 1).collect {
164       |j|
165       row = Array.new(size).fill(0, 0, size)
166       row[j] = values[j]
167       row
168     }
169     rows(rows, false)
170   end
171   
172   #
173   # Creates an +n+ by +n+ diagonal matrix where each diagonal element is
174   # +value+.
175   #   Matrix.scalar(2, 5)
176   #     => 5 0
177   #        0 5
178   #
179   def Matrix.scalar(n, value)
180     Matrix.diagonal(*Array.new(n).fill(value, 0, n))
181   end
183   #
184   # Creates an +n+ by +n+ identity matrix.
185   #   Matrix.identity(2)
186   #     => 1 0
187   #        0 1
188   #
189   def Matrix.identity(n)
190     Matrix.scalar(n, 1)
191   end
192   class << Matrix 
193     alias unit identity
194     alias I identity
195   end
196   
197   #
198   # Creates an +n+ by +n+ zero matrix.
199   #   Matrix.zero(2)
200   #     => 0 0
201   #        0 0
202   #
203   def Matrix.zero(n)
204     Matrix.scalar(n, 0)
205   end
206   
207   #
208   # Creates a single-row matrix where the values of that row are as given in
209   # +row+.
210   #   Matrix.row_vector([4,5,6])
211   #     => 4 5 6
212   #
213   def Matrix.row_vector(row)
215     case row
216     when Vector
217       Matrix.rows([row.to_a], false)
218     when Array
219       Matrix.rows([row.dup], false)
220     else
221       Matrix.rows([[row]], false)
222     end
223   end
224   
225   #
226   # Creates a single-column matrix where the values of that column are as given
227   # in +column+.
228   #   Matrix.column_vector([4,5,6])
229   #     => 4
230   #        5
231   #        6
232   #
233   def Matrix.column_vector(column)
234     case column
235     when Vector
236       Matrix.columns([column.to_a])
237     when Array
238       Matrix.columns([column])
239     else
240       Matrix.columns([[column]])
241     end
242   end
244   #
245   # This method is used by the other methods that create matrices, and is of no
246   # use to general users.
247   #
248   def initialize(init_method, *argv)
249     self.send(init_method, *argv)
250   end
251   
252   def init_rows(rows, copy)
253     if copy
254       @rows = rows.collect{|row| row.dup}
255     else
256       @rows = rows
257     end
258     self
259   end
260   private :init_rows
261   
262   #
263   # Returns element (+i+,+j+) of the matrix.  That is: row +i+, column +j+.
264   #
265   def [](i, j)
266     @rows[i][j]
267   end
269   #
270   # Returns the number of rows.
271   #
272   def row_size
273     @rows.size
274   end
275   
276   #
277   # Returns the number of columns.  Note that it is possible to construct a
278   # matrix with uneven columns (e.g. Matrix[ [1,2,3], [4,5] ]), but this is
279   # mathematically unsound.  This method uses the first row to determine the
280   # result.
281   #
282   def column_size
283     @rows[0].size
284   end
286   #
287   # Returns row vector number +i+ of the matrix as a Vector (starting at 0 like
288   # an array).  When a block is given, the elements of that vector are iterated.
289   #
290   def row(i) # :yield: e
291     if block_given?
292       for e in @rows[i]
293         yield e
294       end
295     else
296       Vector.elements(@rows[i])
297     end
298   end
300   #
301   # Returns column vector number +j+ of the matrix as a Vector (starting at 0
302   # like an array).  When a block is given, the elements of that vector are
303   # iterated.
304   #
305   def column(j) # :yield: e
306     if block_given?
307       0.upto(row_size - 1) do
308         |i|
309         yield @rows[i][j]
310       end
311     else
312       col = (0 .. row_size - 1).collect {
313         |i|
314         @rows[i][j]
315       }
316       Vector.elements(col, false)
317     end
318   end
319   
320   #
321   # Returns a matrix that is the result of iteration of the given block over all
322   # elements of the matrix.
323   #   Matrix[ [1,2], [3,4] ].collect { |i| i**2 }
324   #     => 1  4
325   #        9 16
326   #
327   def collect # :yield: e
328     rows = @rows.collect{|row| row.collect{|e| yield e}}
329     Matrix.rows(rows, false)
330   end
331   alias map collect
332   
333   #
334   # Returns a section of the matrix.  The parameters are either:
335   # *  start_row, nrows, start_col, ncols; OR
336   # *  col_range, row_range
337   #
338   #   Matrix.diagonal(9, 5, -3).minor(0..1, 0..2)
339   #     => 9 0 0
340   #        0 5 0
341   #
342   def minor(*param)
343     case param.size
344     when 2
345       from_row = param[0].first
346       size_row = param[0].end - from_row
347       size_row += 1 unless param[0].exclude_end?
348       from_col = param[1].first
349       size_col = param[1].end - from_col
350       size_col += 1 unless param[1].exclude_end?
351     when 4
352       from_row = param[0]
353       size_row = param[1]
354       from_col = param[2]
355       size_col = param[3]
356     else
357       Matrix.Raise ArgumentError, param.inspect
358     end
359     
360     rows = @rows[from_row, size_row].collect{
361       |row|
362       row[from_col, size_col]
363     }
364     Matrix.rows(rows, false)
365   end
367   #--
368   # TESTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
369   #++
371   #
372   # Returns +true+ if this is a regular matrix.
373   #
374   def regular?
375     square? and rank == column_size
376   end
377   
378   #
379   # Returns +true+ is this is a singular (i.e. non-regular) matrix.
380   #
381   def singular?
382     not regular?
383   end
385   #
386   # Returns +true+ is this is a square matrix.  See note in column_size about this
387   # being unreliable, though.
388   #
389   def square?
390     column_size == row_size
391   end
392   
393   #--
394   # OBJECT METHODS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
395   #++
397   #
398   # Returns +true+ if and only if the two matrices contain equal elements.
399   #
400   def ==(other)
401     return false unless Matrix === other
402     
403     other.compare_by_row_vectors(@rows)
404   end
405   alias eql? ==
406   
407   #
408   # Not really intended for general consumption.
409   #
410   def compare_by_row_vectors(rows)
411     return false unless @rows.size == rows.size
412     
413     0.upto(@rows.size - 1) do
414       |i|
415       return false unless @rows[i] == rows[i]
416     end
417     true
418   end
419   
420   #
421   # Returns a clone of the matrix, so that the contents of each do not reference
422   # identical objects.
423   #
424   def clone
425     Matrix.rows(@rows)
426   end
427   
428   #
429   # Returns a hash-code for the matrix.
430   #
431   def hash
432     value = 0
433     for row in @rows
434       for e in row
435         value ^= e.hash
436       end
437     end
438     return value
439   end
440   
441   #--
442   # ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
443   #++
444   
445   #
446   # Matrix multiplication.
447   #   Matrix[[2,4], [6,8]] * Matrix.identity(2)
448   #     => 2 4
449   #        6 8
450   #
451   def *(m) # m is matrix or vector or number
452     case(m)
453     when Numeric
454       rows = @rows.collect {
455         |row|
456         row.collect {
457           |e|
458           e * m
459         }
460       }
461       return Matrix.rows(rows, false)
462     when Vector
463       m = Matrix.column_vector(m)
464       r = self * m
465       return r.column(0)
466     when Matrix
467       Matrix.Raise ErrDimensionMismatch if column_size != m.row_size
468     
469       rows = (0 .. row_size - 1).collect {
470         |i|
471         (0 .. m.column_size - 1).collect {
472           |j|
473           vij = 0
474           0.upto(column_size - 1) do
475             |k|
476             vij += self[i, k] * m[k, j]
477           end
478           vij
479         }
480       }
481       return Matrix.rows(rows, false)
482     else
483       x, y = m.coerce(self)
484       return x * y
485     end
486   end
487   
488   #
489   # Matrix addition.
490   #   Matrix.scalar(2,5) + Matrix[[1,0], [-4,7]]
491   #     =>  6  0
492   #        -4 12
493   #
494   def +(m)
495     case m
496     when Numeric
497       Matrix.Raise ErrOperationNotDefined, "+"
498     when Vector
499       m = Matrix.column_vector(m)
500     when Matrix
501     else
502       x, y = m.coerce(self)
503       return x + y
504     end
505     
506     Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
507     
508     rows = (0 .. row_size - 1).collect {
509       |i|
510       (0 .. column_size - 1).collect {
511         |j|
512         self[i, j] + m[i, j]
513       }
514     }
515     Matrix.rows(rows, false)
516   end
518   #
519   # Matrix subtraction.
520   #   Matrix[[1,5], [4,2]] - Matrix[[9,3], [-4,1]]
521   #     => -8  2
522   #         8  1
523   #
524   def -(m)
525     case m
526     when Numeric
527       Matrix.Raise ErrOperationNotDefined, "-"
528     when Vector
529       m = Matrix.column_vector(m)
530     when Matrix
531     else
532       x, y = m.coerce(self)
533       return x - y
534     end
535     
536     Matrix.Raise ErrDimensionMismatch unless row_size == m.row_size and column_size == m.column_size
537     
538     rows = (0 .. row_size - 1).collect {
539       |i|
540       (0 .. column_size - 1).collect {
541         |j|
542         self[i, j] - m[i, j]
543       }
544     }
545     Matrix.rows(rows, false)
546   end
547   
548   #
549   # Matrix division (multiplication by the inverse).
550   #   Matrix[[7,6], [3,9]] / Matrix[[2,9], [3,1]]
551   #     => -7  1
552   #        -3 -6
553   #
554   def /(other)
555     case other
556     when Numeric
557       rows = @rows.collect {
558         |row|
559         row.collect {
560           |e|
561           e / other
562         }
563       }
564       return Matrix.rows(rows, false)
565     when Matrix
566       return self * other.inverse
567     else
568       x, y = other.coerce(self)
569       rerurn x / y
570     end
571   end
573   #
574   # Returns the inverse of the matrix.
575   #   Matrix[[1, 2], [2, 1]].inverse
576   #     => -1  1
577   #         0 -1
578   #
579   def inverse
580     Matrix.Raise ErrDimensionMismatch unless square?
581     Matrix.I(row_size).inverse_from(self)
582   end
583   alias inv inverse
585   #
586   # Not for public consumption?
587   #
588   def inverse_from(src)
589     size = row_size - 1
590     a = src.to_a
591     
592     for k in 0..size
593       if (akk = a[k][k]) == 0
594         i = k
595         begin
596           Matrix.Raise ErrNotRegular if (i += 1) > size
597         end while a[i][k] == 0
598         a[i], a[k] = a[k], a[i]
599         @rows[i], @rows[k] = @rows[k], @rows[i]
600         akk = a[k][k]
601       end
602       
603       for i in 0 .. size
604         next if i == k
605         q = a[i][k] / akk
606         a[i][k] = 0
607         
608         (k + 1).upto(size) do   
609           |j|
610           a[i][j] -= a[k][j] * q
611         end
612         0.upto(size) do
613           |j|
614           @rows[i][j] -= @rows[k][j] * q
615         end
616       end
617       
618       (k + 1).upto(size) do
619         |j|
620         a[k][j] /= akk
621       end
622       0.upto(size) do
623         |j|
624         @rows[k][j] /= akk
625       end
626     end
627     self
628   end
629   #alias reciprocal inverse
630   
631   #
632   # Matrix exponentiation.  Defined for integer powers only.  Equivalent to
633   # multiplying the matrix by itself N times.
634   #   Matrix[[7,6], [3,9]] ** 2
635   #     => 67 96
636   #        48 99
637   #
638   def ** (other)
639     if other.kind_of?(Integer)
640       x = self
641       if other <= 0
642         x = self.inverse
643         return Matrix.identity(self.column_size) if other == 0
644         other = -other
645       end
646       z = x
647       n = other  - 1
648       while n != 0
649         while (div, mod = n.divmod(2)
650                mod == 0)
651           x = x * x
652           n = div
653         end
654         z *= x
655         n -= 1
656       end
657       z
658     elsif other.kind_of?(Float) || defined?(Rational) && other.kind_of?(Rational)
659       Matrix.Raise ErrOperationNotDefined, "**"
660     else
661       Matrix.Raise ErrOperationNotDefined, "**"
662     end
663   end
664   
665   #--
666   # MATRIX FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
667   #++
668   
669   #
670   # Returns the determinant of the matrix.  If the matrix is not square, the
671   # result is 0.
672   #   Matrix[[7,6], [3,9]].determinant
673   #     => 63
674   #
675   def determinant
676     return 0 unless square?
677     
678     size = row_size - 1
679     a = to_a
680     
681     det = 1
682     k = 0
683     begin 
684       if (akk = a[k][k]) == 0
685         i = k
686         begin
687           return 0 if (i += 1) > size
688         end while a[i][k] == 0
689         a[i], a[k] = a[k], a[i]
690         akk = a[k][k]
691         det *= -1
692       end
693       (k + 1).upto(size) do
694         |i|
695         q = a[i][k] / akk
696         (k + 1).upto(size) do
697           |j|
698           a[i][j] -= a[k][j] * q
699         end
700       end
701       det *= akk
702     end while (k += 1) <= size
703     det
704   end
705   alias det determinant
706         
707   #
708   # Returns the rank of the matrix.  Beware that using Float values, with their
709   # usual lack of precision, can affect the value returned by this method.  Use
710   # Rational values instead if this is important to you.
711   #   Matrix[[7,6], [3,9]].rank
712   #     => 2
713   #
714   def rank
715     if column_size > row_size
716       a = transpose.to_a
717       a_column_size = row_size
718       a_row_size = column_size
719     else
720       a = to_a
721       a_column_size = column_size
722       a_row_size = row_size
723     end
724     rank = 0
725     k = 0
726     begin
727       if (akk = a[k][k]) == 0
728         i = k
729         exists = true
730         begin
731           if (i += 1) > a_column_size - 1
732             exists = false
733             break
734           end
735         end while a[i][k] == 0
736         if exists
737           a[i], a[k] = a[k], a[i]
738           akk = a[k][k]
739         else
740           i = k
741           exists = true
742           begin
743             if (i += 1) > a_row_size - 1
744               exists = false
745               break
746             end
747           end while a[k][i] == 0
748           if exists
749             k.upto(a_column_size - 1) do
750               |j|
751               a[j][k], a[j][i] = a[j][i], a[j][k]
752             end
753             akk = a[k][k]
754           else
755             next
756           end
757         end
758       end
759       (k + 1).upto(a_row_size - 1) do
760         |i|
761         q = a[i][k] / akk
762         (k + 1).upto(a_column_size - 1) do
763           |j|
764           a[i][j] -= a[k][j] * q
765         end
766       end
767       rank += 1
768     end while (k += 1) <= a_column_size - 1
769     return rank
770   end
772   #
773   # Returns the trace (sum of diagonal elements) of the matrix.
774   #   Matrix[[7,6], [3,9]].trace
775   #     => 16
776   #
777   def trace
778     tr = 0
779     0.upto(column_size - 1) do
780       |i|
781       tr += @rows[i][i]
782     end
783     tr
784   end
785   alias tr trace
786   
787   #
788   # Returns the transpose of the matrix.
789   #   Matrix[[1,2], [3,4], [5,6]]
790   #     => 1 2
791   #        3 4
792   #        5 6
793   #   Matrix[[1,2], [3,4], [5,6]].transpose
794   #     => 1 3 5
795   #        2 4 6
796   #
797   def transpose
798     Matrix.columns(@rows)
799   end
800   alias t transpose
801   
802   #--
803   # CONVERTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
804   #++
805   
806   #
807   # FIXME: describe #coerce.
808   #
809   def coerce(other)
810     case other
811     when Numeric
812       return Scalar.new(other), self
813     else
814       raise TypeError, "#{self.class} can't be coerced into #{other.class}"
815     end
816   end
818   #
819   # Returns an array of the row vectors of the matrix.  See Vector.
820   #
821   def row_vectors
822     rows = (0 .. row_size - 1).collect {
823       |i|
824       row(i)
825     }
826     rows
827   end
828   
829   #
830   # Returns an array of the column vectors of the matrix.  See Vector.
831   #
832   def column_vectors
833     columns = (0 .. column_size - 1).collect {
834       |i|
835       column(i)
836     }
837     columns
838   end
839   
840   #
841   # Returns an array of arrays that describe the rows of the matrix.
842   #
843   def to_a
844     @rows.collect{|row| row.collect{|e| e}}
845   end
846   
847   #--
848   # PRINTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
849   #++
850   
851   #
852   # Overrides Object#to_s
853   #
854   def to_s
855     "Matrix[" + @rows.collect{
856       |row|
857       "[" + row.collect{|e| e.to_s}.join(", ") + "]"
858     }.join(", ")+"]"
859   end
860   
861   #
862   # Overrides Object#inspect
863   #
864   def inspect
865     "Matrix"+@rows.inspect
866   end
867   
868   # Private CLASS
869   
870   class Scalar < Numeric # :nodoc:
871     include ExceptionForMatrix
872     
873     def initialize(value)
874       @value = value
875     end
876     
877     # ARITHMETIC
878     def +(other)
879       case other
880       when Numeric
881         Scalar.new(@value + other)
882       when Vector, Matrix
883         Scalar.Raise WrongArgType, other.class, "Numeric or Scalar"
884       when Scalar
885         Scalar.new(@value + other.value)
886       else
887         x, y = other.coerce(self)
888         x + y
889       end
890     end
891     
892     def -(other)
893       case other
894       when Numeric
895         Scalar.new(@value - other)
896       when Vector, Matrix
897         Scalar.Raise WrongArgType, other.class, "Numeric or Scalar"
898       when Scalar
899         Scalar.new(@value - other.value)
900       else
901         x, y = other.coerce(self)
902         x - y
903       end
904     end
905     
906     def *(other)
907       case other
908       when Numeric
909         Scalar.new(@value * other)
910       when Vector, Matrix
911         other.collect{|e| @value * e}
912       else
913         x, y = other.coerce(self)
914         x * y
915       end
916     end
917     
918     def / (other)
919       case other
920       when Numeric
921         Scalar.new(@value / other)
922       when Vector
923         Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix"
924       when Matrix
925         self * _M.inverse
926       else
927         x, y = other.coerce(self)
928         x / y
929       end
930     end
931     
932     def ** (other)
933       case other
934       when Numeric
935         Scalar.new(@value ** other)
936       when Vector
937         Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix"
938       when Matrix
939         other.powered_by(self)
940       else
941         x, y = other.coerce(self)
942         x ** y
943       end
944     end
945   end
950 # The +Vector+ class represents a mathematical vector, which is useful in its own right, and
951 # also constitutes a row or column of a Matrix.
953 # == Method Catalogue
955 # To create a Vector:
956 # * <tt>  Vector.[](*array)                   </tt>
957 # * <tt>  Vector.elements(array, copy = true) </tt>
959 # To access elements:
960 # * <tt>  [](i)                               </tt>
962 # To enumerate the elements:
963 # * <tt> #each2(v)                            </tt>
964 # * <tt> #collect2(v)                         </tt>
966 # Vector arithmetic:
967 # * <tt>  *(x) "is matrix or number"          </tt>
968 # * <tt>  +(v)                                </tt>
969 # * <tt>  -(v)                                </tt>
971 # Vector functions:
972 # * <tt> #inner_product(v)                    </tt>
973 # * <tt> #collect                             </tt>
974 # * <tt> #map                                 </tt>
975 # * <tt> #map2(v)                             </tt>
976 # * <tt> #r                                   </tt>
977 # * <tt> #size                                </tt>
979 # Conversion to other data types:
980 # * <tt> #covector                            </tt>
981 # * <tt> #to_a                                </tt>
982 # * <tt> #coerce(other)                       </tt>
984 # String representations:
985 # * <tt> #to_s                                </tt>
986 # * <tt> #inspect                             </tt>
988 class Vector
989   include ExceptionForMatrix
990   
991   #INSTANCE CREATION
992   
993   private_class_method :new
995   #
996   # Creates a Vector from a list of elements.
997   #   Vector[7, 4, ...]
998   #
999   def Vector.[](*array)
1000     new(:init_elements, array, copy = false)
1001   end
1002   
1003   #
1004   # Creates a vector from an Array.  The optional second argument specifies
1005   # whether the array itself or a copy is used internally.
1006   #
1007   def Vector.elements(array, copy = true)
1008     new(:init_elements, array, copy)
1009   end
1010   
1011   #
1012   # For internal use.
1013   #
1014   def initialize(method, array, copy)
1015     self.send(method, array, copy)
1016   end
1017   
1018   #
1019   # For internal use.
1020   #
1021   def init_elements(array, copy)
1022     if copy
1023       @elements = array.dup
1024     else
1025       @elements = array
1026     end
1027   end
1028   
1029   # ACCESSING
1030          
1031   #
1032   # Returns element number +i+ (starting at zero) of the vector.
1033   #
1034   def [](i)
1035     @elements[i]
1036   end
1037   
1038   #
1039   # Returns the number of elements in the vector.
1040   #
1041   def size
1042     @elements.size
1043   end
1044   
1045   #--
1046   # ENUMERATIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
1047   #++
1049   #
1050   # Iterate over the elements of this vector and +v+ in conjunction.
1051   #
1052   def each2(v) # :yield: e1, e2
1053     Vector.Raise ErrDimensionMismatch if size != v.size
1054     0.upto(size - 1) do
1055       |i|
1056       yield @elements[i], v[i]
1057     end
1058   end
1059   
1060   #
1061   # Collects (as in Enumerable#collect) over the elements of this vector and +v+
1062   # in conjunction.
1063   #
1064   def collect2(v) # :yield: e1, e2
1065     Vector.Raise ErrDimensionMismatch if size != v.size
1066     (0 .. size - 1).collect do
1067       |i|
1068       yield @elements[i], v[i]
1069     end
1070   end
1072   #--
1073   # COMPARING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
1074   #++
1076   #
1077   # Returns +true+ iff the two vectors have the same elements in the same order.
1078   #
1079   def ==(other)
1080     return false unless Vector === other
1081     
1082     other.compare_by(@elements)
1083   end
1084   alias eqn? ==
1085   
1086   #
1087   # For internal use.
1088   #
1089   def compare_by(elements)
1090     @elements == elements
1091   end
1092   
1093   #
1094   # Return a copy of the vector.
1095   #
1096   def clone
1097     Vector.elements(@elements)
1098   end
1099   
1100   #
1101   # Return a hash-code for the vector.
1102   #
1103   def hash
1104     @elements.hash
1105   end
1106   
1107   #--
1108   # ARITHMETIC -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
1109   #++
1110   
1111   #
1112   # Multiplies the vector by +x+, where +x+ is a number or another vector.
1113   #
1114   def *(x)
1115     case x
1116     when Numeric
1117       els = @elements.collect{|e| e * x}
1118       Vector.elements(els, false)
1119     when Matrix
1120       Matrix.column_vector(self) * x
1121     else
1122       s, x = x.coerce(self)
1123       s * x
1124     end
1125   end
1127   #
1128   # Vector addition.
1129   #
1130   def +(v)
1131     case v
1132     when Vector
1133       Vector.Raise ErrDimensionMismatch if size != v.size
1134       els = collect2(v) {
1135         |v1, v2|
1136         v1 + v2
1137       }
1138       Vector.elements(els, false)
1139     when Matrix
1140       Matrix.column_vector(self) + v
1141     else
1142       s, x = v.coerce(self)
1143       s + x
1144     end
1145   end
1147   #
1148   # Vector subtraction.
1149   #
1150   def -(v)
1151     case v
1152     when Vector
1153       Vector.Raise ErrDimensionMismatch if size != v.size
1154       els = collect2(v) {
1155         |v1, v2|
1156         v1 - v2
1157       }
1158       Vector.elements(els, false)
1159     when Matrix
1160       Matrix.column_vector(self) - v
1161     else
1162       s, x = v.coerce(self)
1163       s - x
1164     end
1165   end
1166   
1167   #--
1168   # VECTOR FUNCTIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
1169   #++
1170   
1171   #
1172   # Returns the inner product of this vector with the other.
1173   #   Vector[4,7].inner_product Vector[10,1]  => 47
1174   #
1175   def inner_product(v)
1176     Vector.Raise ErrDimensionMismatch if size != v.size
1177     
1178     p = 0
1179     each2(v) {
1180       |v1, v2|
1181       p += v1 * v2
1182     }
1183     p
1184   end
1185   
1186   #
1187   # Like Array#collect.
1188   #
1189   def collect # :yield: e
1190     els = @elements.collect {
1191       |v|
1192       yield v
1193     }
1194     Vector.elements(els, false)
1195   end
1196   alias map collect
1197   
1198   #
1199   # Like Vector#collect2, but returns a Vector instead of an Array.
1200   #
1201   def map2(v) # :yield: e1, e2
1202     els = collect2(v) {
1203       |v1, v2|
1204       yield v1, v2
1205     }
1206     Vector.elements(els, false)
1207   end
1208   
1209   #
1210   # Returns the modulus (Pythagorean distance) of the vector.
1211   #   Vector[5,8,2].r => 9.643650761
1212   #
1213   def r
1214     v = 0
1215     for e in @elements
1216       v += e*e
1217     end
1218     return Math.sqrt(v)
1219   end
1220   
1221   #--
1222   # CONVERTING
1223   #++
1225   #
1226   # Creates a single-row matrix from this vector.
1227   #
1228   def covector
1229     Matrix.row_vector(self)
1230   end
1231   
1232   #
1233   # Returns the elements of the vector in an array.
1234   #
1235   def to_a
1236     @elements.dup
1237   end
1238   
1239   #
1240   # FIXME: describe Vector#coerce.
1241   #
1242   def coerce(other)
1243     case other
1244     when Numeric
1245       return Scalar.new(other), self
1246     else
1247       raise TypeError, "#{self.class} can't be coerced into #{other.class}"
1248     end
1249   end
1250   
1251   #--
1252   # PRINTING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
1253   #++
1254   
1255   #
1256   # Overrides Object#to_s
1257   #
1258   def to_s
1259     "Vector[" + @elements.join(", ") + "]"
1260   end
1261   
1262   #
1263   # Overrides Object#inspect
1264   #
1265   def inspect
1266     str = "Vector"+@elements.inspect
1267   end
1271 # Documentation comments:
1272 #  - Matrix#coerce and Vector#coerce need to be documented