From 9670d71ba9921e0dd5307b7661773aa630151f9d Mon Sep 17 00:00:00 2001 From: gsinclair Date: Sun, 1 Feb 2004 09:27:17 +0000 Subject: From ruby_1_8 branch: * lib/test/unit.rb: rearranged documentation for RDoc's sake. * lib/matrix.rb: improved documentation. * lib/net/http.rb: slight documentation formatting improvement. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5599 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/matrix.rb | 576 +++++++++++++++++++++++++++------------------------------- 1 file changed, 263 insertions(+), 313 deletions(-) (limited to 'lib/matrix.rb') diff --git a/lib/matrix.rb b/lib/matrix.rb index 8e56fcbd97..a99875e545 100644 --- a/lib/matrix.rb +++ b/lib/matrix.rb @@ -1,170 +1,28 @@ #!/usr/local/bin/ruby -# +#-- # matrix.rb - -# $Release Version: 1.0$ -# $Revision: 1.11 $ -# $Date: 1999/10/06 11:01:53 $ +# $Release Version: 1.0$ +# $Revision: 1.11 $ +# $Date: 1999/10/06 11:01:53 $ # Original Version from Smalltalk-80 version -# on July 23, 1985 at 8:37:17 am -# by Keiju ISHITSUKA -# -# -- -# -# Matrix[[1,2,3], -# : -# [3,4,5]] -# Matrix[row0, -# row1, -# : -# rown] +# on July 23, 1985 at 8:37:17 am +# by Keiju ISHITSUKA +#++ # +# = matrix.rb # -# module ExceptionForMatrix:: -# Exceptions: -# ErrDimensionMismatch -# number of column/row do not match -# ErrNotRegular -# not a regular matrix -# ErrOperationNotDefined -# specified operator is not defined (yet) +# An implementation of Matrix and Vector classes. # -# class Matrix -# include ExceptionForMatrix +# Author:: Keiju ISHITSUKA +# Documentation:: Gavin Sinclair (sourced from Ruby in a Nutshell (Matsumoto, O'Reilly)) # -# Methods: -# class methods: -# Matrix.[](*rows) -# creates a matrix where `rows' indicates rows. -# `rows' is an array of arrays, -# e.g, Matrix[[11, 12], [21, 22]] -# Matrix.rows(rows, copy = true) -# creates a matrix where `rows' indicates rows. -# if optional argument `copy' is false, use the array as -# internal structure of the metrix without copying. -# Matrix.columns(columns) -# creates a new matrix using `columns` as set of colums vectors. -# Matrix.diagonal(*values) -# creates a matrix where `columns' indicates columns. -# Matrix.scalar(n, value) -# creates a diagonal matrix such that the diagal compornents is -# given by `values'. -# Matrix.scalar(n, value) -# creates an n-by-n scalar matrix such that the diagal compornent is -# given by `value'. -# Matrix.identity(n) -# Matrix.unit(n) -# Matrix.I(n) -# creates an n-by-n unit matrix. -# Matrix.zero(n) -# creates an n-by-n zero matrix. -# Matrix.row_vector(row) -# creates a 1-by-n matrix such the row vector is `row'. -# `row' is specifed as a Vector or an Array. -# Matrix.column_vector(column) -# creates a 1-by-n matrix such that column vector is `column'. -# `column' is specifed as a Vector or an Array. -# accessing: -# [](i, j) -# returns (i,j) compornent -# row_size -# returns the number of rows -# column_size -# returns the number of columns -# row(i) -# returns the i-th row vector. -# when the block is supplied for the method, the block is iterated -# over all row vectors. -# column(j) -# returns the jth column vector. -# when the block is supplied for the method, the block is iterated -# over all column vectors. -# collect -# map -# creates a matrix which is the result of iteration of given -# block over all compornents. -# minor(*param) -# returns sub matrix. parameter is specified as the following: -# 1. from_row, row_size, from_col, size_col -# 2. from_row..to_row, from_col..to_col -# TESTING: -# regular? -# Is regular? -# singular? -# Is singular? i.e. Is non-regular? -# square? -# Is square? -# ARITHMETIC: -# *(m) -# times -# +(m) -# plus -# -(m) -# minus -# /(m) -# self * m.inv -# inverse -# inv -# inverse -# ** -# power -# Matrix functions: -# determinant -# det -# returns the determinant -# rank -# returns the rank -# trace -# tr -# returns the trace -# transpose -# t -# returns the transposed -# CONVERTING: -# coerce(other) -# row_vectors -# array of row vectors -# column_vectors -# array of column vectors -# to_a -# converts to Array of Arrays -# PRINTING: -# to_s -# returns string representation -# inspect +# See classes Matrix and Vector for documentation. # -# class Vector -# include ExceptionForMatrix -# -# INSTANCE CREATION: -# Vector.[](*array) -# Vector.elements(array, copy = true) -# ACCSESSING: -# [](i) -# size -# ENUMRATIONS: -# each2(v) -# collect2(v) -# ARITHMETIC: -# *(x) "is matrix or number" -# +(v) -# -(v) -# VECTOR FUNCTIONS: -# inner_product(v) -# collect -# map -# map2(v) -# r -# CONVERTING: -# covector -# to_a -# coerce(other) -# PRINTING: -# to_s -# inspect + require "e2mmap.rb" -module ExceptionForMatrix +module ExceptionForMatrix # :nodoc: extend Exception2MessageMapper def_e2message(TypeError, "wrong argument type %s (expected %s)") def_e2message(ArgumentError, "Wrong # of arguments(%d for %d)") @@ -175,18 +33,77 @@ module ExceptionForMatrix end # -# Represents a mathematical matrix, and provides methods for creating -# special-case matrices (zero, identity, diagonal, singular, vector), operating -# on them arithmetically and algebraically, and determining their mathematical -# properties (trace, rank, inverse, determinant). -# -# The capabilities of the class indicated in the above paragraph are probably -# not exhaustive. Browse the methods and their documentation for more -# information. +# The +Matrix+ class represents a mathematical matrix, and provides methods for creating +# special-case matrices (zero, identity, diagonal, singular, vector), operating on them +# arithmetically and algebraically, and determining their mathematical properties (trace, rank, +# inverse, determinant). # # Note that although matrices should theoretically be rectangular, this is not # enforced by the class. # +# Also note that the determinant of integer matrices may be incorrectly calculated unless you +# also require 'mathn'. This may be fixed in the future. +# +# == Method Catalogue +# +# To create a matrix: +# * Matrix[*rows] +# * Matrix.[](*rows) +# * Matrix.rows(rows, copy = true) +# * Matrix.columns(columns) +# * Matrix.diagonal(*values) +# * Matrix.scalar(n, value) +# * Matrix.scalar(n, value) +# * Matrix.identity(n) +# * Matrix.unit(n) +# * Matrix.I(n) +# * Matrix.zero(n) +# * Matrix.row_vector(row) +# * Matrix.column_vector(column) +# +# To access Matrix elements/columns/rows/submatrices/properties: +# * [](i, j) +# * #row_size +# * #column_size +# * #row(i) +# * #column(j) +# * #collect +# * #map +# * #minor(*param) +# +# Properties of a matrix: +# * #regular? +# * #singular? +# * #square? +# +# Matrix arithmetic: +# * *(m) +# * +(m) +# * -(m) +# * #/(m) +# * #inverse +# * #inv +# * ** +# +# Matrix functions: +# * #determinant +# * #det +# * #rank +# * #trace +# * #tr +# * #transpose +# * #t +# +# Conversion to other data types: +# * #coerce(other) +# * #row_vectors +# * #column_vectors +# * #to_a +# +# String representations: +# * #to_s +# * #inspect +# class Matrix @RCS_ID='-$Id: matrix.rb,v 1.11 1999/10/06 11:01:53 keiju Exp keiju $-' @@ -228,8 +145,8 @@ class Matrix rows = (0 .. columns[0].size - 1).collect { |i| (0 .. columns.size - 1).collect { - |j| - columns[j][i] + |j| + columns[j][i] } } Matrix.rows(rows, false) @@ -373,7 +290,7 @@ class Matrix def row(i) # :yield: e if block_given? for e in @rows[i] - yield e + yield e end else Vector.elements(@rows[i]) @@ -388,13 +305,13 @@ class Matrix def column(j) # :yield: e if block_given? 0.upto(row_size - 1) do - |i| - yield @rows[i][j] + |i| + yield @rows[i][j] end else col = (0 .. row_size - 1).collect { - |i| - @rows[i][j] + |i| + @rows[i][j] } Vector.elements(col, false) end @@ -515,7 +432,7 @@ class Matrix value = 0 for row in @rows for e in row - value ^= e.hash + value ^= e.hash end end return value @@ -535,11 +452,11 @@ class Matrix case(m) when Numeric rows = @rows.collect { - |row| - row.collect { - |e| - e * m - } + |row| + row.collect { + |e| + e * m + } } return Matrix.rows(rows, false) when Vector @@ -550,16 +467,16 @@ class Matrix Matrix.Raise ErrDimensionMismatch if column_size != m.row_size rows = (0 .. row_size - 1).collect { - |i| - (0 .. m.column_size - 1).collect { - |j| - vij = 0 - 0.upto(column_size - 1) do - |k| - vij += self[i, k] * m[k, j] - end - vij - } + |i| + (0 .. m.column_size - 1).collect { + |j| + vij = 0 + 0.upto(column_size - 1) do + |k| + vij += self[i, k] * m[k, j] + end + vij + } } return Matrix.rows(rows, false) else @@ -591,8 +508,8 @@ class Matrix rows = (0 .. row_size - 1).collect { |i| (0 .. column_size - 1).collect { - |j| - self[i, j] + m[i, j] + |j| + self[i, j] + m[i, j] } } Matrix.rows(rows, false) @@ -621,8 +538,8 @@ class Matrix rows = (0 .. row_size - 1).collect { |i| (0 .. column_size - 1).collect { - |j| - self[i, j] - m[i, j] + |j| + self[i, j] - m[i, j] } } Matrix.rows(rows, false) @@ -638,11 +555,11 @@ class Matrix case other when Numeric rows = @rows.collect { - |row| - row.collect { - |e| - e / other - } + |row| + row.collect { + |e| + e / other + } } return Matrix.rows(rows, false) when Matrix @@ -674,37 +591,37 @@ class Matrix for k in 0..size if (akk = a[k][k]) == 0 - i = k - begin - Matrix.Raise ErrNotRegular if (i += 1) > size - end while a[i][k] == 0 - a[i], a[k] = a[k], a[i] - @rows[i], @rows[k] = @rows[k], @rows[i] - akk = a[k][k] + i = k + begin + Matrix.Raise ErrNotRegular if (i += 1) > size + end while a[i][k] == 0 + a[i], a[k] = a[k], a[i] + @rows[i], @rows[k] = @rows[k], @rows[i] + akk = a[k][k] end for i in 0 .. size - next if i == k - q = a[i][k] / akk - a[i][k] = 0 - - (k + 1).upto(size) do - |j| - a[i][j] -= a[k][j] * q - end - 0.upto(size) do - |j| - @rows[i][j] -= @rows[k][j] * q - end + next if i == k + q = a[i][k] / akk + a[i][k] = 0 + + (k + 1).upto(size) do + |j| + a[i][j] -= a[k][j] * q + end + 0.upto(size) do + |j| + @rows[i][j] -= @rows[k][j] * q + end end (k + 1).upto(size) do - |j| - a[k][j] /= akk + |j| + a[k][j] /= akk end 0.upto(size) do - |j| - @rows[k][j] /= akk + |j| + @rows[k][j] /= akk end end self @@ -722,20 +639,20 @@ class Matrix if other.kind_of?(Integer) x = self if other <= 0 - x = self.inverse - return Matrix.identity(self.column_size) if other == 0 - other = -other + x = self.inverse + return Matrix.identity(self.column_size) if other == 0 + other = -other end z = x n = other - 1 while n != 0 - while (div, mod = n.divmod(2) - mod == 0) - x = x * x - n = div - end - z *= x - n -= 1 + while (div, mod = n.divmod(2) + mod == 0) + x = x * x + n = div + end + z *= x + n -= 1 end z elsif other.kind_of?(Float) || defined?(Rational) && other.kind_of?(Rational) @@ -765,28 +682,28 @@ class Matrix k = 0 begin if (akk = a[k][k]) == 0 - i = k - begin - return 0 if (i += 1) > size - end while a[i][k] == 0 - a[i], a[k] = a[k], a[i] - akk = a[k][k] - det *= -1 + i = k + begin + return 0 if (i += 1) > size + end while a[i][k] == 0 + a[i], a[k] = a[k], a[i] + akk = a[k][k] + det *= -1 end (k + 1).upto(size) do - |i| - q = a[i][k] / akk - (k + 1).upto(size) do - |j| - a[i][j] -= a[k][j] * q - end + |i| + q = a[i][k] / akk + (k + 1).upto(size) do + |j| + a[i][j] -= a[k][j] * q + end end det *= akk end while (k += 1) <= size det end alias det determinant - + # # Returns the rank of the matrix. Beware that using Float values, with their # usual lack of precision, can affect the value returned by this method. Use @@ -808,44 +725,44 @@ class Matrix k = 0 begin if (akk = a[k][k]) == 0 - i = k - exists = true - begin - if (i += 1) > a_column_size - 1 - exists = false - break - end - end while a[i][k] == 0 - if exists - a[i], a[k] = a[k], a[i] - akk = a[k][k] - else - i = k - exists = true - begin - if (i += 1) > a_row_size - 1 - exists = false - break - end - end while a[k][i] == 0 - if exists - k.upto(a_column_size - 1) do - |j| - a[j][k], a[j][i] = a[j][i], a[j][k] - end - akk = a[k][k] - else - next - end - end + i = k + exists = true + begin + if (i += 1) > a_column_size - 1 + exists = false + break + end + end while a[i][k] == 0 + if exists + a[i], a[k] = a[k], a[i] + akk = a[k][k] + else + i = k + exists = true + begin + if (i += 1) > a_row_size - 1 + exists = false + break + end + end while a[k][i] == 0 + if exists + k.upto(a_column_size - 1) do + |j| + a[j][k], a[j][i] = a[j][i], a[j][k] + end + akk = a[k][k] + else + next + end + end end (k + 1).upto(a_row_size - 1) do - |i| - q = a[i][k] / akk - (k + 1).upto(a_column_size - 1) do - |j| - a[i][j] -= a[k][j] * q - end + |i| + q = a[i][k] / akk + (k + 1).upto(a_column_size - 1) do + |j| + a[i][j] -= a[k][j] * q + end end rank += 1 end while (k += 1) <= a_column_size - 1 @@ -961,78 +878,113 @@ class Matrix def +(other) case other when Numeric - Scalar.new(@value + other) + Scalar.new(@value + other) when Vector, Matrix - Scalar.Raise WrongArgType, other.class, "Numeric or Scalar" + Scalar.Raise WrongArgType, other.class, "Numeric or Scalar" when Scalar - Scalar.new(@value + other.value) + Scalar.new(@value + other.value) else - x, y = other.coerce(self) - x + y + x, y = other.coerce(self) + x + y end end def -(other) case other when Numeric - Scalar.new(@value - other) + Scalar.new(@value - other) when Vector, Matrix - Scalar.Raise WrongArgType, other.class, "Numeric or Scalar" + Scalar.Raise WrongArgType, other.class, "Numeric or Scalar" when Scalar - Scalar.new(@value - other.value) + Scalar.new(@value - other.value) else - x, y = other.coerce(self) - x - y + x, y = other.coerce(self) + x - y end end def *(other) case other when Numeric - Scalar.new(@value * other) + Scalar.new(@value * other) when Vector, Matrix - other.collect{|e| @value * e} + other.collect{|e| @value * e} else - x, y = other.coerce(self) - x * y + x, y = other.coerce(self) + x * y end end def / (other) case other when Numeric - Scalar.new(@value / other) + Scalar.new(@value / other) when Vector - Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix" + Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix" when Matrix - self * _M.inverse + self * _M.inverse else - x, y = other.coerce(self) - x / y + x, y = other.coerce(self) + x / y end end def ** (other) case other when Numeric - Scalar.new(@value ** other) + Scalar.new(@value ** other) when Vector - Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix" + Scalar.Raise WrongArgType, other.class, "Numeric or Scalar or Matrix" when Matrix - other.powered_by(self) + other.powered_by(self) else - x, y = other.coerce(self) - x ** y + x, y = other.coerce(self) + x ** y end end end end -#---------------------------------------------------------------------- + +# +# The +Vector+ class represents a mathematical vector, which is useful in its own right, and +# also consitutes a row or column of a Matrix. +# +# == Method Catalogue +# +# To create a Vector: +# * Vector.[](*array) +# * Vector.elements(array, copy = true) +# +# To access elements: +# * [](i) +# +# To enumerate the elements: +# * #each2(v) +# * #collect2(v) +# +# Vector arithmetic: +# * *(x) "is matrix or number" +# * +(v) +# * -(v) +# +# Vector functions: +# * #inner_product(v) +# * #collect +# * #map +# * #map2(v) +# * #r +# * #size +# +# Conversion to other data types: +# * #covector +# * #to_a +# * #coerce(other) # -# - +# String representations: +# * #to_s +# * #inspect # -#---------------------------------------------------------------------- class Vector include ExceptionForMatrix @@ -1075,7 +1027,7 @@ class Vector end # ACCSESSING - + # # Returns element number +i+ (starting at zero) of the vector. # @@ -1180,8 +1132,8 @@ class Vector when Vector Vector.Raise ErrDimensionMismatch if size != v.size els = collect2(v) { - |v1, v2| - v1 + v2 + |v1, v2| + v1 + v2 } Vector.elements(els, false) when Matrix @@ -1200,8 +1152,8 @@ class Vector when Vector Vector.Raise ErrDimensionMismatch if size != v.size els = collect2(v) { - |v1, v2| - v1 - v2 + |v1, v2| + v1 - v2 } Vector.elements(els, false) when Matrix @@ -1318,5 +1270,3 @@ end # Documentation comments: # - Matrix#coerce and Vector#coerce need to be documented -# - Matrix class methods (aliases) unit and I don't appear in RDoc output -# becuase of "class << Matrix". This is an RDoc issue. -- cgit v1.2.3