mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	lib/matrix.rb: Make Matrix & Vector mutable. Add #[]=, #map!.
Adapted from patch by Grzegorz Jakubiak. [#14151] [Fix GH-1769] [Fix GH-1905] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65507 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
		
							parent
							
								
									b9d42af0f2
								
							
						
					
					
						commit
						eda970cfe2
					
				
					 4 changed files with 476 additions and 22 deletions
				
			
		
							
								
								
									
										8
									
								
								NEWS
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								NEWS
									
										
									
									
									
								
							|  | @ -313,6 +313,14 @@ sufficient information, see the ChangeLog file or Redmine | |||
| 
 | ||||
|     * Matrix#antisymmetric? / #skew_symmetric? | ||||
| 
 | ||||
|     * Matrix#map! / #collect! [Feature #14151] | ||||
| 
 | ||||
|     * Matrix#[]= | ||||
| 
 | ||||
|     * Vector#map! / #collect! | ||||
| 
 | ||||
|     * Vector#[]= | ||||
| 
 | ||||
| [Net] | ||||
| 
 | ||||
|   [New options] | ||||
|  |  | |||
							
								
								
									
										247
									
								
								lib/matrix.rb
									
										
									
									
									
								
							
							
						
						
									
										247
									
								
								lib/matrix.rb
									
										
									
									
									
								
							|  | @ -302,12 +302,107 @@ class Matrix | |||
|   alias element [] | ||||
|   alias component [] | ||||
| 
 | ||||
|   # | ||||
|   # :call-seq: | ||||
|   #   matrix[range, range] = matrix/element | ||||
|   #   matrix[range, integer] = vector/column_matrix/element | ||||
|   #   matrix[integer, range] = vector/row_matrix/element | ||||
|   #   matrix[integer, integer] = element | ||||
|   # | ||||
|   # Set element or elements of matrix. | ||||
|   def []=(i, j, v) | ||||
|     @rows[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 | ||||
|   alias set_element []= | ||||
|   alias set_component []= | ||||
|   private :[]=, :set_element, :set_component | ||||
|   private :set_element, :set_component | ||||
| 
 | ||||
|   # Returns range or nil | ||||
|   private 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 | ||||
| 
 | ||||
|   private def check_int(val, direction) | ||||
|     count = direction == :row ? row_count : column_count | ||||
|     CoercionHelper.check_int(val, count, direction) | ||||
|   end | ||||
| 
 | ||||
|   private 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 | ||||
| 
 | ||||
|   private 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 | ||||
| 
 | ||||
|   private def set_row_range(row_range, col, value) | ||||
|     if value.is_a?(Vector) | ||||
|       Matrix.Raise ErrDimensionMismatch unless row_range.size == value.size | ||||
|       set_column_vector(row_range, col, value) | ||||
|     elsif value.is_a?(Matrix) | ||||
|       Matrix.Raise ErrDimensionMismatch unless value.column_count == 1 | ||||
|       value = value.column(0) | ||||
|       Matrix.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 | ||||
| 
 | ||||
|   private 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 | ||||
| 
 | ||||
|   private def set_col_range(row, col_range, value) | ||||
|     value = if value.is_a?(Vector) | ||||
|       value.to_a | ||||
|     elsif value.is_a?(Matrix) | ||||
|       Matrix.Raise ErrDimensionMismatch unless value.row_count == 1 | ||||
|       value.row(0).to_a | ||||
|     else | ||||
|       Array.new(col_range.size, value) | ||||
|     end | ||||
|     Matrix.Raise ErrDimensionMismatch unless col_range.size == value.size | ||||
|     @rows[row][col_range] = value | ||||
|   end | ||||
| 
 | ||||
|   # | ||||
|   # Returns the number of rows. | ||||
|  | @ -360,17 +455,49 @@ class Matrix | |||
|   # | ||||
|   # Returns a matrix that is the result of iteration of the given block over all | ||||
|   # elements of the matrix. | ||||
|   # Elements can be restricted by passing an argument: | ||||
|   # * :all (default): yields all elements | ||||
|   # * :diagonal: yields only elements on the diagonal | ||||
|   # * :off_diagonal: yields all elements except on the diagonal | ||||
|   # * :lower: yields only elements on or below the diagonal | ||||
|   # * :strict_lower: yields only elements below the diagonal | ||||
|   # * :strict_upper: yields only elements above the diagonal | ||||
|   # * :upper: yields only elements on or above the diagonal | ||||
|   #   Matrix[ [1,2], [3,4] ].collect { |e| e**2 } | ||||
|   #     => 1  4 | ||||
|   #        9 16 | ||||
|   # | ||||
|   def collect(&block) # :yield: e | ||||
|     return to_enum(:collect) unless block_given? | ||||
|     rows = @rows.collect{|row| row.collect(&block)} | ||||
|     new_matrix rows, column_count | ||||
|   def collect(which = :all, &block) # :yield: e | ||||
|     return to_enum(:collect, which) unless block_given? | ||||
|     dup.collect!(which, &block) | ||||
|   end | ||||
|   alias_method :map, :collect | ||||
| 
 | ||||
|   # | ||||
|   # Invokes the given block for each element of matrix, replacing the element with the value | ||||
|   # returned by the block. | ||||
|   # Elements can be restricted by passing an argument: | ||||
|   # * :all (default): yields all elements | ||||
|   # * :diagonal: yields only elements on the diagonal | ||||
|   # * :off_diagonal: yields all elements except on the diagonal | ||||
|   # * :lower: yields only elements on or below the diagonal | ||||
|   # * :strict_lower: yields only elements below the diagonal | ||||
|   # * :strict_upper: yields only elements above the diagonal | ||||
|   # * :upper: yields only elements on or above the diagonal | ||||
|   # | ||||
|   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 | ||||
| 
 | ||||
|   alias map! collect! | ||||
| 
 | ||||
|   def freeze | ||||
|     @rows.freeze | ||||
|     super | ||||
|   end | ||||
| 
 | ||||
|   # | ||||
|   # Yields all elements of the matrix, starting with those of the first row, | ||||
|   # or returns an Enumerator if no block given. | ||||
|  | @ -865,12 +992,11 @@ class Matrix | |||
|   end | ||||
| 
 | ||||
|   # | ||||
|   # Returns a clone of the matrix, so that the contents of each do not reference | ||||
|   # identical objects. | ||||
|   # There should be no good reason to do this since Matrices are immutable. | ||||
|   # Called for dup & clone. | ||||
|   # | ||||
|   def clone | ||||
|     new_matrix @rows.map(&:dup), column_count | ||||
|   private def initialize_copy(m) | ||||
|     super | ||||
|     @rows = @rows.map(&:dup) unless frozen? | ||||
|   end | ||||
| 
 | ||||
|   # | ||||
|  | @ -1562,6 +1688,26 @@ class Matrix | |||
|     def self.coerce_to_matrix(obj) | ||||
|       coerce_to(obj, Matrix, :to_matrix) | ||||
|     end | ||||
| 
 | ||||
|     # Returns `nil` for non Ranges | ||||
|     # Checks range validity, return canonical range with 0 <= begin <= end < count | ||||
|     def self.check_range(val, count, kind) | ||||
|       canonical = (val.begin + (val.begin < 0 ? count : 0)).. | ||||
|                   (val.end ? val.end + (val.end < 0 ? count : 0) - (val.exclude_end? ? 1 : 0) | ||||
|                            : count - 1) | ||||
|       unless 0 <= canonical.begin && canonical.begin <= canonical.end && canonical.end < count | ||||
|         raise IndexError, "given range #{val} is outside of #{kind} dimensions: 0...#{count}" | ||||
|       end | ||||
|       canonical | ||||
|     end | ||||
| 
 | ||||
|     def self.check_int(val, count, kind) | ||||
|       val = CoercionHelper.coerce_to_int(val) | ||||
|       if val >= count || val < -count | ||||
|         raise IndexError, "given #{kind} #{val} is outside of #{-count}...#{count}" | ||||
|       end | ||||
|       val | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   include CoercionHelper | ||||
|  | @ -1656,6 +1802,9 @@ end | |||
| # To access elements: | ||||
| # * #[](i) | ||||
| # | ||||
| # To set elements: | ||||
| # * #[]=(i, v) | ||||
| # | ||||
| # To enumerate the elements: | ||||
| # * #each2(v) | ||||
| # * #collect2(v) | ||||
|  | @ -1678,8 +1827,10 @@ end | |||
| # * #inner_product(v), dot(v) | ||||
| # * #cross_product(v), cross(v) | ||||
| # * #collect | ||||
| # * #collect! | ||||
| # * #magnitude | ||||
| # * #map | ||||
| # * #map! | ||||
| # * #map2(v) | ||||
| # * #norm | ||||
| # * #normalize | ||||
|  | @ -1758,7 +1909,11 @@ class Vector | |||
|   # ACCESSING | ||||
| 
 | ||||
|   # | ||||
|   # Returns element number +i+ (starting at zero) of the vector. | ||||
|   # :call-seq: | ||||
|   #   vector[range] | ||||
|   #   vector[integer] | ||||
|   # | ||||
|   # Returns element or elements of the vector. | ||||
|   # | ||||
|   def [](i) | ||||
|     @elements[i] | ||||
|  | @ -1766,12 +1921,44 @@ class Vector | |||
|   alias element [] | ||||
|   alias component [] | ||||
| 
 | ||||
|   # | ||||
|   # :call-seq: | ||||
|   #   vector[range] = new_vector | ||||
|   #   vector[range] = row_matrix | ||||
|   #   vector[range] = new_element | ||||
|   #   vector[integer] = new_element | ||||
|   # | ||||
|   # Set element or elements of vector. | ||||
|   # | ||||
|   def []=(i, v) | ||||
|     @elements[i]= v | ||||
|     raise FrozenError, "can't modify frozen Vector" if frozen? | ||||
|     if i.is_a?(Range) | ||||
|       range = Matrix::CoercionHelper.check_range(i, size, :vector) | ||||
|       set_range(range, v) | ||||
|     else | ||||
|       index = Matrix::CoercionHelper.check_int(i, size, :index) | ||||
|       set_value(index, v) | ||||
|     end | ||||
|   end | ||||
|   alias set_element []= | ||||
|   alias set_component []= | ||||
|   private :[]=, :set_element, :set_component | ||||
|   private :set_element, :set_component | ||||
| 
 | ||||
|   private def set_value(index, value) | ||||
|     @elements[index] = value | ||||
|   end | ||||
| 
 | ||||
|   private def set_range(range, value) | ||||
|     if value.is_a?(Vector) | ||||
|       raise ArgumentError, "vector to be set has wrong size" unless range.size == value.size | ||||
|       @elements[range] = value.elements | ||||
|     elsif value.is_a?(Matrix) | ||||
|       Matrix.Raise ErrDimensionMismatch unless value.row_count == 1 | ||||
|       @elements[range] = value.row(0).elements | ||||
|     else | ||||
|       @elements[range] = Array.new(range.size, value) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   # Returns a vector with entries rounded to the given precision | ||||
|   # (see Float#round) | ||||
|  | @ -1868,6 +2055,20 @@ class Vector | |||
|     all?(&:zero?) | ||||
|   end | ||||
| 
 | ||||
|   def freeze | ||||
|     @elements.freeze | ||||
|     super | ||||
|   end | ||||
| 
 | ||||
|   # | ||||
|   # Called for dup & clone. | ||||
|   # | ||||
|   private def initialize_copy(v) | ||||
|     super | ||||
|     @elements = @elements.dup unless frozen? | ||||
|   end | ||||
| 
 | ||||
| 
 | ||||
|   #-- | ||||
|   # COMPARING -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- | ||||
|   #++ | ||||
|  | @ -1885,13 +2086,6 @@ class Vector | |||
|     @elements.eql? other.elements | ||||
|   end | ||||
| 
 | ||||
|   # | ||||
|   # Returns a copy of the vector. | ||||
|   # | ||||
|   def clone | ||||
|     self.class.elements(@elements) | ||||
|   end | ||||
| 
 | ||||
|   # | ||||
|   # Returns a hash-code for the vector. | ||||
|   # | ||||
|  | @ -2042,6 +2236,17 @@ class Vector | |||
|   end | ||||
|   alias_method :map, :collect | ||||
| 
 | ||||
|   # | ||||
|   # Like Array#collect! | ||||
|   # | ||||
|   def collect!(&block) | ||||
|     return to_enum(:collect!) unless block_given? | ||||
|     raise FrozenError, "can't modify frozen Vector" if frozen? | ||||
|     @elements.collect!(&block) | ||||
|     self | ||||
|   end | ||||
|   alias map! collect! | ||||
| 
 | ||||
|   # | ||||
|   # Returns the modulus (Pythagorean distance) of the vector. | ||||
|   #   Vector[5,8,2].r => 9.643650761 | ||||
|  |  | |||
|  | @ -283,7 +283,18 @@ class TestMatrix < Test::Unit::TestCase | |||
|   end | ||||
| 
 | ||||
|   def test_collect | ||||
|     assert_equal(Matrix[[1, 4, 9], [16, 25, 36]], @m1.collect {|x| x ** 2 }) | ||||
|     m1 = Matrix.zero(2,2) | ||||
|     m2 = Matrix.build(3,4){|row, col| 1} | ||||
| 
 | ||||
|     assert_equal(Matrix[[5, 5, 5, 5], [5, 5, 5, 5], [5, 5, 5, 5]], m2.collect{|e| e * 5}) | ||||
|     assert_equal(Matrix[[7, 0],[0, 7]], m1.collect(:diagonal){|e| e + 7}) | ||||
|     assert_equal(Matrix[[0, 5],[5, 0]], m1.collect(:off_diagonal){|e| e + 5}) | ||||
|     assert_equal(Matrix[[8, 1, 1, 1], [8, 8, 1, 1], [8, 8, 8, 1]], m2.collect(:lower){|e| e + 7}) | ||||
|     assert_equal(Matrix[[1, 1, 1, 1], [-11, 1, 1, 1], [-11, -11, 1, 1]], m2.collect(:strict_lower){|e| e - 12}) | ||||
|     assert_equal(Matrix[[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], m2.collect(:strict_upper){|e| e ** 2}) | ||||
|     assert_equal(Matrix[[-1, -1, -1, -1], [1, -1, -1, -1], [1, 1, -1, -1]], m2.collect(:upper){|e| -e}) | ||||
|     assert_raise(ArgumentError) {m1.collect(:test){|e| e + 7}} | ||||
|     assert_not_equal(m2, m2.collect {|e| e * 2 }) | ||||
|   end | ||||
| 
 | ||||
|   def test_minor | ||||
|  | @ -623,6 +634,134 @@ class TestMatrix < Test::Unit::TestCase | |||
|     assert_equal Matrix.empty(0,3), Matrix.combine(Matrix.empty(0,3), Matrix.empty(0,3)) { raise } | ||||
|   end | ||||
| 
 | ||||
|   def test_set_element | ||||
|     src = Matrix[ | ||||
|       [1, 2, 3, 4], | ||||
|       [5, 6, 7, 8], | ||||
|       [9, 10, 11, 12], | ||||
|     ] | ||||
|     rows = { | ||||
|       range:   [1..2, 1...3, 1..-1, -2..2, 1.., 1..., -2.., -2...], | ||||
|       int:     [2, -1], | ||||
|       invalid: [-4, 4, -4..2, 2..-4, 0...0, 2..0, -4..], | ||||
|     } | ||||
|     columns = { | ||||
|       range:   [2..3, 2...4, 2..-1, -2..3, 2.., 2..., -2..., -2..], | ||||
|       int:     [3, -1], | ||||
|       invalid: [-5, 5, -5..2, 2..-5, 0...0, -5..], | ||||
|     } | ||||
|     values = { | ||||
|       element: 42, | ||||
|       matrix:  Matrix[[20, 21], [22, 23]], | ||||
|       vector:  Vector[30, 31], | ||||
|       row:     Matrix[[60, 61]], | ||||
|       column:  Matrix[[50], [51]], | ||||
|       mismatched_matrix: Matrix.identity(3), | ||||
|       mismatched_vector: Vector[0, 1, 2, 3], | ||||
|     } | ||||
|     solutions = { | ||||
|       [:int, :int] => { | ||||
|         element: Matrix[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 42]], | ||||
|       }, | ||||
|       [:range , :int] => { | ||||
|         element: Matrix[[1, 2, 3, 4], [5, 6, 7, 42], [9, 10, 11, 42]], | ||||
|         column:  Matrix[[1, 2, 3, 4], [5, 6, 7, 50], [9, 10, 11, 51]], | ||||
|         vector:  Matrix[[1, 2, 3, 4], [5, 6, 7, 30], [9, 10, 11, 31]], | ||||
|       }, | ||||
|       [:int, :range] => { | ||||
|         element: Matrix[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 42, 42]], | ||||
|         row:     Matrix[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 60, 61]], | ||||
|         vector:  Matrix[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 30, 31]], | ||||
|       }, | ||||
|       [:range , :range] => { | ||||
|         element: Matrix[[1, 2, 3, 4], [5, 6, 42, 42], [9, 10, 42, 42]], | ||||
|         matrix:  Matrix[[1, 2, 3, 4], [5, 6, 20, 21], [9, 10, 22, 23]], | ||||
|       }, | ||||
|     } | ||||
|     solutions.default = Hash.new(IndexError) | ||||
| 
 | ||||
|     rows.each do |row_style, row_arguments| | ||||
|       row_arguments.each do |row_argument| | ||||
|         columns.each do |column_style, column_arguments| | ||||
|           column_arguments.each do |column_argument| | ||||
|             values.each do |value_type, value| | ||||
|               expected = solutions[[row_style, column_style]][value_type] || Matrix::ErrDimensionMismatch | ||||
| 
 | ||||
|               result = src.clone | ||||
|               begin | ||||
|                 result[row_argument, column_argument] = value | ||||
|                 assert_equal expected, result, | ||||
|                   "m[#{row_argument.inspect}][#{column_argument.inspect}] = #{value.inspect} failed" | ||||
|               rescue Exception => e | ||||
|                 raise if e.class != expected | ||||
|               end | ||||
|             end | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def test_map! | ||||
|     m1 = Matrix.zero(2,2) | ||||
|     m2 = Matrix.build(3,4){|row, col| 1} | ||||
|     m3 = Matrix.zero(3,5).freeze | ||||
|     m4 = Matrix.empty.freeze | ||||
| 
 | ||||
|     assert_equal Matrix[[5, 5, 5, 5], [5, 5, 5, 5], [5, 5, 5, 5]], m2.map!{|e| e * 5} | ||||
|     assert_equal Matrix[[7, 0],[0, 7]], m1.map!(:diagonal){|e| e + 7} | ||||
|     assert_equal Matrix[[7, 5],[5, 7]], m1.map!(:off_diagonal){|e| e + 5} | ||||
|     assert_equal Matrix[[12, 5, 5, 5], [12, 12, 5, 5], [12, 12, 12, 5]], m2.map!(:lower){|e| e + 7} | ||||
|     assert_equal Matrix[[12, 5, 5, 5], [0, 12, 5, 5], [0, 0, 12, 5]], m2.map!(:strict_lower){|e| e - 12} | ||||
|     assert_equal Matrix[[12, 25, 25, 25], [0, 12, 25, 25], [0, 0, 12, 25]], m2.map!(:strict_upper){|e| e ** 2} | ||||
|     assert_equal Matrix[[-12, -25, -25, -25], [0, -12, -25, -25], [0, 0, -12, -25]], m2.map!(:upper){|e| -e} | ||||
|     assert_equal m1, m1.map!{|e| e ** 2 } | ||||
|     assert_equal m2, m2.map!(:lower){ |e| e - 3 } | ||||
|     assert_raise(ArgumentError) {m1.map!(:test){|e| e + 7}} | ||||
|     assert_raise(FrozenError) { m3.map!{|e| e * 2} } | ||||
|     assert_raise(FrozenError) { m4.map!{} } | ||||
|   end | ||||
| 
 | ||||
|   def test_freeze | ||||
|     m = Matrix[[1, 2, 3],[4, 5, 6]] | ||||
|     f = m.freeze | ||||
|     assert_equal true, f.frozen? | ||||
|     assert m.equal?(f) | ||||
|     assert m.equal?(f.freeze) | ||||
|     assert_raise(FrozenError){ m[0, 1] = 56 } | ||||
|     assert_equal m.dup, m | ||||
|   end | ||||
| 
 | ||||
|   def test_clone | ||||
|     a = Matrix[[4]] | ||||
|     def a.foo | ||||
|       42 | ||||
|     end | ||||
| 
 | ||||
|     m = a.clone | ||||
|     m[0, 0] = 2 | ||||
|     assert_equal a, m * 2 | ||||
|     assert_equal 42, m.foo | ||||
| 
 | ||||
|     a.freeze | ||||
|     m = a.clone | ||||
|     assert m.frozen? | ||||
|     assert_equal 42, m.foo | ||||
|   end | ||||
| 
 | ||||
|   def test_dup | ||||
|     a = Matrix[[4]] | ||||
|     def a.foo | ||||
|       42 | ||||
|     end | ||||
|     a.freeze | ||||
| 
 | ||||
|     m = a.dup | ||||
|     m[0, 0] = 2 | ||||
|     assert_equal a, m * 2 | ||||
|     assert !m.respond_to?(:foo) | ||||
|   end | ||||
| 
 | ||||
|   def test_eigenvalues_and_eigenvectors_symmetric | ||||
|     m = Matrix[ | ||||
|       [8, 1], | ||||
|  |  | |||
|  | @ -27,6 +27,108 @@ class TestVector < Test::Unit::TestCase | |||
|     assert_raise(ArgumentError) { Vector.basis(index: 3) } | ||||
|   end | ||||
| 
 | ||||
|   def test_get_element | ||||
|     assert_equal(@v1[0..], [1, 2, 3]) | ||||
|     assert_equal(@v1[0..1], [1, 2]) | ||||
|     assert_equal(@v1[2], 3) | ||||
|     assert_equal(@v1[4], nil) | ||||
|   end | ||||
| 
 | ||||
|   def test_set_element | ||||
| 
 | ||||
|     assert_block do | ||||
|       v = Vector[5, 6, 7, 8, 9] | ||||
|       v[1..2] = Vector[1, 2] | ||||
|       v == Vector[5, 1, 2, 8, 9] | ||||
|     end | ||||
| 
 | ||||
|     assert_block do | ||||
|       v = Vector[6, 7, 8] | ||||
|       v[1..2] = Matrix[[1, 3]] | ||||
|       v == Vector[6, 1, 3] | ||||
|     end | ||||
| 
 | ||||
|     assert_block do | ||||
|       v = Vector[1, 2, 3, 4, 5, 6] | ||||
|       v[0..2] = 8 | ||||
|       v == Vector[8, 8, 8, 4, 5, 6] | ||||
|     end | ||||
| 
 | ||||
|     assert_block do | ||||
|       v = Vector[1, 3, 4, 5] | ||||
|       v[2] = 5 | ||||
|       v == Vector[1, 3, 5, 5] | ||||
|     end | ||||
| 
 | ||||
|     assert_block do | ||||
|       v = Vector[2, 3, 5] | ||||
|       v[-2] = 13 | ||||
|       v == Vector[2, 13, 5] | ||||
|     end | ||||
| 
 | ||||
|     assert_block do | ||||
|       v = Vector[4, 8, 9, 11, 30] | ||||
|       v[1..-2] = Vector[1, 2, 3] | ||||
|       v == Vector[4, 1, 2, 3, 30] | ||||
|     end | ||||
| 
 | ||||
|     assert_raise(IndexError) {Vector[1, 3, 4, 5][5..6] = 17} | ||||
|     assert_raise(IndexError) {Vector[1, 3, 4, 5][6] = 17} | ||||
|     assert_raise(Matrix::ErrDimensionMismatch) {Vector[1, 3, 4, 5][0..2] = Matrix[[1], [2], [3]]} | ||||
|     assert_raise(ArgumentError) {Vector[1, 2, 3, 4, 5, 6][0..2] = Vector[1, 2, 3, 4, 5, 6]} | ||||
|     assert_raise(FrozenError) { Vector[7, 8, 9].freeze[0..1] = 5} | ||||
|   end | ||||
| 
 | ||||
|   def test_map! | ||||
|     v1 = Vector[1, 2, 3] | ||||
|     v2 = Vector[1, 3, 5].freeze | ||||
|     v3 = Vector[].freeze | ||||
|     assert_equal Vector[1, 4, 9], v1.map!{|e| e ** 2} | ||||
|     assert_equal v1, v1.map!{|e| e - 8} | ||||
|     assert_raise(FrozenError) { v2.map!{|e| e + 2 }} | ||||
|     assert_raise(FrozenError){ v3.map!{} } | ||||
|   end | ||||
| 
 | ||||
|   def test_freeze | ||||
|     v = Vector[1,2,3] | ||||
|     f = v.freeze | ||||
|     assert_equal true, f.frozen? | ||||
|     assert v.equal?(f) | ||||
|     assert v.equal?(f.freeze) | ||||
|     assert_raise(FrozenError){ v[1] = 56 } | ||||
|     assert_equal v.dup, v | ||||
|   end | ||||
| 
 | ||||
|   def test_clone | ||||
|     a = Vector[4] | ||||
|     def a.foo | ||||
|       42 | ||||
|     end | ||||
| 
 | ||||
|     v = a.clone | ||||
|     v[0] = 2 | ||||
|     assert_equal a, v * 2 | ||||
|     assert_equal 42, v.foo | ||||
| 
 | ||||
|     a.freeze | ||||
|     v = a.clone | ||||
|     assert v.frozen? | ||||
|     assert_equal 42, v.foo | ||||
|   end | ||||
| 
 | ||||
|   def test_dup | ||||
|     a = Vector[4] | ||||
|     def a.foo | ||||
|       42 | ||||
|     end | ||||
|     a.freeze | ||||
| 
 | ||||
|     v = a.dup | ||||
|     v[0] = 2 | ||||
|     assert_equal a, v * 2 | ||||
|     assert !v.respond_to?(:foo) | ||||
|   end | ||||
| 
 | ||||
|   def test_identity | ||||
|     assert_same @v1, @v1 | ||||
|     assert_not_same @v1, @v2 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 marcandre
						marcandre