home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2007 September / PCWSEP07.iso / Software / Linux / Linux Mint 3.0 Light / LinuxMint-3.0-Light.iso / casper / filesystem.squashfs / usr / lib / ruby / 1.8 / matrix.rb < prev    next >
Encoding:
Ruby Source  |  2007-03-07  |  27.1 KB  |  1,272 lines

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