ruby-changes:35687
From: marcandre <ko1@a...>
Date: Fri, 3 Oct 2014 12:44:26 +0900 (JST)
Subject: [ruby-changes:35687] marcandRe: r47769 (trunk): * lib/matrix.rb: Add hstack & vstack methods.
marcandre 2014-10-03 12:44:20 +0900 (Fri, 03 Oct 2014) New Revision: 47769 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=47769 Log: * lib/matrix.rb: Add hstack & vstack methods. Based on a patch by creasywuqiong. [Fix GH-344] Modified files: trunk/ChangeLog trunk/NEWS trunk/lib/matrix.rb trunk/test/matrix/test_matrix.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 47768) +++ ChangeLog (revision 47769) @@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Fri Oct 3 12:42:15 2014 Marc-Andre Lafortune <ruby-core@m...> + + * lib/matrix.rb: Add hstack & vstack methods. + Based on a patch by creasywuqiong. [Fix GH-344] + Fri Oct 3 12:37:48 2014 Marc-Andre Lafortune <ruby-core@m...> * lib/matrix.rb: Fix Matrix.rows copy bug. Index: lib/matrix.rb =================================================================== --- lib/matrix.rb (revision 47768) +++ lib/matrix.rb (revision 47769) @@ -45,6 +45,8 @@ end https://github.com/ruby/ruby/blob/trunk/lib/matrix.rb#L45 # * Matrix.zero(n) # * Matrix.row_vector(row) # * Matrix.column_vector(column) +# * Matrix.hstack(*matrices) +# * Matrix.vstack(*matrices) # # To access Matrix elements/columns/rows/submatrices/properties: # * #[](i, j) @@ -90,12 +92,14 @@ end https://github.com/ruby/ruby/blob/trunk/lib/matrix.rb#L92 # Matrix functions: # * #determinant # * #det +# * #hstack(*matrices) # * #rank # * #round # * #trace # * #tr # * #transpose # * #t +# * #vstack(*matrices) # # Matrix decompositions: # * #eigen @@ -296,6 +300,51 @@ class Matrix https://github.com/ruby/ruby/blob/trunk/lib/matrix.rb#L300 end # + # Create a matrix by stacking matrices vertically + # + # 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]] + # + def Matrix.vstack(x, *matrices) + raise TypeError, "Expected a Matrix, got a #{x.class}" unless x.is_a?(Matrix) + result = x.send(:rows).map(&:dup) + matrices.each do |m| + raise TypeError, "Expected a Matrix, got a #{m.class}" unless m.is_a?(Matrix) + 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 + + + # + # Create a matrix by stacking matrices horizontally + # + # 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]] + # + def Matrix.hstack(x, *matrices) + raise TypeError, "Expected a Matrix, got a #{x.class}" unless x.is_a?(Matrix) + result = x.send(:rows).map(&:dup) + total_column_count = x.column_count + matrices.each do |m| + raise TypeError, "Expected a Matrix, got a #{m.class}" unless m.is_a?(Matrix) + 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 + + # # Matrix.new is private; use Matrix.rows, columns, [], etc... to create. # def initialize(rows, column_count = rows[0].size) @@ -1143,6 +1192,18 @@ class Matrix https://github.com/ruby/ruby/blob/trunk/lib/matrix.rb#L1192 alias det_e determinant_e # + # Returns a new matrix resulting by stacking horizontally + # the receiver with the given matrices + # + # x = Matrix[[1, 2], [3, 4]] + # y = Matrix[[5, 6], [7, 8]] + # x.hstack(y) # => Matrix[[1, 2, 5, 6], [3, 4, 7, 8]] + # + def hstack(*matrices) + self.class.hstack(self, *matrices) + end + + # # Returns the rank of the matrix. # Beware that using Float values can yield erroneous results # because of their lack of precision. @@ -1223,6 +1284,18 @@ class Matrix https://github.com/ruby/ruby/blob/trunk/lib/matrix.rb#L1284 end alias t transpose + # + # Returns a new matrix resulting by stacking vertically + # the receiver with the given matrices + # + # x = Matrix[[1, 2], [3, 4]] + # y = Matrix[[5, 6], [7, 8]] + # x.vstack(y) # => Matrix[[1, 2], [3, 4], [5, 6], [7, 8]] + # + def vstack(*matrices) + self.class.vstack(self, *matrices) + end + #-- # DECOMPOSITIONS -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #++ Index: NEWS =================================================================== --- NEWS (revision 47768) +++ NEWS (revision 47769) @@ -78,6 +78,8 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L78 by deleting the specified row and column. * Matrix#cofactor(row, column) returns the (row, column) cofactor which is obtained by multiplying the first minor by (-1)**(row + column). + * hstack and vstack are new instance and class methods to stack matrices + horizontally and vertically. * Method * New methods: Index: test/matrix/test_matrix.rb =================================================================== --- test/matrix/test_matrix.rb (revision 47768) +++ test/matrix/test_matrix.rb (revision 47769) @@ -1,6 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/test/matrix/test_matrix.rb#L1 require 'test/unit' require 'matrix' +class SubMatrix < Matrix +end + class TestMatrix < Test::Unit::TestCase def setup @m1 = Matrix[[1,2,3], [4,5,6]] @@ -9,6 +12,8 @@ class TestMatrix < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/matrix/test_matrix.rb#L12 @m4 = Matrix[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]] @n1 = Matrix[[2,3,4], [5,6,7]] @c1 = Matrix[[Complex(1,2), Complex(0,1), 0], [1, 2, 3]] + @e1 = Matrix.empty(2,0) + @e2 = Matrix.empty(0,3) end def test_matrix @@ -499,4 +504,34 @@ class TestMatrix < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/matrix/test_matrix.rb#L504 end assert_equal(1, s1 ** o) end + + def test_hstack + assert_equal Matrix[[1,2,3,2,3,4,1,2,3], [4,5,6,5,6,7,4,5,6]], + @m1.hstack(@n1, @m1) + # Error checking: + assert_raise(TypeError) { @m1.hstack(42) } + assert_raise(TypeError) { Matrix.hstack(42, @m1) } + assert_raise(Matrix::ErrDimensionMismatch) { @m1.hstack(Matrix.identity(3)) } + assert_raise(Matrix::ErrDimensionMismatch) { @e1.hstack(@e2) } + # Corner cases: + assert_equal @m1, @m1.hstack + assert_equal @e1, @e1.hstack(@e1) + assert_equal Matrix.empty(0,6), @e2.hstack(@e2) + assert_equal SubMatrix, SubMatrix.hstack(@e1).class + end + + def test_vstack + assert_equal Matrix[[1,2,3], [4,5,6], [2,3,4], [5,6,7], [1,2,3], [4,5,6]], + @m1.vstack(@n1, @m1) + # Error checking: + assert_raise(TypeError) { @m1.vstack(42) } + assert_raise(TypeError) { Matrix.vstack(42, @m1) } + assert_raise(Matrix::ErrDimensionMismatch) { @m1.vstack(Matrix.identity(2)) } + assert_raise(Matrix::ErrDimensionMismatch) { @e1.vstack(@e2) } + # Corner cases: + assert_equal @m1, @m1.vstack + assert_equal Matrix.empty(4,0), @e1.vstack(@e1) + assert_equal @e2, @e2.vstack(@e2) + assert_equal SubMatrix, SubMatrix.vstack(@e1).class + end end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/