Created
October 3, 2009 21:34
-
-
Save leandro/200896 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Matrix#det2 does what Matrix#det doesn't do: calculate correctly a matrix determinant | |
require 'matrix' | |
module FixnumExt | |
def square? | |
sqrt = self ** (1.0/2) | |
(sqrt - sqrt.to_i).zero? | |
end | |
end | |
module MatrixDeterminant | |
def det2 | |
return nil unless self.square? | |
return self[0,0] if self.row_size == 1 | |
return self[0,0] * self[1,1] - self[0,1] * self[1,0] if self.row_size == 2 | |
return self[0,0] * self[1,1] * self[2,2] + self[1,0] * self[2,1] * self[0,2] + self[2,0] * self[0,1] * self[1,2] - | |
self[0,2] * self[1,1] * self[2,0] - self[0,0] * self[1,2] * self[2,1] - self[0,1] * self[1,0] * | |
self[2,2] if self.row_size == 3 | |
# calculating determinant for 4x4 or bigger | |
most_zeros_line = self.lowest_cost_line | |
_row = most_zeros_line > 0 | |
line_index = _row ? most_zeros_line - 1 : most_zeros_line.abs - 1 | |
line = (_row ? self.row(line_index) : self.column(line_index)).to_a | |
sum = 0 | |
line.each_index {|k| sum += line[k].zero? ? 0 : line[k] * (_row ? self.minor2(line_index, k).det2 : self.minor2(k, line_index).det2)} | |
sum | |
end | |
def lowest_cost_line | |
rows = self.to_a.map {|e| e - [0]} | |
cols = self.transpose.to_a.map {|e| e - [0]} | |
lowest_row = rows.index(rows.inject(rows.first) {|lowest, e| lowest.size > e.size ? e : lowest}) | |
lowest_col = cols.index(cols.inject(cols.first) {|lowest, e| lowest.size > e.size ? e : lowest}) | |
rows[lowest_row].size <= cols[lowest_col].size ? lowest_row + 1 : - (lowest_col + 1) | |
end | |
def minor2(row, col) | |
r = [] | |
self.row_size.times do |i| | |
next if i == row | |
r << (crow = []) | |
self.column_size.times do |j| | |
next if j == col | |
crow << self[i,j] | |
end | |
end | |
Matrix[*r] | |
end | |
end | |
module MatrixCoreExt | |
def self.included(base) | |
base.extend ClassMethods | |
end | |
module ClassMethods | |
def square_from_rows *members | |
return nil unless members.size.square? | |
msize = (members.size ** (1.0/2)).to_i | |
matrix = [] | |
members.each_slice(msize) {|s| matrix << s} | |
Matrix[*matrix] | |
end | |
end | |
def % num | |
r = [] | |
self.row_size.times do |i| | |
r << (crow = []) | |
self.column_size.times do |j| | |
crow << self[i,j] % num | |
end | |
end | |
Matrix[*r] | |
end | |
end | |
module Main | |
class ::Matrix | |
include MatrixDeterminant | |
include MatrixCoreExt | |
end | |
class ::Fixnum | |
include FixnumExt | |
end | |
end | |
include Main | |
puts Matrix.square_from_rows(0,6,0,0,0,0,7,0,0,5,4,5,1,2,1,6,2,1,4,2,3,2,0,2,1).det2 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment