class Matrix
Matrix
类表示一个数学矩阵。它提供了创建矩阵、对其进行算术和代数运算以及确定其数学属性(如迹、秩、逆、行列式或特征系统)的方法。
常量
- SELECTORS
- VERSION
属性
返回列数。
返回列数。
实例创建
公共类方法
创建一个矩阵,其中每个参数都是一行。
Matrix[ [25, 93], [-1, 66] ] # => 25 93 # -1 66
# File matrix-0.4.2/lib/matrix.rb, line 78 def Matrix.[](*rows) rows(rows, false) end
创建一个大小为 row_count
x column_count
的矩阵。它通过调用给定的块来填充值,传递当前行和列。如果没有给定块,则返回一个枚举器。
m = Matrix.build(2, 4) {|row, col| col - row } # => Matrix[[0, 1, 2, 3], [-1, 0, 1, 2]] m = Matrix.build(3) { rand } # => a 3x3 matrix with random elements
# File matrix-0.4.2/lib/matrix.rb, line 123 def Matrix.build(row_count, column_count = row_count) row_count = CoercionHelper.coerce_to_int(row_count) column_count = CoercionHelper.coerce_to_int(column_count) raise ArgumentError if row_count < 0 || column_count < 0 return to_enum :build, row_count, column_count unless block_given? rows = Array.new(row_count) do |i| Array.new(column_count) do |j| yield i, j end end new rows, column_count end
创建一个单列矩阵,其中该列的值如 column
中给定的那样。
Matrix.column_vector([4,5,6]) # => 4 # 5 # 6
# File matrix-0.4.2/lib/matrix.rb, line 209 def Matrix.column_vector(column) column = convert_to_array(column) new [column].transpose, 1 end
使用 columns
作为列向量数组创建一个矩阵。
Matrix.columns([[25, 93], [-1, 66]]) # => 25 -1 # 93 66
# File matrix-0.4.2/lib/matrix.rb, line 108 def Matrix.columns(columns) rows(columns, false).transpose end
通过使用给定的块逐元素组合矩阵来创建矩阵
x = Matrix[[6, 6], [4, 4]] y = Matrix[[1, 2], [3, 4]] Matrix.combine(x, y) {|a, b| a - b} # => Matrix[[5, 4], [1, 0]]
# File matrix-0.4.2/lib/matrix.rb, line 288 def Matrix.combine(*matrices) return to_enum(__method__, *matrices) unless block_given? return Matrix.empty if matrices.empty? matrices.map!(&CoercionHelper.method(:coerce_to_matrix)) x = matrices.first matrices.each do |m| raise ErrDimensionMismatch unless x.row_count == m.row_count && x.column_count == m.column_count end rows = Array.new(x.row_count) do |i| Array.new(x.column_count) do |j| yield matrices.map{|m| m[i,j]} end end new rows, x.column_count end
创建一个矩阵,其中对角线元素由 values
组成。
Matrix.diagonal(9, 5, -3) # => 9 0 0 # 0 5 0 # 0 0 -3
# File matrix-0.4.2/lib/matrix.rb, line 143 def Matrix.diagonal(*values) size = values.size return Matrix.empty if size == 0 rows = Array.new(size) {|j| row = Array.new(size, 0) row[j] = values[j] row } new rows end
创建一个 row_count
x column_count
的空矩阵。 row_count
或 column_count
中至少有一个必须为 0。
m = Matrix.empty(2, 0) m == Matrix[ [], [] ] # => true n = Matrix.empty(0, 3) n == Matrix.columns([ [], [], [] ]) # => true m * n # => Matrix[[0, 0, 0], [0, 0, 0]]
# File matrix-0.4.2/lib/matrix.rb, line 227 def Matrix.empty(row_count = 0, column_count = 0) raise ArgumentError, "One size must be 0" if column_count != 0 && row_count != 0 raise ArgumentError, "Negative size" if column_count < 0 || row_count < 0 new([[]]*row_count, column_count) end
通过水平堆叠矩阵来创建矩阵
x = Matrix[[1, 2], [3, 4]] y = Matrix[[5, 6], [7, 8]] Matrix.hstack(x, y) # => Matrix[[1, 2, 5, 6], [3, 4, 7, 8]]
# File matrix-0.4.2/lib/matrix.rb, line 262 def Matrix.hstack(x, *matrices) x = CoercionHelper.coerce_to_matrix(x) result = x.send(:rows).map(&:dup) total_column_count = x.column_count matrices.each do |m| m = CoercionHelper.coerce_to_matrix(m) if m.row_count != x.row_count raise ErrDimensionMismatch, "The given matrices must have #{x.row_count} rows, but one has #{m.row_count}" end result.each_with_index do |row, i| row.concat m.send(:rows)[i] end total_column_count += m.column_count end new result, total_column_count end
创建一个 n
x n
的单位矩阵。
Matrix.identity(2) # => 1 0 # 0 1
# File matrix-0.4.2/lib/matrix.rb, line 171 def Matrix.identity(n) scalar(n, 1) end
Matrix.new
是私有的;使用 ::rows
, ::columns
, ::[]
等来创建。
# File matrix-0.4.2/lib/matrix.rb, line 322 def initialize(rows, column_count = rows[0].size) # No checking is done at this point. rows must be an Array of Arrays. # column_count must be the size of the first row, if there is one, # otherwise it *must* be specified and can be any integer >= 0 @rows = rows @column_count = column_count end
创建一个单行矩阵,其中该行的值如 row
中给定的那样。
Matrix.row_vector([4,5,6]) # => 4 5 6
# File matrix-0.4.2/lib/matrix.rb, line 196 def Matrix.row_vector(row) row = convert_to_array(row) new [row] end
创建一个矩阵,其中 rows
是一个数组的数组,每个数组都是矩阵的一行。如果可选参数 copy
为 false,则使用给定的数组作为矩阵的内部结构,而不进行复制。
Matrix.rows([[25, 93], [-1, 66]]) # => 25 93 # -1 66
# File matrix-0.4.2/lib/matrix.rb, line 90 def Matrix.rows(rows, copy = true) rows = convert_to_array(rows, copy) rows.map! do |row| convert_to_array(row, copy) end size = (rows[0] || []).size rows.each do |row| raise ErrDimensionMismatch, "row size differs (#{row.size} should be #{size})" unless row.size == size end new rows, size end
创建一个 n
x n
的对角矩阵,其中每个对角线元素都是 value
。
Matrix.scalar(2, 5) # => 5 0 # 0 5
# File matrix-0.4.2/lib/matrix.rb, line 161 def Matrix.scalar(n, value) diagonal(*Array.new(n, value)) end
通过垂直堆叠矩阵来创建矩阵
x = Matrix[[1, 2], [3, 4]] y = Matrix[[5, 6], [7, 8]] Matrix.vstack(x, y) # => Matrix[[1, 2], [3, 4], [5, 6], [7, 8]]
# File matrix-0.4.2/lib/matrix.rb, line 241 def Matrix.vstack(x, *matrices) x = CoercionHelper.coerce_to_matrix(x) result = x.send(:rows).map(&:dup) matrices.each do |m| m = CoercionHelper.coerce_to_matrix(m) if m.column_count != x.column_count raise ErrDimensionMismatch, "The given matrices must have #{x.column_count} columns, but one has #{m.column_count}" end result.concat(m.send(:rows)) end new result, x.column_count end
创建一个零矩阵。
Matrix.zero(2) # => 0 0 # 0 0
# File matrix-0.4.2/lib/matrix.rb, line 185 def Matrix.zero(row_count, column_count = row_count) rows = Array.new(row_count){Array.new(column_count, 0)} new rows, column_count end
公共实例方法
Matrix
乘法。
Matrix[[2,4], [6,8]] * Matrix.identity(2) # => 2 4 # 6 8
# File matrix-0.4.2/lib/matrix.rb, line 1058 def *(m) # m is matrix or vector or number case(m) when Numeric new_rows = @rows.collect {|row| row.collect {|e| e * m } } return new_matrix new_rows, column_count when Vector m = self.class.column_vector(m) r = self * m return r.column(0) when Matrix raise ErrDimensionMismatch if column_count != m.row_count m_rows = m.rows new_rows = rows.map do |row_i| Array.new(m.column_count) do |j| vij = 0 column_count.times do |k| vij += row_i[k] * m_rows[k][j] end vij end end return new_matrix new_rows, m.column_count else return apply_through_coercion(m, __method__) end end
Matrix
指数运算。等效于将矩阵自乘 N 次。非整数指数将通过对矩阵进行对角化来处理。
Matrix[[7,6], [3,9]] ** 2 # => 67 96 # 48 99
# File matrix-0.4.2/lib/matrix.rb, line 1237 def **(exp) case exp when Integer case when exp == 0 raise ErrDimensionMismatch unless square? self.class.identity(column_count) when exp < 0 inverse.power_int(-exp) else power_int(exp) end when Numeric v, d, v_inv = eigensystem v * self.class.diagonal(*d.each(:diagonal).map{|e| e ** exp}) * v_inv else raise ErrOperationNotDefined, ["**", self.class, exp.class] end end
Matrix
加法。
Matrix.scalar(2,5) + Matrix[[1,0], [-4,7]] # => 6 0 # -4 12
# File matrix-0.4.2/lib/matrix.rb, line 1093 def +(m) case m when Numeric raise ErrOperationNotDefined, ["+", self.class, m.class] when Vector m = self.class.column_vector(m) when Matrix else return apply_through_coercion(m, __method__) end raise ErrDimensionMismatch unless row_count == m.row_count && column_count == m.column_count rows = Array.new(row_count) {|i| Array.new(column_count) {|j| self[i, j] + m[i, j] } } new_matrix rows, column_count end
# File matrix-0.4.2/lib/matrix.rb, line 1283 def +@ self end
Matrix
减法。
Matrix[[1,5], [4,2]] - Matrix[[9,3], [-4,1]] # => -8 2 # 8 1
# File matrix-0.4.2/lib/matrix.rb, line 1120 def -(m) case m when Numeric raise ErrOperationNotDefined, ["-", self.class, m.class] when Vector m = self.class.column_vector(m) when Matrix else return apply_through_coercion(m, __method__) end raise ErrDimensionMismatch unless row_count == m.row_count && column_count == m.column_count rows = Array.new(row_count) {|i| Array.new(column_count) {|j| self[i, j] - m[i, j] } } new_matrix rows, column_count end
一元矩阵取负。
-Matrix[[1,5], [4,2]] # => -1 -5 # -4 -2
# File matrix-0.4.2/lib/matrix.rb, line 1292 def -@ collect {|e| -e } end
Matrix
除法(乘以逆矩阵)。
Matrix[[7,6], [3,9]] / Matrix[[2,9], [3,1]] # => -7 1 # -3 -6
# File matrix-0.4.2/lib/matrix.rb, line 1147 def /(other) case other when Numeric rows = @rows.collect {|row| row.collect {|e| e / other } } return new_matrix rows, column_count when Matrix return self * other.inverse else return apply_through_coercion(other, __method__) end end
返回两个矩阵是否包含相等的元素。
# File matrix-0.4.2/lib/matrix.rb, line 1021 def ==(other) return false unless Matrix === other && column_count == other.column_count # necessary for empty matrices rows == other.rows end
返回矩阵的元素(i
, j
)。即:第 i
行,第 j
列。
# File matrix-0.4.2/lib/matrix.rb, line 337 def [](i, j) @rows.fetch(i){return nil}[j] end
设置矩阵的一个或多个元素。
# File matrix-0.4.2/lib/matrix.rb, line 351 def []=(i, j, v) raise FrozenError, "can't modify frozen Matrix" if frozen? rows = check_range(i, :row) or row = check_int(i, :row) columns = check_range(j, :column) or column = check_int(j, :column) if rows && columns set_row_and_col_range(rows, columns, v) elsif rows set_row_range(rows, column, v) elsif columns set_col_range(row, columns, v) else set_value(row, column, v) end end
返回逐元素的绝对值
# File matrix-0.4.2/lib/matrix.rb, line 1299 def abs collect(&:abs) end
返回矩阵的伴随矩阵。
Matrix[ [i,1],[2,-i] ].adjoint # => -i 2 # 1 i
# File matrix-0.4.2/lib/matrix.rb, line 1595 def adjoint conjugate.transpose end
返回矩阵的伴随矩阵。
Matrix[ [7,6],[3,9] ].adjugate # => 9 -6 # -3 7
# File matrix-0.4.2/lib/matrix.rb, line 793 def adjugate raise ErrDimensionMismatch unless square? Matrix.build(row_count, column_count) do |row, column| cofactor(column, row) end end
如果这是一个反对称矩阵,则返回 true
。如果矩阵不是方阵,则引发错误。
# File matrix-0.4.2/lib/matrix.rb, line 973 def antisymmetric? raise ErrDimensionMismatch unless square? each_with_index(:upper) do |e, row, col| return false unless e == -rows[col][row] end true end
coerce 方法为 Ruby 类型强制转换提供支持。 Ruby 使用此强制转换机制来处理混合类型的数值运算:它旨在查找运算符的两个操作数之间兼容的公共类型。另请参阅 Numeric#coerce。
# File matrix-0.4.2/lib/matrix.rb, line 1648 def coerce(other) case other when Numeric return Scalar.new(other), self else raise TypeError, "#{self.class} can't be coerced into #{other.class}" end end
返回 (row, column) 的余因子,它是通过将第一主子式乘以 (-1)**(row + column) 获得的。
Matrix.diagonal(9, 5, -3, 4).cofactor(1, 1) # => -108
# File matrix-0.4.2/lib/matrix.rb, line 778 def cofactor(row, column) raise RuntimeError, "cofactor of empty matrix is not defined" if empty? raise ErrDimensionMismatch unless square? det_of_minor = first_minor(row, column).determinant det_of_minor * (-1) ** (row + column) end
返回一个矩阵,该矩阵是对矩阵的所有元素迭代给定块的结果。可以通过传递参数来限制元素
-
:all(默认):产生所有元素
-
:diagonal:仅产生对角线上的元素
-
:off_diagonal:产生除对角线上的所有元素
-
:lower:仅产生对角线或之下的元素
-
:strict_lower:仅产生对角线以下的元素
-
:strict_upper:仅产生对角线以上的元素
-
:upper:仅产生对角线或以上的元素 Matrix[ [1,2], [3,4] ].collect { |e| e**2 } # => 1 4 # 9 16
# File matrix-0.4.2/lib/matrix.rb, line 508 def collect(which = :all, &block) # :yield: e return to_enum(:collect, which) unless block_given? dup.collect!(which, &block) end
对矩阵的每个元素调用给定的块,用该块返回的值替换该元素。可以通过传递参数来限制元素
-
:all(默认):产生所有元素
-
:diagonal:仅产生对角线上的元素
-
:off_diagonal:产生除对角线上的所有元素
-
:lower:仅产生对角线或之下的元素
-
:strict_lower:仅产生对角线以下的元素
-
:strict_upper:仅产生对角线以上的元素
-
:upper:仅产生对角线或以上的元素
# File matrix-0.4.2/lib/matrix.rb, line 526 def collect!(which = :all) return to_enum(:collect!, which) unless block_given? raise FrozenError, "can't modify frozen Matrix" if frozen? each_with_index(which){ |e, row_index, col_index| @rows[row_index][col_index] = yield e } end
将矩阵的第 j
列作为 Vector
返回(从 0 开始,如数组)。当给定一个块时,该向量的元素将被迭代。
# File matrix-0.4.2/lib/matrix.rb, line 477 def column(j) # :yield: e if block_given? return self if j >= column_count || j < -column_count row_count.times do |i| yield @rows[i][j] end self else return nil if j >= column_count || j < -column_count col = Array.new(row_count) {|i| @rows[i][j] } Vector.elements(col, false) end end
返回矩阵的列向量数组。参见 Vector
。
# File matrix-0.4.2/lib/matrix.rb, line 1669 def column_vectors Array.new(column_count) {|i| column(i) } end
通过使用给定的块与 other_matrices 逐元素组合来创建新矩阵。
x = Matrix[[6, 6], [4, 4]] y = Matrix[[1, 2], [3, 4]] x.combine(y) {|a, b| a - b} # => Matrix[[5, 4], [1, 0]]
# File matrix-0.4.2/lib/matrix.rb, line 315 def combine(*matrices, &block) Matrix.combine(self, *matrices, &block) end
返回矩阵的共轭矩阵。
Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]] # => 1+2i i 0 # 1 2 3 Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].conjugate # => 1-2i -i 0 # 1 2 3
# File matrix-0.4.2/lib/matrix.rb, line 1583 def conjugate collect(&:conjugate) end
返回矩阵的行列式。
请注意,使用浮点数值可能会因其精度不足而产生错误的结果。 考虑使用精确类型,如 Rational 或 BigDecimal。
Matrix[[7,6], [3,9]].determinant # => 45
# File matrix-0.4.2/lib/matrix.rb, line 1317 def determinant raise ErrDimensionMismatch unless square? m = @rows case row_count # Up to 4x4, give result using Laplacian expansion by minors. # This will typically be faster, as well as giving good results # in case of Floats when 0 +1 when 1 + m[0][0] when 2 + m[0][0] * m[1][1] - m[0][1] * m[1][0] when 3 m0, m1, m2 = m + m0[0] * m1[1] * m2[2] - m0[0] * m1[2] * m2[1] \ - m0[1] * m1[0] * m2[2] + m0[1] * m1[2] * m2[0] \ + m0[2] * m1[0] * m2[1] - m0[2] * m1[1] * m2[0] when 4 m0, m1, m2, m3 = m + m0[0] * m1[1] * m2[2] * m3[3] - m0[0] * m1[1] * m2[3] * m3[2] \ - m0[0] * m1[2] * m2[1] * m3[3] + m0[0] * m1[2] * m2[3] * m3[1] \ + m0[0] * m1[3] * m2[1] * m3[2] - m0[0] * m1[3] * m2[2] * m3[1] \ - m0[1] * m1[0] * m2[2] * m3[3] + m0[1] * m1[0] * m2[3] * m3[2] \ + m0[1] * m1[2] * m2[0] * m3[3] - m0[1] * m1[2] * m2[3] * m3[0] \ - m0[1] * m1[3] * m2[0] * m3[2] + m0[1] * m1[3] * m2[2] * m3[0] \ + m0[2] * m1[0] * m2[1] * m3[3] - m0[2] * m1[0] * m2[3] * m3[1] \ - m0[2] * m1[1] * m2[0] * m3[3] + m0[2] * m1[1] * m2[3] * m3[0] \ + m0[2] * m1[3] * m2[0] * m3[1] - m0[2] * m1[3] * m2[1] * m3[0] \ - m0[3] * m1[0] * m2[1] * m3[2] + m0[3] * m1[0] * m2[2] * m3[1] \ + m0[3] * m1[1] * m2[0] * m3[2] - m0[3] * m1[1] * m2[2] * m3[0] \ - m0[3] * m1[2] * m2[0] * m3[1] + m0[3] * m1[2] * m2[1] * m3[0] else # For bigger matrices, use an efficient and general algorithm. # Currently, we use the Gauss-Bareiss algorithm determinant_bareiss end end
已弃用; 请使用 Matrix#determinant
# File matrix-0.4.2/lib/matrix.rb, line 1398 def determinant_e warn "Matrix#determinant_e is deprecated; use #determinant", uplevel: 1 determinant end
如果这是一个对角矩阵,则返回 true
。 如果矩阵不是方阵,则引发错误。
# File matrix-0.4.2/lib/matrix.rb, line 839 def diagonal? raise ErrDimensionMismatch unless square? each(:off_diagonal).all?(&:zero?) end
产生矩阵的所有元素,从第一行的元素开始,如果没有给出块,则返回一个枚举器。 可以通过传递参数来限制元素。
-
:all(默认):产生所有元素
-
:diagonal:仅产生对角线上的元素
-
:off_diagonal:产生除对角线上的所有元素
-
:lower:仅产生对角线或之下的元素
-
:strict_lower:仅产生对角线以下的元素
-
:strict_upper:仅产生对角线以上的元素
-
:upper:仅产生对角线或以上的元素
Matrix[ [1,2], [3,4] ].each { |e| puts e } # => prints the numbers 1 to 4 Matrix[ [1,2], [3,4] ].each(:strict_lower).to_a # => [3]
# File matrix-0.4.2/lib/matrix.rb, line 556 def each(which = :all, &block) # :yield: e return to_enum :each, which unless block_given? last = column_count - 1 case which when :all @rows.each do |row| row.each(&block) end when :diagonal @rows.each_with_index do |row, row_index| yield row.fetch(row_index){return self} end when :off_diagonal @rows.each_with_index do |row, row_index| column_count.times do |col_index| yield row[col_index] unless row_index == col_index end end when :lower @rows.each_with_index do |row, row_index| 0.upto([row_index, last].min) do |col_index| yield row[col_index] end end when :strict_lower @rows.each_with_index do |row, row_index| [row_index, column_count].min.times do |col_index| yield row[col_index] end end when :strict_upper @rows.each_with_index do |row, row_index| (row_index+1).upto(last) do |col_index| yield row[col_index] end end when :upper @rows.each_with_index do |row, row_index| row_index.upto(last) do |col_index| yield row[col_index] end end else raise ArgumentError, "expected #{which.inspect} to be one of :all, :diagonal, :off_diagonal, :lower, :strict_lower, :strict_upper or :upper" end self end
与 each
相同,但除了元素之外,还包括行索引和列索引。
Matrix[ [1,2], [3,4] ].each_with_index do |e, row, col| puts "#{e} at #{row}, #{col}" end # => Prints: # 1 at 0, 0 # 2 at 0, 1 # 3 at 1, 0 # 4 at 1, 1
# File matrix-0.4.2/lib/matrix.rb, line 616 def each_with_index(which = :all) # :yield: e, row, column return to_enum :each_with_index, which unless block_given? last = column_count - 1 case which when :all @rows.each_with_index do |row, row_index| row.each_with_index do |e, col_index| yield e, row_index, col_index end end when :diagonal @rows.each_with_index do |row, row_index| yield row.fetch(row_index){return self}, row_index, row_index end when :off_diagonal @rows.each_with_index do |row, row_index| column_count.times do |col_index| yield row[col_index], row_index, col_index unless row_index == col_index end end when :lower @rows.each_with_index do |row, row_index| 0.upto([row_index, last].min) do |col_index| yield row[col_index], row_index, col_index end end when :strict_lower @rows.each_with_index do |row, row_index| [row_index, column_count].min.times do |col_index| yield row[col_index], row_index, col_index end end when :strict_upper @rows.each_with_index do |row, row_index| (row_index+1).upto(last) do |col_index| yield row[col_index], row_index, col_index end end when :upper @rows.each_with_index do |row, row_index| row_index.upto(last) do |col_index| yield row[col_index], row_index, col_index end end else raise ArgumentError, "expected #{which.inspect} to be one of :all, :diagonal, :off_diagonal, :lower, :strict_lower, :strict_upper or :upper" end self end
返回矩阵的特征系统;请参阅 EigenvalueDecomposition
。
m = Matrix[[1, 2], [3, 4]] v, d, v_inv = m.eigensystem d.diagonal? # => true v.inv == v_inv # => true (v * d * v_inv).round(5) == m # => true
# File matrix-0.4.2/lib/matrix.rb, line 1550 def eigensystem EigenvalueDecomposition.new(self) end
已弃用。
请使用 map(&:to_f)
# File matrix-0.4.2/lib/matrix.rb, line 1692 def elements_to_f warn "Matrix#elements_to_f is deprecated, use map(&:to_f)", uplevel: 1 map(&:to_f) end
已弃用。
请使用 map(&:to_i)
# File matrix-0.4.2/lib/matrix.rb, line 1700 def elements_to_i warn "Matrix#elements_to_i is deprecated, use map(&:to_i)", uplevel: 1 map(&:to_i) end
已弃用。
请使用 map(&:to_r)
# File matrix-0.4.2/lib/matrix.rb, line 1708 def elements_to_r warn "Matrix#elements_to_r is deprecated, use map(&:to_r)", uplevel: 1 map(&:to_r) end
如果这是一个空矩阵,即行数或列数为 0,则返回 true
。
# File matrix-0.4.2/lib/matrix.rb, line 848 def empty? column_count == 0 || row_count == 0 end
# File matrix-0.4.2/lib/matrix.rb, line 1027 def eql?(other) return false unless Matrix === other && column_count == other.column_count # necessary for empty matrices rows.eql? other.rows end
返回通过删除指定的行和列获得的子矩阵。
Matrix.diagonal(9, 5, -3, 4).first_minor(1, 2) # => 9 0 0 # 0 0 0 # 0 0 4
# File matrix-0.4.2/lib/matrix.rb, line 751 def first_minor(row, column) raise RuntimeError, "first_minor of empty matrix is not defined" if empty? unless 0 <= row && row < row_count raise ArgumentError, "invalid row (#{row.inspect} for 0..#{row_count - 1})" end unless 0 <= column && column < column_count raise ArgumentError, "invalid column (#{column.inspect} for 0..#{column_count - 1})" end arrays = to_a arrays.delete_at(row) arrays.each do |array| array.delete_at(column) end new_matrix arrays, column_count - 1 end
# File matrix-0.4.2/lib/matrix.rb, line 534 def freeze @rows.each(&:freeze).freeze super end
哈达玛积
Matrix[[1,2], [3,4]].hadamard_product(Matrix[[1,2], [3,2]]) # => 1 4 # 9 8
# File matrix-0.4.2/lib/matrix.rb, line 1167 def hadamard_product(m) combine(m){|a, b| a * b} end
返回矩阵的哈希码。
# File matrix-0.4.2/lib/matrix.rb, line 1044 def hash @rows.hash end
如果这是一个埃尔米特矩阵,则返回 true
。如果矩阵不是方阵,则引发错误。
# File matrix-0.4.2/lib/matrix.rb, line 856 def hermitian? raise ErrDimensionMismatch unless square? each_with_index(:upper).all? do |e, row, col| e == rows[col][row].conj end end
返回一个新矩阵,该矩阵是通过将接收器与给定的矩阵水平堆叠而形成的。
x = Matrix[[1, 2], [3, 4]] y = Matrix[[5, 6], [7, 8]] x.hstack(y) # => Matrix[[1, 2, 5, 6], [3, 4, 7, 8]]
# File matrix-0.4.2/lib/matrix.rb, line 1412 def hstack(*matrices) self.class.hstack(self, *matrices) end
返回矩阵的虚部。
Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]] # => 1+2i i 0 # 1 2 3 Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].imaginary # => 2i i 0 # 0 0 0
# File matrix-0.4.2/lib/matrix.rb, line 1608 def imaginary collect(&:imaginary) end
index 方法专门用于以 [row, column] 的形式返回索引。它还接受一个可选的 selector
参数,有关详细信息,请参阅 each
。
Matrix[ [1,2], [3,4] ].index(&:even?) # => [0, 1] Matrix[ [1,1], [1,1] ].index(1, :strict_lower) # => [1, 0]
# File matrix-0.4.2/lib/matrix.rb, line 679 def index(*args) raise ArgumentError, "wrong number of arguments(#{args.size} for 0-2)" if args.size > 2 which = (args.size == 2 || SELECTORS.include?(args.last)) ? args.pop : :all return to_enum :find_index, which, *args unless block_given? || args.size == 1 if args.size == 1 value = args.first each_with_index(which) do |e, row_index, col_index| return row_index, col_index if e == value end else each_with_index(which) do |e, row_index, col_index| return row_index, col_index if yield e end end nil end
覆盖 Object#inspect
# File matrix-0.4.2/lib/matrix.rb, line 1733 def inspect if empty? "#{self.class}.empty(#{row_count}, #{column_count})" else "#{self.class}#{@rows.inspect}" end end
返回矩阵的逆矩阵。
Matrix[[-1, -1], [0, -1]].inverse # => -1 1 # 0 -1
# File matrix-0.4.2/lib/matrix.rb, line 1178 def inverse raise ErrDimensionMismatch unless square? self.class.I(row_count).send(:inverse_from, self) end
返回沿给定行或列的拉普拉斯展开。
Matrix[[7,6], [3,9]].laplace_expansion(column: 1) # => 45 Matrix[[Vector[1, 0], Vector[0, 1]], [2, 3]].laplace_expansion(row: 0) # => Vector[3, -2]
# File matrix-0.4.2/lib/matrix.rb, line 810 def laplace_expansion(row: nil, column: nil) num = row || column if !num || (row && column) raise ArgumentError, "exactly one the row or column arguments must be specified" end raise ErrDimensionMismatch unless square? raise RuntimeError, "laplace_expansion of empty matrix is not defined" if empty? unless 0 <= num && num < row_count raise ArgumentError, "invalid num (#{num.inspect} for 0..#{row_count - 1})" end send(row ? :row : :column, num).map.with_index { |e, k| e * cofactor(*(row ? [num, k] : [k,num])) }.inject(:+) end
如果这是一个下三角矩阵,则返回 true
。
# File matrix-0.4.2/lib/matrix.rb, line 866 def lower_triangular? each(:strict_upper).all?(&:zero?) end
返回矩阵的 LUP 分解;请参阅 LUPDecomposition
。
a = Matrix[[1, 2], [3, 4]] l, u, p = a.lup l.lower_triangular? # => true u.upper_triangular? # => true p.permutation? # => true l * u == p * a # => true a.lup.solve([2, 5]) # => Vector[(1/1), (1/2)]
# File matrix-0.4.2/lib/matrix.rb, line 1565 def lup LUPDecomposition.new(self) end
返回矩阵的一部分。 参数为:
-
start_row,nrows,start_col,ncols; 或者
-
row_range,col_range
Matrix.diagonal(9, 5, -3).minor(0..1, 0..2) # => 9 0 0 # 0 5 0
类似于 Array#[],负索引从行或列的末尾向后计数(-1 是最后一个元素)。 如果起始行或列分别大于 row_count
或 column_count
,则返回 nil。
# File matrix-0.4.2/lib/matrix.rb, line 710 def minor(*param) case param.size when 2 row_range, col_range = param from_row = row_range.first from_row += row_count if from_row < 0 to_row = row_range.end to_row += row_count if to_row < 0 to_row += 1 unless row_range.exclude_end? size_row = to_row - from_row from_col = col_range.first from_col += column_count if from_col < 0 to_col = col_range.end to_col += column_count if to_col < 0 to_col += 1 unless col_range.exclude_end? size_col = to_col - from_col when 4 from_row, size_row, from_col, size_col = param return nil if size_row < 0 || size_col < 0 from_row += row_count if from_row < 0 from_col += column_count if from_col < 0 else raise ArgumentError, param.inspect end return nil if from_row > row_count || from_col > column_count || from_row < 0 || from_col < 0 rows = @rows[from_row, size_row].collect{|row| row[from_col, size_col] } new_matrix rows, [column_count - from_col, size_col].min end
如果这是一个正规矩阵,则返回 true
。如果矩阵不是方阵,则引发错误。
# File matrix-0.4.2/lib/matrix.rb, line 874 def normal? raise ErrDimensionMismatch unless square? rows.each_with_index do |row_i, i| rows.each_with_index do |row_j, j| s = 0 rows.each_with_index do |row_k, k| s += row_i[k] * row_j[k].conj - row_k[i].conj * row_k[j] end return false unless s == 0 end end true end
如果这是一个正交矩阵,则返回 true
。如果矩阵不是方阵,则引发错误。
# File matrix-0.4.2/lib/matrix.rb, line 892 def orthogonal? raise ErrDimensionMismatch unless square? rows.each_with_index do |row_i, i| rows.each_with_index do |row_j, j| s = 0 row_count.times do |k| s += row_i[k] * row_j[k] end return false unless s == (i == j ? 1 : 0) end end true end
如果这是一个置换矩阵,则返回 true
。如果矩阵不是方阵,则引发错误。
# File matrix-0.4.2/lib/matrix.rb, line 911 def permutation? raise ErrDimensionMismatch unless square? cols = Array.new(column_count) rows.each_with_index do |row, i| found = false row.each_with_index do |e, j| if e == 1 return false if found || cols[j] found = cols[j] = true elsif e != 0 return false end end return false unless found end true end
返回矩阵的秩。请注意,使用浮点数值可能会因其精度不足而产生错误的结果。考虑使用精确类型,如 Rational 或 BigDecimal。
Matrix[[7,6], [3,9]].rank # => 2
# File matrix-0.4.2/lib/matrix.rb, line 1425 def rank # We currently use Bareiss' multistep integer-preserving gaussian elimination # (see comments on determinant) a = to_a last_column = column_count - 1 last_row = row_count - 1 pivot_row = 0 previous_pivot = 1 0.upto(last_column) do |k| switch_row = (pivot_row .. last_row).find {|row| a[row][k] != 0 } if switch_row a[switch_row], a[pivot_row] = a[pivot_row], a[switch_row] unless pivot_row == switch_row pivot = a[pivot_row][k] (pivot_row+1).upto(last_row) do |i| ai = a[i] (k+1).upto(last_column) do |j| ai[j] = (pivot * ai[j] - ai[k] * a[pivot_row][j]) / previous_pivot end end pivot_row += 1 previous_pivot = pivot end end pivot_row end
已弃用;请使用 Matrix#rank
# File matrix-0.4.2/lib/matrix.rb, line 1456 def rank_e warn "Matrix#rank_e is deprecated; use #rank", uplevel: 1 rank end
返回矩阵的实部。
Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]] # => 1+2i i 0 # 1 2 3 Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]].real # => 1 0 0 # 1 2 3
# File matrix-0.4.2/lib/matrix.rb, line 1622 def real collect(&:real) end
如果矩阵的所有条目都是实数,则返回 true
。
# File matrix-0.4.2/lib/matrix.rb, line 932 def real? all?(&:real?) end
返回一个包含与矩阵的实部和虚部相对应的矩阵的数组。
m.rect == [m.real, m.imag] # ==> true for all matrices m
# File matrix-0.4.2/lib/matrix.rb, line 1632 def rect [real, imag] end
如果这是一个正则(即非奇异)矩阵,则返回 true
。
# File matrix-0.4.2/lib/matrix.rb, line 939 def regular? not singular? end
返回一个具有旋转元素的新矩阵。 参数指定旋转(默认为 ‘:clockwise`)
-
:clockwise, 1, -3, 等: “向右转” - 第一行变为最后一列
-
:half_turn, 2, -2, 等: 第一行变为最后一行,元素顺序相反
-
:counter_clockwise, -1, 3: “向左转” - 第一行变为第一列(但元素顺序相反)
m = Matrix[ [1, 2], [3, 4] ] r = m.rotate_entries(:clockwise) # => Matrix[[3, 1], [4, 2]]
# File matrix-0.4.2/lib/matrix.rb, line 1473 def rotate_entries(rotation = :clockwise) rotation %= 4 if rotation.respond_to? :to_int case rotation when 0 dup when 1, :clockwise new_matrix @rows.transpose.each(&:reverse!), row_count when 2, :half_turn new_matrix @rows.map(&:reverse).reverse!, column_count when 3, :counter_clockwise new_matrix @rows.transpose.reverse!, row_count else raise ArgumentError, "expected #{rotation.inspect} to be one of :clockwise, :counter_clockwise, :half_turn or an integer" end end
返回一个条目四舍五入到给定精度的矩阵(请参阅 Float#round)
# File matrix-0.4.2/lib/matrix.rb, line 1493 def round(ndigits=0) map{|e| e.round(ndigits)} end
将矩阵的第 i
个行向量作为 Vector
返回(像数组一样从 0 开始)。 当给出一个块时,将迭代该向量的元素。
# File matrix-0.4.2/lib/matrix.rb, line 463 def row(i, &block) # :yield: e if block_given? @rows.fetch(i){return self}.each(&block) self else Vector.elements(@rows.fetch(i){return nil}) end end
返回行数。
# File matrix-0.4.2/lib/matrix.rb, line 448 def row_count @rows.size end
返回矩阵的行向量数组。 请参阅 Vector
。
# File matrix-0.4.2/lib/matrix.rb, line 1660 def row_vectors Array.new(row_count) {|i| row(i) } end
如果这是一个奇异矩阵,则返回 true
。
# File matrix-0.4.2/lib/matrix.rb, line 946 def singular? determinant == 0 end
如果这是一个方阵,则返回 true
。
# File matrix-0.4.2/lib/matrix.rb, line 953 def square? column_count == row_count end
如果这是一个对称矩阵,则返回 true
。如果矩阵不是方阵,则引发错误。
# File matrix-0.4.2/lib/matrix.rb, line 961 def symmetric? raise ErrDimensionMismatch unless square? each_with_index(:strict_upper) do |e, row, col| return false if e != rows[col][row] end true end
返回一个描述矩阵行的数组数组。
# File matrix-0.4.2/lib/matrix.rb, line 1685 def to_a @rows.collect(&:dup) end
显式转换为 Matrix
。 返回 self
# File matrix-0.4.2/lib/matrix.rb, line 1678 def to_matrix self end
覆盖 Object#to_s
# File matrix-0.4.2/lib/matrix.rb, line 1720 def to_s if empty? "#{self.class}.empty(#{row_count}, #{column_count})" else "#{self.class}[" + @rows.collect{|row| "[" + row.collect{|e| e.to_s}.join(", ") + "]" }.join(", ")+"]" end end
返回矩阵的迹(对角线元素之和)。
Matrix[[7,6], [3,9]].trace # => 16
# File matrix-0.4.2/lib/matrix.rb, line 1502 def trace raise ErrDimensionMismatch unless square? (0...column_count).inject(0) do |tr, i| tr + @rows[i][i] end end
返回矩阵的转置。
Matrix[[1,2], [3,4], [5,6]] # => 1 2 # 3 4 # 5 6 Matrix[[1,2], [3,4], [5,6]].transpose # => 1 3 5 # 2 4 6
# File matrix-0.4.2/lib/matrix.rb, line 1520 def transpose return self.class.empty(column_count, 0) if row_count.zero? new_matrix @rows.transpose, row_count end
如果这是一个酉矩阵则返回 true
。如果矩阵不是方阵,则引发错误。
# File matrix-0.4.2/lib/matrix.rb, line 986 def unitary? raise ErrDimensionMismatch unless square? rows.each_with_index do |row_i, i| rows.each_with_index do |row_j, j| s = 0 row_count.times do |k| s += row_i[k].conj * row_j[k] end return false unless s == (i == j ? 1 : 0) end end true end
如果这是一个上三角矩阵则返回 true
。
# File matrix-0.4.2/lib/matrix.rb, line 1003 def upper_triangular? each(:strict_lower).all?(&:zero?) end
返回一个新矩阵,该矩阵是通过将接收器与给定的矩阵垂直堆叠而形成的。
x = Matrix[[1, 2], [3, 4]] y = Matrix[[5, 6], [7, 8]] x.vstack(y) # => Matrix[[1, 2], [3, 4], [5, 6], [7, 8]]
# File matrix-0.4.2/lib/matrix.rb, line 1534 def vstack(*matrices) self.class.vstack(self, *matrices) end
如果这是一个仅包含零元素的矩阵,则返回 true
。
# File matrix-0.4.2/lib/matrix.rb, line 1010 def zero? all?(&:zero?) end
受保护的实例方法
# File matrix-0.4.2/lib/matrix.rb, line 1257 def power_int(exp) # assumes `exp` is an Integer > 0 # # Previous algorithm: # build M**2, M**4 = (M**2)**2, M**8, ... and multiplying those you need # e.g. M**0b1011 = M**11 = M * M**2 * M**8 # ^ ^ # (highlighted the 2 out of 5 multiplications involving `M * x`) # # Current algorithm has same number of multiplications but with lower exponents: # M**11 = M * (M * M**4)**2 # ^ ^ ^ # (highlighted the 3 out of 5 multiplications involving `M * x`) # # This should be faster for all (non nil-potent) matrices. case when exp == 1 self when exp.odd? self * power_int(exp - 1) else sqrt = power_int(exp / 2) sqrt * sqrt end end
私有实例方法
# File matrix-0.4.2/lib/matrix.rb, line 376 def check_int(val, direction) count = direction == :row ? row_count : column_count CoercionHelper.check_int(val, count, direction) end
返回范围或 nil
# File matrix-0.4.2/lib/matrix.rb, line 370 def check_range(val, direction) return unless val.is_a?(Range) count = direction == :row ? row_count : column_count CoercionHelper.check_range(val, count, direction) end
私有。请使用 Matrix#determinant
返回矩阵的行列式,使用 Bareiss 的多步整数保留高斯消元法。它与标准高斯消元法具有相同的计算成本阶数 O(n^3)。中间结果是无分数的,并且复杂度较低。因此,整数矩阵的中间结果也将是整数,且具有较小的 bignum(如果有的话),而浮点数矩阵通常具有精度更高的中间结果。
# File matrix-0.4.2/lib/matrix.rb, line 1368 def determinant_bareiss size = row_count last = size - 1 a = to_a no_pivot = Proc.new{ return 0 } sign = +1 pivot = 1 size.times do |k| previous_pivot = pivot if (pivot = a[k][k]) == 0 switch = (k+1 ... size).find(no_pivot) {|row| a[row][k] != 0 } a[switch], a[k] = a[k], a[switch] pivot = a[k][k] sign = -sign end (k+1).upto(last) do |i| ai = a[i] (k+1).upto(last) do |j| ai[j] = (pivot * ai[j] - ai[k] * a[k][j]) / previous_pivot end end end sign * pivot end
用于 dup 和 clone 调用。
# File matrix-0.4.2/lib/matrix.rb, line 1036 def initialize_copy(m) super @rows = @rows.map(&:dup) unless frozen? end
# File matrix-0.4.2/lib/matrix.rb, line 432 def set_col_range(row, col_range, value) value = if value.is_a?(Vector) value.to_a elsif value.is_a?(Matrix) raise ErrDimensionMismatch unless value.row_count == 1 value.row(0).to_a else Array.new(col_range.size, value) end raise ErrDimensionMismatch unless col_range.size == value.size @rows[row][col_range] = value end
# File matrix-0.4.2/lib/matrix.rb, line 425 def set_column_vector(row_range, col, value) value.each_with_index do |e, index| r = row_range.begin + index @rows[r][col] = e end end
# File matrix-0.4.2/lib/matrix.rb, line 387 def set_row_and_col_range(row_range, col_range, value) if value.is_a?(Matrix) if row_range.size != value.row_count || col_range.size != value.column_count raise ErrDimensionMismatch, [ 'Expected a Matrix of dimensions', "#{row_range.size}x#{col_range.size}", 'got', "#{value.row_count}x#{value.column_count}", ].join(' ') end source = value.instance_variable_get :@rows row_range.each_with_index do |row, i| @rows[row][col_range] = source[i] end elsif value.is_a?(Vector) raise ErrDimensionMismatch, 'Expected a Matrix or a value, got a Vector' else value_to_set = Array.new(col_range.size, value) row_range.each do |i| @rows[i][col_range] = value_to_set end end end
# File matrix-0.4.2/lib/matrix.rb, line 411 def set_row_range(row_range, col, value) if value.is_a?(Vector) raise ErrDimensionMismatch unless row_range.size == value.size set_column_vector(row_range, col, value) elsif value.is_a?(Matrix) raise ErrDimensionMismatch unless value.column_count == 1 value = value.column(0) raise ErrDimensionMismatch unless row_range.size == value.size set_column_vector(row_range, col, value) else @rows[row_range].each{|e| e[col] = value } end end
# File matrix-0.4.2/lib/matrix.rb, line 381 def set_value(row, col, value) raise ErrDimensionMismatch, "Expected a value, got a #{value.class}" if value.respond_to?(:to_matrix) @rows[row][col] = value end