class GraphViz class Math def self.Matrix( line, column = 0, val = 0 ) GraphViz::Math::Matrix.new(line, column, val) end class CoordinateError < RuntimeError end class ValueError < RuntimeError end class Matrix def initialize( line_or_array, column = 0, val = 0 ) if line_or_array.kind_of?(Array) line = line_or_array.size column = nil line_or_array.size.times do |l| unless line_or_array[l].kind_of?(Array) raise ArgumentError, "Wrong matrix definition" end column = line_or_array[l].size if column.nil? unless line_or_array[l].size == column raise ArgumentError, "Wrong matrix definition" end line_or_array[l].size.times do |c| unless line_or_array[l][c].kind_of?(Numeric) raise ValueError, "Element at [#{l+1}, #{c+1}] is not a number" end end end @matrix = line_or_array @line = line @column = column elsif line_or_array.kind_of?(Integer) and column > 0 @matrix = Array.new(line_or_array) @matrix.size.times do |l| @matrix[l] = Array.new(column) @matrix[l].size.times do |c| @matrix[l][c] = val end end @line = line_or_array @column = column else raise ArgumentError, "Wrong matrix definition" end end def [](line, column) unless (0...@line).to_a.include?(line-1) raise CoordinateError, "Line out of range (#{line} for 1..#{@line})!" end unless (0...@column).to_a.include?(column-1) raise CoordinateError, "Column out of range (#{column} for 1..#{@column})!" end @matrix[line-1][column-1] end def []=( line, column, val ) unless (0...@line).to_a.include?(line-1) raise CoordinateError, "Line out of range (#{line} for 1..#{@line})!" end unless (0...@column).to_a.include?(column-1) raise CoordinateError, "Column out of range (#{column} for 1..#{@column})!" end @matrix[line-1][column-1] = val end def matrix @matrix end alias :to_a :matrix def columns @column end def lines @line end def to_s size = bigger out = "" @line.times do |line| out << "[" @column.times do |column| out << sprintf(" %1$*2$s", @matrix[line][column].to_s, size) end out << "]\n" end return out end def -(m) matrix = GraphViz::Math::Matrix.new( @line, @column ) @line.times do |line| @column.times do |column| matrix[line+1, column+1] = self[line+1, column+1] - m[line+1, column+1] end end return matrix end def *(m) matrix = GraphViz::Math::Matrix.new( @line, @line ) @line.times do |line| @line.times do |column| l = self.line(line+1) c = m.column(column+1) v = 0 l.size.times do |i| v += l[i]*c[i] end matrix[line+1,column+1] = v end end return matrix end def line( line ) unless (0...@line).to_a.include?(line-1) raise CoordinateError, "Line out of range (#{line} for 1..#{@line})!" end @matrix[line-1] end def column( column ) col = [] unless (0...@column).to_a.include?(column-1) raise CoordinateError, "Column out of range (#{column} for 1..#{@column})!" end @line.times do |line| col << self[line+1, column] end return col end def transpose matrix = GraphViz::Math::Matrix.new( @column, @line ) @line.times do |line| @column.times do |column| matrix[column+1, line+1] = self[line+1, column+1] end end return matrix end def ==(m) equal = true @line.times do |line| @column.times do |column| equal &&= (m[line+1, column+1] == self[line+1, column+1]) end end return equal end def remove_line(n) unless (0...@line).to_a.include?(n-1) raise CoordinateError, "Line out of range (#{n} for 1..#{@line})!" end matrix = GraphViz::Math::Matrix.new( @line - 1, @column ) nline = 0 @line.times do |line| next if line == n - 1 @column.times do |column| matrix[nline+1, column+1] = self[line+1, column+1] end nline += 1 end return matrix end def remove_column(n) unless (0...@column).to_a.include?(n-1) raise CoordinateError, "Column out of range (#{n} for 1..#{@column})!" end matrix = GraphViz::Math::Matrix.new( @line, @column - 1 ) @line.times do |line| ncolumn = 0 @column.times do |column| next if column == n - 1 matrix[line+1, ncolumn+1] = self[line+1, column+1] ncolumn += 1 end end return matrix end def sum_of_column(n) column(n).inject(0){|sum,item| sum + item} end def sum_of_line(n) line(n).inject(0){|sum,item| sum + item} end def set_matrix(m) #:nodoc: @matrix = m end private def bigger b = 0 @matrix.each do |line| line.each do |column| b = column.to_s.size if column.to_s.size > b end end return b end end end end