класс Matrix
Класс Matrix представляет собой математическую матрицу. Он предоставляет методы для создания матриц, выполнения арифметических и алгебраических операций над ними, а также определения их математических свойств, таких как след, ранг, обратная матрица, определитель или собственные значения.
Константы
- SELECTORS
- VERSION
Атрибуты
Возвращает количество столбцов.
Возвращает количество столбцов.
создание экземпляров
Методы публичного класса
# File lib/matrix.rb, line 78 def Matrix.[](*rows) rows(rows, false) end
Создает матрицу, где каждый аргумент является строкой.
Matrix[ [25, 93], [-1, 66] ]
=> 25 93
-1 66 # File 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 Создает матрицу размером 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 lib/matrix.rb, line 209 def Matrix.column_vector(column) column = convert_to_array(column) new [column].transpose, 1 end
Создает матрицу с одним столбцом, где значения этого столбца заданы в column.
Matrix.column_vector([4,5,6])
=> 4
5
6 # File lib/matrix.rb, line 108 def Matrix.columns(columns) rows(columns, false).transpose end
Создает матрицу, используя columns в качестве массива столбцов.
Matrix.columns([[25, 93], [-1, 66]])
=> 25 -1
93 66 # File lib/matrix.rb, line 286
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 Создает матрицу, объединяя матрицы по элементам, используя заданный блок
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 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 Создает матрицу, где диагональные элементы состоят из values.
Matrix.diagonal(9, 5, -3)
=> 9 0 0
0 5 0
0 0 -3 # File 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
Создает пустую матрицу размером 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 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 Создает матрицу, объединяя матрицы по горизонтали
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 lib/matrix.rb, line 171 def Matrix.identity(n) scalar(n, 1) end
Создаёт n на n единичную матрицу.
Matrix.identity(2)
=> 1 0
0 1 # File lib/matrix.rb, line 311 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
Matrix.new является приватным; используйте Matrix.rows, columns, [], и т.д. для создания.
# File lib/matrix.rb, line 196 def Matrix.row_vector(row) row = convert_to_array(row) new [row] end
Создаёт матрицу с одной строкой, где значения этой строки заданы в row.
Matrix.row_vector([4,5,6]) => 4 5 6
# File 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 Создаёт матрицу, где rows является массивом массивов, каждый из которых является строкой матрицы. Если необязательный аргумент copy равен false, используйте заданные массивы как внутреннюю структуру матрицы без копирования.
Matrix.rows([[25, 93], [-1, 66]])
=> 25 93
-1 66 # File lib/matrix.rb, line 161 def Matrix.scalar(n, value) diagonal(*Array.new(n, value)) end
Создаёт n на n диагональную матрицу, где каждый диагональный элемент равен value.
Matrix.scalar(2, 5)
=> 5 0
0 5 # File 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 Создаёт матрицу, объединяя матрицы по вертикали
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 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.zero(2)
=> 0 0
0 0 Методы публичного экземпляра
# File lib/matrix.rb, line 1045
def *(m) # m is matrix or vector or number
case(m)
when Numeric
rows = @rows.collect {|row|
row.collect {|e| e * m }
}
return new_matrix 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
rows = Array.new(row_count) {|i|
Array.new(m.column_count) {|j|
(0 ... column_count).inject(0) do |vij, k|
vij + self[i, k] * m[k, j]
end
}
}
return new_matrix rows, m.column_count
else
return apply_through_coercion(m, __method__)
end
end Умножение на Matrix.
Matrix[[2,4], [6,8]] * Matrix.identity(2)
=> 2 4
6 8 # File lib/matrix.rb, line 1222
def **(other)
case other
when Integer
x = self
if other <= 0
x = self.inverse
return self.class.identity(self.column_count) if other == 0
other = -other
end
z = nil
loop do
z = z ? z * x : x if other[0] == 1
return z if (other >>= 1).zero?
x *= x
end
when Numeric
v, d, v_inv = eigensystem
v * self.class.diagonal(*d.each(:diagonal).map{|e| e ** other}) * v_inv
else
raise ErrOperationNotDefined, ["**", self.class, other.class]
end
end Возведение в степень Matrix. Эквивалентно умножению матрицы на себя N раз. Для нецелых показателей степени будет использовано диагонализация матрицы.
Matrix[[7,6], [3,9]] ** 2
=> 67 96
48 99 # File lib/matrix.rb, line 1078
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.
Matrix.scalar(2,5) + Matrix[[1,0], [-4,7]]
=> 6 0
-4 12 # File lib/matrix.rb, line 1245 def +@ self end
# File lib/matrix.rb, line 1105
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.
Matrix[[1,5], [4,2]] - Matrix[[9,3], [-4,1]]
=> -8 2
8 1 # File lib/matrix.rb, line 1249
def -@
collect {|e| -e }
end # File lib/matrix.rb, line 1132
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 Деление (умножение на обратную матрицу) Matrix.
Matrix[[7,6], [3,9]] / Matrix[[2,9], [3,1]]
=> -7 1
-3 -6 # File lib/matrix.rb, line 1008
def ==(other)
return false unless Matrix === other &&
column_count == other.column_count # necessary for empty matrices
rows == other.rows
end Возвращает true, если и только если две матрицы содержат одинаковые элементы.
# File lib/matrix.rb, line 326
def [](i, j)
@rows.fetch(i){return nil}[j]
end Возвращает элемент (i, j) матрицы. То есть: строка i, столбец j.
# File lib/matrix.rb, line 340
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 Установка элемента или элементов Set матрицы.
# File lib/matrix.rb, line 1256 def abs collect(&:abs) end
Возвращает модуль элементов по отдельности
# File lib/matrix.rb, line 781
def adjugate
raise ErrDimensionMismatch unless square?
Matrix.build(row_count, column_count) do |row, column|
cofactor(column, row)
end
end Возвращает присоединенную матрицу.
Matrix[ [7,6],[3,9] ].adjugate
=> 9 -6
-3 7 # File lib/matrix.rb, line 960
def antisymmetric?
raise ErrDimensionMismatch unless square?
each_with_index(:upper) do |e, row, col|
return false unless e == -rows[col][row]
end
true
end Возвращает true, если это кососимметрическая матрица. Возвращает ошибку, если матрица не квадратная.
# File lib/matrix.rb, line 1565
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 Метод coerce обеспечивает поддержку приведения типов в Ruby. Этот механизм приведения типов используется Ruby для обработки операций с числами разных типов: он призван найти совместимый общий тип между двумя операндами оператора. См. также Numeric#coerce.
# File lib/matrix.rb, line 766 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
Возвращает (строка, столбец) алгебраическое дополнение, полученное умножением первого минора на (-1)**(строка + столбец).
Matrix.diagonal(9, 5, -3, 4).cofactor(1, 1) => -108
# File lib/matrix.rb, line 497 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: возвращает только элементы на или выше диагонали
-
Matrix[ [1,2], [3,4] ].collect { |e| e**2 }
=> 1 4 9 16
# File lib/matrix.rb, line 515
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 Вызывает заданный блок для каждого элемента матрицы, заменяя элемент значением, возвращаемым блоком. Элементы можно ограничить, передав аргумент:
-
:all (по умолчанию): возвращает все элементы
-
:diagonal: возвращает только элементы на диагонали
-
:off_diagonal: возвращает все элементы, кроме диагональных
-
:lower: возвращает только элементы на или ниже диагонали
-
:strict_lower: возвращает только элементы ниже диагонали
-
:strict_upper: возвращает только элементы выше диагонали
-
:upper: возвращает только элементы на или выше диагонали
# File lib/matrix.rb, line 466
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 Возвращает вектор-столбец с номером j матрицы в виде Vector (начиная с 0, как в массиве). Если задан блок, элементы этого вектора будут итерироваться.
# File lib/matrix.rb, line 1586
def column_vectors
Array.new(column_count) {|i|
column(i)
}
end Возвращает массив векторов-столбцов матрицы. См. Vector.
# File lib/matrix.rb, line 304 def combine(*matrices, &block) Matrix.combine(self, *matrices, &block) end
# File lib/matrix.rb, line 1511 def conjugate collect(&:conjugate) 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 lib/matrix.rb, line 1274
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 Возвращает определитель матрицы.
Будьте внимательны, использование значений типа Float может привести к неточным результатам из-за недостаточной точности. Рассмотрите использование точных типов, таких как Rational или BigDecimal.
Matrix[[7,6], [3,9]].determinant => 45
# File lib/matrix.rb, line 1355 def determinant_e warn "Matrix#determinant_e is deprecated; use #determinant", uplevel: 1 determinant end
устаревшее; используйте Matrix#determinant
# File lib/matrix.rb, line 827 def diagonal? raise ErrDimensionMismatch unless square? each(:off_diagonal).all?(&:zero?) end
Возвращает true, если это диагональная матрица. Вызывает ошибку, если матрица не квадратная.
# File lib/matrix.rb, line 544
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 Возвращает все элементы матрицы, начиная с первого ряда, или возвращает перечислитель Enumerator, если блок не задан. Элементы могут быть ограничены, передав аргумент:
-
: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 lib/matrix.rb, line 604
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 Аналогично 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 lib/matrix.rb, line 1478 def eigensystem EigenvalueDecomposition.new(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 lib/matrix.rb, line 1609 def elements_to_f warn "Matrix#elements_to_f is deprecated, use map(&:to_f)", uplevel: 1 map(&:to_f) end
Устаревшее.
Используйте map(&:to_f)
# File lib/matrix.rb, line 1617 def elements_to_i warn "Matrix#elements_to_i is deprecated, use map(&:to_i)", uplevel: 1 map(&:to_i) end
Устаревшее.
Используйте map(&:to_i)
# File lib/matrix.rb, line 1625 def elements_to_r warn "Matrix#elements_to_r is deprecated, use map(&:to_r)", uplevel: 1 map(&:to_r) end
Устаревшее.
Используйте map(&:to_r)
# File lib/matrix.rb, line 836 def empty? column_count == 0 || row_count == 0 end
Возвращает true, если это пустая матрица, т.е. если число строк или столбцов равно 0.
# File lib/matrix.rb, line 1014
def eql?(other)
return false unless Matrix === other &&
column_count == other.column_count # necessary for empty matrices
rows.eql? other.rows
end # File lib/matrix.rb, line 739
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 Возвращает подматрицу, полученную путём удаления указанной строки и столбца.
Matrix.diagonal(9, 5, -3, 4).first_minor(1, 2)
=> 9 0 0
0 0 0
0 0 4 # File lib/matrix.rb, line 523 def freeze @rows.freeze super end
Object#freeze # File lib/matrix.rb, line 1152
def hadamard_product(m)
combine(m){|a, b| a * b}
end Произведение Адамара
Matrix[[1,2], [3,4]].hadamard_product(Matrix[[1,2], [3,2]])
=> 1 4
9 8 # File lib/matrix.rb, line 1031 def hash @rows.hash end
Возвращает хэш-код для матрицы.
# File lib/matrix.rb, line 844
def hermitian?
raise ErrDimensionMismatch unless square?
each_with_index(:upper).all? do |e, row, col|
e == rows[col][row].conj
end
end Возвращает true, если это эрмитова матрица. Вызывает ошибку, если матрица не квадратная.
# File lib/matrix.rb, line 1369 def hstack(*matrices) self.class.hstack(self, *matrices) 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 lib/matrix.rb, line 1525 def imaginary collect(&:imaginary) 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 lib/matrix.rb, line 667
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 Метод 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 lib/matrix.rb, line 1650
def inspect
if empty?
"#{self.class}.empty(#{row_count}, #{column_count})"
else
"#{self.class}#{@rows.inspect}"
end
end Переопределяет Object#inspect
# File lib/matrix.rb, line 1163 def inverse raise ErrDimensionMismatch unless square? self.class.I(row_count).send(:inverse_from, self) end
Возвращает обратную матрицу.
Matrix[[-1, -1], [0, -1]].inverse
=> -1 1
0 -1 # File lib/matrix.rb, line 798
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 Возвращает разложение Лапласа по заданной строке или столбцу.
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 lib/matrix.rb, line 854 def lower_triangular? each(:strict_upper).all?(&:zero?) end
Возвращает true если это нижняя треугольная матрица.
# File lib/matrix.rb, line 1493 def lup LUPDecomposition.new(self) 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 lib/matrix.rb, line 698
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 Возвращает секцию матрицы. Параметрами являются:
-
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 - последний элемент). Возвращает nil, если начальная строка или столбец больше, чем row_count или column_count соответственно.
# File lib/matrix.rb, line 862
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 lib/matrix.rb, line 880
def orthogonal?
raise ErrDimensionMismatch unless square?
rows.each_with_index do |row, i|
column_count.times do |j|
s = 0
row_count.times do |k|
s += row[k] * rows[k][j]
end
return false unless s == (i == j ? 1 : 0)
end
end
true
end Возвращает true если это ортогональная матрица. Вызывает ошибку, если матрица не квадратная.
# File lib/matrix.rb, line 898
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 Возвращает true если это матрица перестановок. Вызывает ошибку, если матрица не квадратная.
# File lib/matrix.rb, line 1382
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 Возвращает ранг матрицы. Имейте в виду, что использование значений Float может давать ошибочные результаты из-за их недостаточной точности. Рассмотрите использование точных типов, таких как Rational или BigDecimal вместо этого.
Matrix[[7,6], [3,9]].rank => 2
# File lib/matrix.rb, line 1413 def rank_e warn "Matrix#rank_e is deprecated; use #rank", uplevel: 1 rank end
устарело; используйте Matrix#rank
# File lib/matrix.rb, line 1539 def real collect(&:real) 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 lib/matrix.rb, line 919 def real? all?(&:real?) end
Возвращает true если все элементы матрицы действительны.
# File lib/matrix.rb, line 1549 def rect [real, imag] end
Возвращает массив, содержащий матрицы, соответствующие действительной и мнимой частям матрицы
m.rect == [m.real, m.imag] # ==> true для всех матриц m
# File lib/matrix.rb, line 926 def regular? not singular? end
Возвращает true если это регулярная (т.е. несингулярная) матрица.
# File lib/matrix.rb, line 1421
def round(ndigits=0)
map{|e| e.round(ndigits)}
end Возвращает матрицу с элементами, округленными до заданной точности (см. Float#round)
# File lib/matrix.rb, line 452
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 Возвращает вектор-строку с номером i матрицы в виде Vector (индексация начинается с 0, как в массиве). Если задан блок, элементы этого вектора будут итерироваться.
# File lib/matrix.rb, line 437 def row_count @rows.size end
Возвращает количество строк.
# File lib/matrix.rb, line 1577
def row_vectors
Array.new(row_count) {|i|
row(i)
}
end Возвращает массив векторов-строк матрицы. Смотрите Vector.
# File lib/matrix.rb, line 933 def singular? determinant == 0 end
Возвращает true, если матрица вырожденная.
# File lib/matrix.rb, line 940 def square? column_count == row_count end
Возвращает true, если матрица квадратная.
# File lib/matrix.rb, line 948
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 Возвращает true, если матрица симметричная. Возбуждает ошибку, если матрица не квадратная.
# File lib/matrix.rb, line 1602 def to_a @rows.collect(&:dup) end
Возвращает массив массивов, описывающих строки матрицы.
# File lib/matrix.rb, line 1595 def to_matrix self end
Явное преобразование в Matrix. Возвращает self
# File lib/matrix.rb, line 1637
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 Переопределяет Object#to_s
# File lib/matrix.rb, line 1430
def trace
raise ErrDimensionMismatch unless square?
(0...column_count).inject(0) do |tr, i|
tr + @rows[i][i]
end
end Возвращает след (сумму диагональных элементов) матрицы.
Matrix[[7,6], [3,9]].trace => 16
# File lib/matrix.rb, line 1448 def transpose return self.class.empty(column_count, 0) if row_count.zero? new_matrix @rows.transpose, row_count 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 lib/matrix.rb, line 973
def unitary?
raise ErrDimensionMismatch unless square?
rows.each_with_index do |row, i|
column_count.times do |j|
s = 0
row_count.times do |k|
s += row[k].conj * rows[k][j]
end
return false unless s == (i == j ? 1 : 0)
end
end
true
end Возвращает true, если матрица унитарная. Возбуждает ошибку, если матрица не квадратная.
# File lib/matrix.rb, line 990 def upper_triangular? each(:strict_lower).all?(&:zero?) end
Возвращает true, если матрица верхнетреугольная.
# File lib/matrix.rb, line 1462 def vstack(*matrices) self.class.vstack(self, *matrices) 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 lib/matrix.rb, line 997 def zero? all?(&:zero?) end
Возвращает true, если матрица состоит только из нулевых элементов.
Приватные методы экземпляра
# File lib/matrix.rb, line 365
def check_int(val, direction)
count = direction == :row ? row_count : column_count
CoercionHelper.check_int(val, count, direction)
end # File lib/matrix.rb, line 359
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 Возвращает диапазон или nil
# File lib/matrix.rb, line 1325
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 Приватный. Используйте Matrix#determinant
Возвращает определитель матрицы, используя многоступенчатую целочисленную элиминацию Гаусса Барейсса. Она имеет ту же вычислительную сложность порядка O(n^3), что и стандартная элиминация Гаусса. Промежуточные результаты свободные от дробей и имеют меньшую сложность. Матрица целых чисел будет иметь таким образом промежуточные результаты, которые также являются целыми числами, с меньшими большими числами (если таковые имеются), в то время как матрица Float обычно имеет промежуточные результаты с большей точностью.
# File lib/matrix.rb, line 1023
def initialize_copy(m)
super
@rows = @rows.map(&:dup) unless frozen?
end Вызывается для dup и clone.
# File lib/matrix.rb, line 421
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 lib/matrix.rb, line 414
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 lib/matrix.rb, line 376
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 lib/matrix.rb, line 400
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 lib/matrix.rb, line 370
def set_value(row, col, value)
raise ErrDimensionMismatch, "Expected a a value, got a #{value.class}" if value.respond_to?(:to_matrix)
@rows[row][col] = value
end
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.