diff options
Diffstat (limited to 'spec/ruby/library/matrix')
109 files changed, 2787 insertions, 0 deletions
diff --git a/spec/ruby/library/matrix/I_spec.rb b/spec/ruby/library/matrix/I_spec.rb new file mode 100644 index 0000000000..6eeffe8e98 --- /dev/null +++ b/spec/ruby/library/matrix/I_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/identity' + +describe "Matrix.I" do + it_behaves_like :matrix_identity, :I +end diff --git a/spec/ruby/library/matrix/antisymmetric_spec.rb b/spec/ruby/library/matrix/antisymmetric_spec.rb new file mode 100644 index 0000000000..200df703cb --- /dev/null +++ b/spec/ruby/library/matrix/antisymmetric_spec.rb @@ -0,0 +1,36 @@ +require_relative '../../spec_helper' + +require 'matrix' + +describe "Matrix#antisymmetric?" do + it "returns true for an antisymmetric Matrix" do + Matrix[[0, -2, Complex(1, 3)], [2, 0, 5], [-Complex(1, 3), -5, 0]].antisymmetric?.should be_true + end + + it "returns true for a 0x0 empty matrix" do + Matrix.empty.antisymmetric?.should be_true + end + + it "returns false for non-antisymmetric matrices" do + [ + Matrix[[1, 2, 3], [4, 5, 6], [7, 8, 9]], + Matrix[[1, -2, 3], [2, 0, 6], [-3, -6, 0]], # wrong diagonal element + Matrix[[0, 2, -3], [2, 0, 6], [-3, 6, 0]] # only signs wrong + ].each do |matrix| + matrix.antisymmetric?.should be_false + end + end + + it "raises an error for rectangular matrices" do + [ + Matrix[[0], [0]], + Matrix[[0, 0]], + Matrix.empty(0, 2), + Matrix.empty(2, 0), + ].each do |rectangular_matrix| + -> { + rectangular_matrix.antisymmetric? + }.should raise_error(Matrix::ErrDimensionMismatch) + end + end +end diff --git a/spec/ruby/library/matrix/build_spec.rb b/spec/ruby/library/matrix/build_spec.rb new file mode 100644 index 0000000000..6d8017a3df --- /dev/null +++ b/spec/ruby/library/matrix/build_spec.rb @@ -0,0 +1,73 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix.build" do + + it "returns a Matrix object of the given size" do + m = Matrix.build(3, 4){1} + m.should be_an_instance_of(Matrix) + m.row_size.should == 3 + m.column_size.should == 4 + end + + it "builds the Matrix using the given block" do + Matrix.build(2, 3){|col, row| 10*col - row}.should == + Matrix[[0, -1, -2], [10, 9, 8]] + end + + it "iterates through the first row, then the second, ..." do + acc = [] + Matrix.build(2, 3){|*args| acc << args} + acc.should == [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]] + end + + it "returns an Enumerator is no block is given" do + enum = Matrix.build(2, 1) + enum.should be_an_instance_of(Enumerator) + enum.each{1}.should == Matrix[[1], [1]] + end + + it "requires integers as parameters" do + -> { Matrix.build("1", "2"){1} }.should raise_error(TypeError) + -> { Matrix.build(nil, nil){1} }.should raise_error(TypeError) + -> { Matrix.build(1..2){1} }.should raise_error(TypeError) + end + + it "requires non-negative integers" do + -> { Matrix.build(-1, 1){1} }.should raise_error(ArgumentError) + -> { Matrix.build(+1,-1){1} }.should raise_error(ArgumentError) + end + + it "returns empty Matrix if one argument is zero" do + m = Matrix.build(0, 3){ + raise "Should not yield" + } + m.should be_empty + m.column_size.should == 3 + + m = Matrix.build(3, 0){ + raise "Should not yield" + } + m.should be_empty + m.row_size.should == 3 + end + + it "tries to calls :to_int on arguments" do + int = mock('int') + int.should_receive(:to_int).twice.and_return(2) + Matrix.build(int, int){ 1 }.should == Matrix[ [1,1], [1,1] ] + end + + it "builds an nxn Matrix when given only one argument" do + m = Matrix.build(3){1} + m.row_size.should == 3 + m.column_size.should == 3 + end +end + +describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.build(3){1}.should be_an_instance_of(MatrixSub) + end +end diff --git a/spec/ruby/library/matrix/clone_spec.rb b/spec/ruby/library/matrix/clone_spec.rb new file mode 100644 index 0000000000..74e5bf157e --- /dev/null +++ b/spec/ruby/library/matrix/clone_spec.rb @@ -0,0 +1,25 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix#clone" do + before :each do + @a = Matrix[[1, 2], [3, 4], [5, 6]] + end + + it "returns a shallow copy of the matrix" do + b = @a.clone + @a.should_not equal(b) + b.should be_kind_of(Matrix) + b.should == @a + 0.upto(@a.row_size - 1) do |i| + @a.row(i).should_not equal(b.row(i)) + end + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.ins.clone.should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/coerce_spec.rb b/spec/ruby/library/matrix/coerce_spec.rb new file mode 100644 index 0000000000..4022f00236 --- /dev/null +++ b/spec/ruby/library/matrix/coerce_spec.rb @@ -0,0 +1,8 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#coerce" do + it "allows the division of integer by a Matrix " do + (1/Matrix[[0,1],[-1,0]]).should == Matrix[[0,-1],[1,0]] + end +end diff --git a/spec/ruby/library/matrix/collect_spec.rb b/spec/ruby/library/matrix/collect_spec.rb new file mode 100644 index 0000000000..bba640213b --- /dev/null +++ b/spec/ruby/library/matrix/collect_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/collect' + +describe "Matrix#collect" do + it_behaves_like :collect, :collect +end diff --git a/spec/ruby/library/matrix/column_size_spec.rb b/spec/ruby/library/matrix/column_size_spec.rb new file mode 100644 index 0000000000..041914e5b9 --- /dev/null +++ b/spec/ruby/library/matrix/column_size_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#column_size" do + it "returns the number of columns" do + Matrix[ [1,2], [3,4] ].column_size.should == 2 + end + + it "returns 0 for empty matrices" do + Matrix[ [], [] ].column_size.should == 0 + Matrix[ ].column_size.should == 0 + end +end diff --git a/spec/ruby/library/matrix/column_spec.rb b/spec/ruby/library/matrix/column_spec.rb new file mode 100644 index 0000000000..1f3c80964a --- /dev/null +++ b/spec/ruby/library/matrix/column_spec.rb @@ -0,0 +1,35 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#column" do + before :all do + @m = Matrix[[1,2,3], [2,3,4]] + end + + it "returns a Vector when called without a block" do + @m.column(1).should == Vector[2,3] + end + + it "yields each element in the column to the block" do + a = [] + @m.column(1) {|n| a << n } + a.should == [2,3] + end + + it "counts backwards for negative argument" do + @m.column(-1).should == Vector[3, 4] + end + + it "returns self when called with a block" do + @m.column(0) { |x| x }.should equal(@m) + end + + it "returns nil when out of bounds" do + @m.column(3).should == nil + end + + it "never yields when out of bounds" do + -> { @m.column(3){ raise } }.should_not raise_error + -> { @m.column(-4){ raise } }.should_not raise_error + end +end diff --git a/spec/ruby/library/matrix/column_vector_spec.rb b/spec/ruby/library/matrix/column_vector_spec.rb new file mode 100644 index 0000000000..47e866a8d5 --- /dev/null +++ b/spec/ruby/library/matrix/column_vector_spec.rb @@ -0,0 +1,25 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix.column_vector" do + + it "returns a single column Matrix when called with an Array" do + m = Matrix.column_vector([4,5,6]) + m.should be_an_instance_of(Matrix) + m.should == Matrix[ [4],[5],[6] ] + end + + it "returns an empty Matrix when called with an empty Array" do + m = Matrix.column_vector([]) + m.should be_an_instance_of(Matrix) + m.row_size.should == 0 + m.column_size.should == 1 + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.column_vector([4,5,6]).should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/column_vectors_spec.rb b/spec/ruby/library/matrix/column_vectors_spec.rb new file mode 100644 index 0000000000..b0cb6f914c --- /dev/null +++ b/spec/ruby/library/matrix/column_vectors_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#column_vectors" do + + before :each do + @vectors = Matrix[ [1,2], [3,4] ].column_vectors + end + + it "returns an Array" do + Matrix[ [1,2], [3,4] ].column_vectors.should be_an_instance_of(Array) + end + + it "returns an Array of Vectors" do + @vectors.all? {|v| v.should be_an_instance_of(Vector)} + end + + it "returns each column as a Vector" do + @vectors.should == [Vector[1,3], Vector[2,4]] + end + + it "returns an empty Array for empty matrices" do + Matrix[ [] ].column_vectors.should == [] + end + +end diff --git a/spec/ruby/library/matrix/columns_spec.rb b/spec/ruby/library/matrix/columns_spec.rb new file mode 100644 index 0000000000..3095fdd7af --- /dev/null +++ b/spec/ruby/library/matrix/columns_spec.rb @@ -0,0 +1,42 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix.columns" do + before :each do + @a = [1, 2] + @b = [3, 4] + @m = Matrix.columns([@a, @b]) + end + + it "creates a Matrix from argument columns" do + @m.should be_an_instance_of(Matrix) + @m.column(0).to_a.should == @a + @m.column(1).to_a.should == @b + end + + it "accepts Vectors as argument columns" do + m = Matrix.columns([Vector[*@a], Vector[*@b]]) + m.should == @m + m.column(0).to_a.should == @a + m.column(1).to_a.should == @b + end + + it "handles empty matrices" do + e = Matrix.columns([]) + e.row_size.should == 0 + e.column_size.should == 0 + e.should == Matrix[] + + v = Matrix.columns([[],[],[]]) + v.row_size.should == 0 + v.column_size.should == 3 + v.should == Matrix[[], [], []].transpose + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.columns([[1]]).should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/conj_spec.rb b/spec/ruby/library/matrix/conj_spec.rb new file mode 100644 index 0000000000..ecee95c255 --- /dev/null +++ b/spec/ruby/library/matrix/conj_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/conjugate' + +describe "Matrix#conj" do + it_behaves_like :matrix_conjugate, :conj +end diff --git a/spec/ruby/library/matrix/conjugate_spec.rb b/spec/ruby/library/matrix/conjugate_spec.rb new file mode 100644 index 0000000000..682bd41d94 --- /dev/null +++ b/spec/ruby/library/matrix/conjugate_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/conjugate' + +describe "Matrix#conjugate" do + it_behaves_like :matrix_conjugate, :conjugate +end diff --git a/spec/ruby/library/matrix/constructor_spec.rb b/spec/ruby/library/matrix/constructor_spec.rb new file mode 100644 index 0000000000..70d77babbb --- /dev/null +++ b/spec/ruby/library/matrix/constructor_spec.rb @@ -0,0 +1,65 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix.[]" do + + it "requires arrays as parameters" do + -> { Matrix[5] }.should raise_error(TypeError) + -> { Matrix[nil] }.should raise_error(TypeError) + -> { Matrix[1..2] }.should raise_error(TypeError) + -> { Matrix[[1, 2], 3] }.should raise_error(TypeError) + end + + it "creates an empty Matrix with no arguments" do + m = Matrix[] + m.column_size.should == 0 + m.row_size.should == 0 + end + + it "raises for non-rectangular matrices" do + ->{ Matrix[ [0], [0,1] ] }.should \ + raise_error(Matrix::ErrDimensionMismatch) + ->{ Matrix[ [0,1], [0,1,2], [0,1] ]}.should \ + raise_error(Matrix::ErrDimensionMismatch) + end + + it "accepts vector arguments" do + a = Matrix[Vector[1, 2], Vector[3, 4]] + a.should be_an_instance_of(Matrix) + a.should == Matrix[ [1, 2], [3, 4] ] + end + + it "tries to calls :to_ary on arguments" do + array = mock('ary') + array.should_receive(:to_ary).and_return([1,2]) + Matrix[array, [3,4] ].should == Matrix[ [1,2], [3,4] ] + end + + + it "returns a Matrix object" do + Matrix[ [1] ].should be_an_instance_of(Matrix) + end + + it "can create an nxn Matrix" do + m = Matrix[ [20,30], [40.5, 9] ] + m.row_size.should == 2 + m.column_size.should == 2 + m.column(0).should == Vector[20, 40.5] + m.column(1).should == Vector[30, 9] + m.row(0).should == Vector[20, 30] + m.row(1).should == Vector[40.5, 9] + end + + it "can create a 0xn Matrix" do + m = Matrix[ [], [], [] ] + m.row_size.should == 3 + m.column_size.should == 0 + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub[ [20,30], [40.5, 9] ].should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/det_spec.rb b/spec/ruby/library/matrix/det_spec.rb new file mode 100644 index 0000000000..aa7086cacf --- /dev/null +++ b/spec/ruby/library/matrix/det_spec.rb @@ -0,0 +1,7 @@ +require_relative '../../spec_helper' +require_relative 'shared/determinant' +require 'matrix' + +describe "Matrix#det" do + it_behaves_like :determinant, :det +end diff --git a/spec/ruby/library/matrix/determinant_spec.rb b/spec/ruby/library/matrix/determinant_spec.rb new file mode 100644 index 0000000000..825c9907b1 --- /dev/null +++ b/spec/ruby/library/matrix/determinant_spec.rb @@ -0,0 +1,7 @@ +require_relative '../../spec_helper' +require_relative 'shared/determinant' +require 'matrix' + +describe "Matrix#determinant" do + it_behaves_like :determinant, :determinant +end diff --git a/spec/ruby/library/matrix/diagonal_spec.rb b/spec/ruby/library/matrix/diagonal_spec.rb new file mode 100644 index 0000000000..ef9738e73e --- /dev/null +++ b/spec/ruby/library/matrix/diagonal_spec.rb @@ -0,0 +1,72 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix.diagonal" do + before :each do + @m = Matrix.diagonal(10, 11, 12, 13, 14) + end + + it "returns an object of type Matrix" do + @m.should be_kind_of(Matrix) + end + + it "returns a square Matrix of the right size" do + @m.column_size.should == 5 + @m.row_size.should == 5 + end + + it "sets the diagonal to the arguments" do + (0..4).each do |i| + @m[i, i].should == i + 10 + end + end + + it "fills all non-diagonal cells with 0" do + (0..4).each do |i| + (0..4).each do |j| + if i != j + @m[i, j].should == 0 + end + end + end + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.diagonal(1).should be_an_instance_of(MatrixSub) + end + end +end + +describe "Matrix.diagonal?" do + it "returns true for a diagonal Matrix" do + Matrix.diagonal([1, 2, 3]).diagonal?.should be_true + end + + it "returns true for a zero square Matrix" do + Matrix.zero(3).diagonal?.should be_true + end + + it "returns false for a non diagonal square Matrix" do + Matrix[[0, 1], [0, 0]].diagonal?.should be_false + Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].diagonal?.should be_false + end + + it "returns true for an empty 0x0 matrix" do + Matrix.empty(0,0).diagonal?.should be_true + end + + it "raises an error for rectangular matrices" do + [ + Matrix[[0], [0]], + Matrix[[0, 0]], + Matrix.empty(0, 2), + Matrix.empty(2, 0), + ].each do |rectangular_matrix| + -> { + rectangular_matrix.diagonal? + }.should raise_error(Matrix::ErrDimensionMismatch) + end + end +end diff --git a/spec/ruby/library/matrix/divide_spec.rb b/spec/ruby/library/matrix/divide_spec.rb new file mode 100644 index 0000000000..2e3bb85bf6 --- /dev/null +++ b/spec/ruby/library/matrix/divide_spec.rb @@ -0,0 +1,54 @@ +require_relative '../../spec_helper' +require_relative 'spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix#/" do + before :each do + @a = Matrix[ [1, 2], [3, 4] ] + @b = Matrix[ [4, 5], [6, 7] ] + @c = Matrix[ [1.2, 2.4], [3.6, 4.8] ] + end + + it "returns the result of dividing self by another Matrix" do + (@a / @b).should be_close_to_matrix([[2.5, -1.5], [1.5, -0.5]]) + end + + # Guard against the Mathn library + guard -> { !defined?(Math.rsqrt) } do + it "returns the result of dividing self by a Fixnum" do + (@a / 2).should == Matrix[ [0, 1], [1, 2] ] + end + + it "returns the result of dividing self by a Bignum" do + (@a / bignum_value).should == Matrix[ [0, 0], [0, 0] ] + end + end + + it "returns the result of dividing self by a Float" do + (@c / 1.2).should == Matrix[ [1, 2], [3, 4] ] + end + + it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do + -> { @a / Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch) + end + + it "returns an instance of Matrix" do + (@a / @b).should be_kind_of(Matrix) + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + m = MatrixSub.ins + (m/m).should be_an_instance_of(MatrixSub) + (m/1).should be_an_instance_of(MatrixSub) + end + end + + it "raises a TypeError if other is of wrong type" do + -> { @a / nil }.should raise_error(TypeError) + -> { @a / "a" }.should raise_error(TypeError) + -> { @a / [ [1, 2] ] }.should raise_error(TypeError) + -> { @a / Object.new }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/matrix/each_spec.rb b/spec/ruby/library/matrix/each_spec.rb new file mode 100644 index 0000000000..f3b0f01867 --- /dev/null +++ b/spec/ruby/library/matrix/each_spec.rb @@ -0,0 +1,74 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#each" do + before :all do + @m = Matrix[ [1, 2, 3], [4, 5, 6] ] + @result = (1..6).to_a + end + + it "returns an Enumerator when called without a block" do + enum = @m.each + enum.should be_an_instance_of(Enumerator) + enum.to_a.should == @result + end + + it "returns self" do + @m.each{}.should equal(@m) + end + + it "yields the elements starting with the those of the first row" do + a = [] + @m.each {|x| a << x} + a.should == @result + end +end + +describe "Matrix#each with an argument" do + before :all do + @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ] + @t = Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ] + end + + it "raises an ArgumentError for unrecognized argument" do + -> { + @m.each("all"){} + }.should raise_error(ArgumentError) + -> { + @m.each(nil){} + }.should raise_error(ArgumentError) + -> { + @m.each(:left){} + }.should raise_error(ArgumentError) + end + + it "yields the rights elements when passed :diagonal" do + @m.each(:diagonal).to_a.should == [1, 6] + @t.each(:diagonal).to_a.should == [1, 4] + end + + it "yields the rights elements when passed :off_diagonal" do + @m.each(:off_diagonal).to_a.should == [2, 3, 4, 5, 7, 8] + @t.each(:off_diagonal).to_a.should == [2, 3, 5, 6, 7, 8] + end + + it "yields the rights elements when passed :lower" do + @m.each(:lower).to_a.should == [1, 5, 6] + @t.each(:lower).to_a.should == [1, 3, 4, 5, 6, 7, 8] + end + + it "yields the rights elements when passed :strict_lower" do + @m.each(:strict_lower).to_a.should == [5] + @t.each(:strict_lower).to_a.should == [3, 5, 6, 7, 8] + end + + it "yields the rights elements when passed :strict_upper" do + @m.each(:strict_upper).to_a.should == [2, 3, 4, 7, 8] + @t.each(:strict_upper).to_a.should == [2] + end + + it "yields the rights elements when passed :upper" do + @m.each(:upper).to_a.should == [1, 2, 3, 4, 6, 7, 8] + @t.each(:upper).to_a.should == [1, 2, 4] + end +end diff --git a/spec/ruby/library/matrix/each_with_index_spec.rb b/spec/ruby/library/matrix/each_with_index_spec.rb new file mode 100644 index 0000000000..a005b88621 --- /dev/null +++ b/spec/ruby/library/matrix/each_with_index_spec.rb @@ -0,0 +1,81 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#each_with_index" do + before :all do + @m = Matrix[ [1, 2, 3], [4, 5, 6] ] + @result = [ + [1, 0, 0], + [2, 0, 1], + [3, 0, 2], + [4, 1, 0], + [5, 1, 1], + [6, 1, 2] + ] + end + + it "returns an Enumerator when called without a block" do + enum = @m.each_with_index + enum.should be_an_instance_of(Enumerator) + enum.to_a.should == @result + end + + it "returns self" do + @m.each_with_index{}.should equal(@m) + end + + it "yields the elements starting with the those of the first row" do + a = [] + @m.each_with_index {|x, r, c| a << [x, r, c]} + a.should == @result + end +end + +describe "Matrix#each_with_index with an argument" do + before :all do + @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ] + @t = Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ] + end + + it "raises an ArgumentError for unrecognized argument" do + -> { + @m.each_with_index("all"){} + }.should raise_error(ArgumentError) + -> { + @m.each_with_index(nil){} + }.should raise_error(ArgumentError) + -> { + @m.each_with_index(:left){} + }.should raise_error(ArgumentError) + end + + it "yields the rights elements when passed :diagonal" do + @m.each_with_index(:diagonal).to_a.should == [[1, 0, 0], [6, 1, 1]] + @t.each_with_index(:diagonal).to_a.should == [[1, 0, 0], [4, 1, 1]] + end + + it "yields the rights elements when passed :off_diagonal" do + @m.each_with_index(:off_diagonal).to_a.should == [[2, 0, 1], [3, 0, 2], [4, 0, 3], [5, 1, 0], [7, 1, 2], [8, 1, 3]] + @t.each_with_index(:off_diagonal).to_a.should == [[2, 0, 1], [3, 1, 0], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]] + end + + it "yields the rights elements when passed :lower" do + @m.each_with_index(:lower).to_a.should == [[1, 0, 0], [5, 1, 0], [6, 1, 1]] + @t.each_with_index(:lower).to_a.should == [[1, 0, 0], [3, 1, 0], [4, 1, 1], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]] + end + + it "yields the rights elements when passed :strict_lower" do + @m.each_with_index(:strict_lower).to_a.should == [[5, 1, 0]] + @t.each_with_index(:strict_lower).to_a.should == [[3, 1, 0], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]] + end + + it "yields the rights elements when passed :strict_upper" do + @m.each_with_index(:strict_upper).to_a.should == [[2, 0, 1], [3, 0, 2], [4, 0, 3], [7, 1, 2], [8, 1, 3]] + @t.each_with_index(:strict_upper).to_a.should == [[2, 0, 1]] + end + + it "yields the rights elements when passed :upper" do + @m.each_with_index(:upper).to_a.should == [[1, 0, 0], [2, 0, 1], [3, 0, 2], [4, 0, 3], [6, 1, 1], [7, 1, 2], [8, 1, 3]] + @t.each_with_index(:upper).to_a.should == [[1, 0, 0], [2, 0, 1], [4, 1, 1]] + end +end diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalue_matrix_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalue_matrix_spec.rb new file mode 100644 index 0000000000..67f9dd1c19 --- /dev/null +++ b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalue_matrix_spec.rb @@ -0,0 +1,9 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::EigenvalueDecomposition#eigenvalue_matrix" do + it "returns a diagonal matrix with the eigenvalues on the diagonal" do + Matrix[[14, 16], [-6, -6]].eigensystem.eigenvalue_matrix.should == Matrix[[6, 0],[0, 2]] + Matrix[[1, 1], [-1, 1]].eigensystem.eigenvalue_matrix.should == Matrix[[Complex(1,1), 0],[0, Complex(1,-1)]] + end +end diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalues_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalues_spec.rb new file mode 100644 index 0000000000..7552b7616c --- /dev/null +++ b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalues_spec.rb @@ -0,0 +1,22 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::EigenvalueDecomposition#eigenvalues" do + it "returns an array of complex eigenvalues for a rotation matrix" do + Matrix[[ 1, 1], + [-1, 1]].eigensystem.eigenvalues.sort_by{|v| v.imag}.should == + [ Complex(1, -1), Complex(1, 1)] + end + + it "returns an array of real eigenvalues for a symmetric matrix" do + Matrix[[1, 2], + [2, 1]].eigensystem.eigenvalues.sort.map!{|x| x.round(10)}.should == + [ -1, 3 ] + end + + it "returns an array of real eigenvalues for a matrix" do + Matrix[[14, 16], + [-6, -6]].eigensystem.eigenvalues.sort.map!{|x| x.round(10)}.should == + [ 2, 6 ] + end +end diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvector_matrix_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvector_matrix_spec.rb new file mode 100644 index 0000000000..09f229ee15 --- /dev/null +++ b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvector_matrix_spec.rb @@ -0,0 +1,20 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::EigenvalueDecomposition#eigenvector_matrix" do + it "returns a complex eigenvector matrix given a rotation matrix" do + # Fix me: should test for linearity, not for equality + Matrix[[ 1, 1], + [-1, 1]].eigensystem.eigenvector_matrix.should == + Matrix[[1, 1], + [Complex(0, 1), Complex(0, -1)]] + end + + it "returns an real eigenvector matrix for a symmetric matrix" do + # Fix me: should test for linearity, not for equality + Matrix[[1, 2], + [2, 1]].eigensystem.eigenvector_matrix.should == + Matrix[[0.7071067811865475, 0.7071067811865475], + [-0.7071067811865475, 0.7071067811865475]] + end +end diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvectors_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvectors_spec.rb new file mode 100644 index 0000000000..2b6ce74ea8 --- /dev/null +++ b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvectors_spec.rb @@ -0,0 +1,22 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::EigenvalueDecomposition#eigenvectors" do + it "returns an array of complex eigenvectors for a rotation matrix" do + # Fix me: should test for linearity, not for equality + Matrix[[ 1, 1], + [-1, 1]].eigensystem.eigenvectors.should == + [ Vector[1, Complex(0, 1)], + Vector[1, Complex(0, -1)] + ] + end + + it "returns an array of real eigenvectors for a symmetric matrix" do + # Fix me: should test for linearity, not for equality + Matrix[[1, 2], + [2, 1]].eigensystem.eigenvectors.should == + [ Vector[0.7071067811865475, -0.7071067811865475], + Vector[0.7071067811865475, 0.7071067811865475] + ] + end +end diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb new file mode 100644 index 0000000000..8438f63133 --- /dev/null +++ b/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb @@ -0,0 +1,24 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::EigenvalueDecomposition#initialize" do + it "raises an error if argument is not a matrix" do + -> { + Matrix::EigenvalueDecomposition.new([[]]) + }.should raise_error(TypeError) + -> { + Matrix::EigenvalueDecomposition.new(42) + }.should raise_error(TypeError) + end + + it "raises an error if matrix is not square" do + -> { + Matrix::EigenvalueDecomposition.new(Matrix[[1, 2]]) + }.should raise_error(Matrix::ErrDimensionMismatch) + end + + it "never hangs" do + m = Matrix[ [0,0,0,0,0], [0,0,0,0,1], [0,0,0,1,0], [1,1,0,0,1], [1,0,1,0,1] ] + Matrix::EigenvalueDecomposition.new(m).should_not == "infinite loop" + end +end diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/to_a_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/to_a_spec.rb new file mode 100644 index 0000000000..8be41a5720 --- /dev/null +++ b/spec/ruby/library/matrix/eigenvalue_decomposition/to_a_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::EigenvalueDecomposition#to_a" do + before :each do + @a = Matrix[[14, 16], [-6, -6]] + @e = Matrix::EigenvalueDecomposition.new(@a) + end + + it "returns an array of with [V, D, V.inv]" do + @e.to_a.should == [@e.v, @e.d, @e.v_inv] + end + + it "returns a factorization" do + v, d, v_inv = @e.to_a + (v * d * v_inv).map{|e| e.round(10)}.should == @a + end +end diff --git a/spec/ruby/library/matrix/element_reference_spec.rb b/spec/ruby/library/matrix/element_reference_spec.rb new file mode 100644 index 0000000000..b950d1c391 --- /dev/null +++ b/spec/ruby/library/matrix/element_reference_spec.rb @@ -0,0 +1,23 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#[]" do + + before :all do + @m = Matrix[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]] + end + + it "returns element at (i, j)" do + (0..3).each do |i| + (0..2).each do |j| + @m[i, j].should == (i * 3) + j + end + end + end + + it "returns nil for an invalid index pair" do + @m[8,1].should be_nil + @m[1,8].should be_nil + end + +end diff --git a/spec/ruby/library/matrix/empty_spec.rb b/spec/ruby/library/matrix/empty_spec.rb new file mode 100644 index 0000000000..5f294711db --- /dev/null +++ b/spec/ruby/library/matrix/empty_spec.rb @@ -0,0 +1,68 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix#empty?" do + it "returns true when the Matrix is empty" do + Matrix[ ].empty?.should be_true + Matrix[ [], [], [] ].empty?.should be_true + Matrix[ [], [], [] ].transpose.empty?.should be_true + end + + it "returns false when the Matrix has elements" do + Matrix[ [1, 2] ].empty?.should be_false + Matrix[ [1], [2] ].empty?.should be_false + end + + it "doesn't accept any parameter" do + ->{ + Matrix[ [1, 2] ].empty?(42) + }.should raise_error(ArgumentError) + end +end + +describe "Matrix.empty" do + it "returns an empty matrix of the requested size" do + m = Matrix.empty(3, 0) + m.row_size.should == 3 + m.column_size.should == 0 + + m = Matrix.empty(0, 3) + m.row_size.should == 0 + m.column_size.should == 3 + end + + it "has arguments defaulting to 0" do + Matrix.empty.should == Matrix.empty(0, 0) + Matrix.empty(42).should == Matrix.empty(42, 0) + end + + it "does not accept more than two parameters" do + ->{ + Matrix.empty(1, 2, 3) + }.should raise_error(ArgumentError) + end + + it "raises an error if both dimensions are > 0" do + ->{ + Matrix.empty(1, 2) + }.should raise_error(ArgumentError) + end + + it "raises an error if any dimension is < 0" do + ->{ + Matrix.empty(-2, 0) + }.should raise_error(ArgumentError) + + ->{ + Matrix.empty(0, -2) + }.should raise_error(ArgumentError) + end + +end + +describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.empty(0, 1).should be_an_instance_of(MatrixSub) + end +end diff --git a/spec/ruby/library/matrix/eql_spec.rb b/spec/ruby/library/matrix/eql_spec.rb new file mode 100644 index 0000000000..ea26c3320d --- /dev/null +++ b/spec/ruby/library/matrix/eql_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../spec_helper' +require_relative 'shared/equal_value' +require 'matrix' + +describe "Matrix#eql?" do + it_behaves_like :equal, :eql? + + it "returns false if some elements are == but not eql?" do + Matrix[[1, 2],[3, 4]].eql?(Matrix[[1, 2],[3, 4.0]]).should be_false + end +end diff --git a/spec/ruby/library/matrix/equal_value_spec.rb b/spec/ruby/library/matrix/equal_value_spec.rb new file mode 100644 index 0000000000..10cf1e6c29 --- /dev/null +++ b/spec/ruby/library/matrix/equal_value_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../spec_helper' +require_relative 'shared/equal_value' +require 'matrix' + +describe "Matrix#==" do + it_behaves_like :equal, :== + + it "returns true if some elements are == but not eql?" do + Matrix[[1, 2],[3, 4]].should == Matrix[[1, 2],[3, 4.0]] + end +end diff --git a/spec/ruby/library/matrix/exponent_spec.rb b/spec/ruby/library/matrix/exponent_spec.rb new file mode 100644 index 0000000000..38cdfa9276 --- /dev/null +++ b/spec/ruby/library/matrix/exponent_spec.rb @@ -0,0 +1,62 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix#**" do + + describe "given an integer _n_" do + it "multiples the Matrix by itself _n_ times" do + m = Matrix[ [7,6], [3,9] ] + (m ** 1).should == m + (m ** 2).should == Matrix[ [67, 96], [48,99] ] + (m ** 2).should == m * m + (m ** 3).should == m * m * m + (m ** 4).should == m * m * m * m + (m ** 5).should == m * m * m * m * m + end + + it "raises a ErrDimensionMismatch for non square matrices" do + m = Matrix[ [1, 1], [1, 2], [2, 3]] + -> { m ** 3 }.should raise_error(Matrix::ErrDimensionMismatch) + -> { m ** 0 }.should raise_error(Matrix::ErrDimensionMismatch) + end + + describe "that is < 0" do + it "returns the inverse of **(-n)" do + m = Matrix[ [1, 1], [1, 2] ] + (m ** -2).should == Matrix[ [5, -3], [-3, 2]] + (m ** -4).should == (m.inverse ** 4) + end + + it "raises a ErrNotRegular for irregular matrices" do + m = Matrix[ [1, 1], [1, 1] ] + -> { m ** -2 }.should raise_error(Matrix::ErrNotRegular) + end + end + + describe "that is 0" do + it "returns the identity for square matrices" do + m = Matrix[ [1, 1], [1, 1] ] + (m ** 0).should == Matrix.identity(2) + end + + it "raises an ErrDimensionMismatch for non-square matrices" do + m = Matrix[ [1, 1] ] + -> { m ** 0 }.should raise_error(Matrix::ErrDimensionMismatch) + end + end + end + + it "returns the power for non integer powers" do + a = Matrix[[5, 4], [4, 5]] + ((a ** 0.5) ** 2).round(8).should == a + a = Matrix[[7, 10], [15, 22]] + ((a ** 0.25) ** 4).round(8).should == a + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + (MatrixSub.ins ** 1).should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/find_index_spec.rb b/spec/ruby/library/matrix/find_index_spec.rb new file mode 100644 index 0000000000..c2bfa6d61a --- /dev/null +++ b/spec/ruby/library/matrix/find_index_spec.rb @@ -0,0 +1,146 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#find_index without any argument" do + before :all do + @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ] + end + + it "returns an Enumerator when called without a block" do + enum = @m.find_index + enum.should be_an_instance_of(Enumerator) + enum.to_a.should == [1, 2, 3, 4, 5, 6, 7, 8] + end + + it "returns nil if the block is always false" do + @m.find_index{false}.should be_nil + end + + it "returns the first index for which the block is true" do + @m.find_index{|x| x >= 3}.should == [0, 2] + end +end + +describe "Matrix#find_index with a subselection argument" do + before :all do + @tests = [ + [ Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ], { + diagonal: [1, 6] , + off_diagonal: [2, 3, 4, 5, 7, 8], + lower: [1, 5, 6] , + strict_lower: [5] , + strict_upper: [2, 3, 4, 7, 8] , + upper: [1, 2, 3, 4, 6, 7, 8] , + } + ], + [ Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ], { + diagonal: [1, 4] , + off_diagonal: [2, 3, 5, 6, 7, 8], + lower: [1, 3, 4, 5, 6, 7, 8] , + strict_lower: [3, 5, 6, 7, 8] , + strict_upper: [2] , + upper: [1, 2, 4] , + } + ]] + end + + describe "and no generic argument" do + it "returns an Enumerator when called without a block" do + @tests.each do |matrix, h| + h.each do |selector, result| + matrix.find_index(selector).should be_an_instance_of(Enumerator) + end + end + end + + it "yields the rights elements" do + @tests.each do |matrix, h| + h.each do |selector, result| + matrix.find_index(selector).to_a.should == result + end + end + end + + it "returns the first index for which the block returns true" do + @tests.each do |matrix, h| + h.each do |selector, result| + cnt = result.size.div 2 + which = result[cnt] + idx = matrix.find_index(selector){|x| cnt -= 1; x == which} + matrix[*idx].should == which + cnt.should == -1 + end + end + end + + it "returns nil if the block is always false" do + @tests.each do |matrix, h| + h.each do |selector, result| + matrix.find_index(selector){ nil }.should == nil + end + end + end + + end + + describe "and a generic argument" do + it "ignores a block" do + @m.find_index(42, :diagonal){raise "oups"}.should == nil + end + + it "returns the index of the requested value" do + @tests.each do |matrix, h| + h.each do |selector, result| + cnt = result.size / 2 + which = result[cnt] + idx = matrix.find_index(which, selector) + matrix[*idx].should == which + end + end + end + + it "returns nil if the requested value is not found" do + @tests.each do |matrix, h| + h.each do |selector, result| + matrix.find_index(42, selector).should == nil + end + end + end + end + +end + +describe "Matrix#find_index with only a generic argument" do + before :all do + @m = Matrix[ [1, 2, 3, 4], [1, 2, 3, 4] ] + end + + it "returns nil if the value is not found" do + @m.find_index(42).should be_nil + end + + it "returns the first index for of the requested value" do + @m.find_index(3).should == [0, 2] + end + + it "ignores a block" do + @m.find_index(4){raise "oups"}.should == [0, 3] + end +end + +describe "Matrix#find_index with two arguments" do + it "raises an ArgumentError for an unrecognized last argument" do + -> { + @m.find_index(1, "all"){} + }.should raise_error(ArgumentError) + -> { + @m.find_index(1, nil){} + }.should raise_error(ArgumentError) + -> { + @m.find_index(1, :left){} + }.should raise_error(ArgumentError) + -> { + @m.find_index(:diagonal, 1){} + }.should raise_error(ArgumentError) + end +end diff --git a/spec/ruby/library/matrix/fixtures/classes.rb b/spec/ruby/library/matrix/fixtures/classes.rb new file mode 100644 index 0000000000..394377135f --- /dev/null +++ b/spec/ruby/library/matrix/fixtures/classes.rb @@ -0,0 +1,7 @@ +require 'matrix' + +class MatrixSub < Matrix + def self.ins + rows([[1, 0], [0, 1]]) + end +end diff --git a/spec/ruby/library/matrix/hash_spec.rb b/spec/ruby/library/matrix/hash_spec.rb new file mode 100644 index 0000000000..7dabcd3737 --- /dev/null +++ b/spec/ruby/library/matrix/hash_spec.rb @@ -0,0 +1,15 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#hash" do + + it "returns an Integer" do + Matrix[ [1,2] ].hash.should be_an_instance_of(Integer) + end + + it "returns the same value for the same matrix" do + data = [ [40,5], [2,7] ] + Matrix[ *data ].hash.should == Matrix[ *data ].hash + end + +end diff --git a/spec/ruby/library/matrix/hermitian_spec.rb b/spec/ruby/library/matrix/hermitian_spec.rb new file mode 100644 index 0000000000..177ca64d83 --- /dev/null +++ b/spec/ruby/library/matrix/hermitian_spec.rb @@ -0,0 +1,34 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix.hermitian?" do + it "returns true for a hermitian Matrix" do + Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, -3), 5, 6]].hermitian?.should be_true + end + + it "returns true for a 0x0 empty matrix" do + Matrix.empty.hermitian?.should be_true + end + + it "returns false for an asymmetric Matrix" do + Matrix[[1, 2],[-2, 1]].hermitian?.should be_false + end + + it "raises an error for rectangular matrices" do + [ + Matrix[[0], [0]], + Matrix[[0, 0]], + Matrix.empty(0, 2), + Matrix.empty(2, 0), + ].each do |rectangular_matrix| + -> { + rectangular_matrix.hermitian? + }.should raise_error(Matrix::ErrDimensionMismatch) + end + end + + it "returns false for a matrix with complex values on the diagonal" do + Matrix[[Complex(1,1)]].hermitian?.should be_false + Matrix[[Complex(1,0)]].hermitian?.should be_true + end +end diff --git a/spec/ruby/library/matrix/identity_spec.rb b/spec/ruby/library/matrix/identity_spec.rb new file mode 100644 index 0000000000..646462bc47 --- /dev/null +++ b/spec/ruby/library/matrix/identity_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/identity' + +describe "Matrix.identity" do + it_behaves_like :matrix_identity, :identity +end diff --git a/spec/ruby/library/matrix/imag_spec.rb b/spec/ruby/library/matrix/imag_spec.rb new file mode 100644 index 0000000000..1c988753d8 --- /dev/null +++ b/spec/ruby/library/matrix/imag_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/imaginary' + +describe "Matrix#imag" do + it_behaves_like :matrix_imaginary, :imag +end diff --git a/spec/ruby/library/matrix/imaginary_spec.rb b/spec/ruby/library/matrix/imaginary_spec.rb new file mode 100644 index 0000000000..ceae4bbe8d --- /dev/null +++ b/spec/ruby/library/matrix/imaginary_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/imaginary' + +describe "Matrix#imaginary" do + it_behaves_like :matrix_imaginary, :imaginary +end diff --git a/spec/ruby/library/matrix/inspect_spec.rb b/spec/ruby/library/matrix/inspect_spec.rb new file mode 100644 index 0000000000..508f478252 --- /dev/null +++ b/spec/ruby/library/matrix/inspect_spec.rb @@ -0,0 +1,27 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix#inspect" do + + it "returns a stringified representation of the Matrix" do + Matrix[ [1,2], [2,1] ].inspect.should == "Matrix[[1, 2], [2, 1]]" + end + + it "returns 'Matrix.empty(...)' for empty matrices" do + Matrix[ [], [], [] ].inspect.should == "Matrix.empty(3, 0)" + Matrix.columns([ [], [], [] ]).inspect.should == "Matrix.empty(0, 3)" + end + + it "calls inspect on its contents" do + obj = mock("some_value") + obj.should_receive(:inspect).and_return("some_value") + Matrix[ [1, 2], [3, obj] ].inspect.should == "Matrix[[1, 2], [3, some_value]]" + end + + describe "for a subclass of Matrix" do + it "returns a string using the subclass' name" do + MatrixSub.ins.inspect.should == "MatrixSub[[1, 0], [0, 1]]" + end + end +end diff --git a/spec/ruby/library/matrix/inv_spec.rb b/spec/ruby/library/matrix/inv_spec.rb new file mode 100644 index 0000000000..82879a6d82 --- /dev/null +++ b/spec/ruby/library/matrix/inv_spec.rb @@ -0,0 +1,7 @@ +require_relative '../../spec_helper' +require_relative 'spec_helper' +require_relative 'shared/inverse' + +describe "Matrix#inv" do + it_behaves_like :inverse, :inv +end diff --git a/spec/ruby/library/matrix/inverse_from_spec.rb b/spec/ruby/library/matrix/inverse_from_spec.rb new file mode 100644 index 0000000000..651d56a244 --- /dev/null +++ b/spec/ruby/library/matrix/inverse_from_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#inverse_from" do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/library/matrix/inverse_spec.rb b/spec/ruby/library/matrix/inverse_spec.rb new file mode 100644 index 0000000000..fa3fa7de8a --- /dev/null +++ b/spec/ruby/library/matrix/inverse_spec.rb @@ -0,0 +1,7 @@ +require_relative '../../spec_helper' +require_relative 'spec_helper' +require_relative 'shared/inverse' + +describe "Matrix#inverse" do + it_behaves_like :inverse, :inverse +end diff --git a/spec/ruby/library/matrix/lower_triangular_spec.rb b/spec/ruby/library/matrix/lower_triangular_spec.rb new file mode 100644 index 0000000000..f3aa4501f4 --- /dev/null +++ b/spec/ruby/library/matrix/lower_triangular_spec.rb @@ -0,0 +1,24 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix.lower_triangular?" do + it "returns true for a square lower triangular Matrix" do + Matrix[[1, 0, 0], [1, 2, 0], [1, 2, 3]].lower_triangular?.should be_true + Matrix.diagonal([1, 2, 3]).lower_triangular?.should be_true + Matrix[[1, 0], [1, 2], [1, 2], [1, 2]].lower_triangular?.should be_true + Matrix[[1, 0, 0, 0], [1, 2, 0, 0]].lower_triangular?.should be_true + end + + it "returns true for an empty Matrix" do + Matrix.empty(3, 0).lower_triangular?.should be_true + Matrix.empty(0, 3).lower_triangular?.should be_true + Matrix.empty(0, 0).lower_triangular?.should be_true + end + + it "returns false for a non lower triangular square Matrix" do + Matrix[[0, 1], [0, 0]].lower_triangular?.should be_false + Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].lower_triangular?.should be_false + Matrix[[0, 1], [0, 0], [0, 0], [0, 0]].lower_triangular?.should be_false + Matrix[[0, 0, 0, 1], [0, 0, 0, 0]].lower_triangular?.should be_false + end +end diff --git a/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb b/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb new file mode 100644 index 0000000000..9d733066c1 --- /dev/null +++ b/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::LUPDecomposition#determinant" do + it "returns the determinant when the matrix is square" do + a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]] + a.lup.determinant.should == 15120 # == a.determinant + end + + it "raises an error for rectangular matrices" do + [ + Matrix[[7, 8, 9], [14, 46, 51]], + Matrix[[7, 8], [14, 46], [28, 82]], + ].each do |m| + lup = m.lup + -> { + lup.determinant + }.should raise_error(Matrix::ErrDimensionMismatch) + end + end +end diff --git a/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb b/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb new file mode 100644 index 0000000000..36afb349e6 --- /dev/null +++ b/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::LUPDecomposition#initialize" do + it "raises an error if argument is not a matrix" do + -> { + Matrix::LUPDecomposition.new([[]]) + }.should raise_error(TypeError) + -> { + Matrix::LUPDecomposition.new(42) + }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/matrix/lup_decomposition/l_spec.rb b/spec/ruby/library/matrix/lup_decomposition/l_spec.rb new file mode 100644 index 0000000000..9514ab5d06 --- /dev/null +++ b/spec/ruby/library/matrix/lup_decomposition/l_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::LUPDecomposition#l" do + before :each do + @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]] + @lu = Matrix::LUPDecomposition.new(@a) + @l = @lu.l + end + + it "returns the first element of to_a" do + @l.should == @lu.to_a[0] + end + + it "returns a lower triangular matrix" do + @l.lower_triangular?.should be_true + end +end diff --git a/spec/ruby/library/matrix/lup_decomposition/p_spec.rb b/spec/ruby/library/matrix/lup_decomposition/p_spec.rb new file mode 100644 index 0000000000..c7b5e9196e --- /dev/null +++ b/spec/ruby/library/matrix/lup_decomposition/p_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::LUPDecomposition#p" do + before :each do + @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]] + @lu = Matrix::LUPDecomposition.new(@a) + @p = @lu.p + end + + it "returns the third element of to_a" do + @p.should == @lu.to_a[2] + end + + it "returns a permutation matrix" do + @p.permutation?.should be_true + end +end diff --git a/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb b/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb new file mode 100644 index 0000000000..66242627e9 --- /dev/null +++ b/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb @@ -0,0 +1,53 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::LUPDecomposition#solve" do + describe "for rectangular matrices" do + it "raises an error for singular matrices" do + a = Matrix[[1, 2, 3], [1, 3, 5], [2, 5, 8]] + lu = Matrix::LUPDecomposition.new(a) + -> { + lu.solve(a) + }.should raise_error(Matrix::ErrNotRegular) + end + + describe "for non singular matrices" do + before :each do + @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]] + @lu = Matrix::LUPDecomposition.new(@a) + end + + it "returns the appropriate empty matrix when given an empty matrix" do + @lu.solve(Matrix.empty(3,0)).should == Matrix.empty(3,0) + empty = Matrix::LUPDecomposition.new(Matrix.empty(0, 0)) + empty.solve(Matrix.empty(0,3)).should == Matrix.empty(0,3) + end + + it "returns the right matrix when given a matrix of the appropriate size" do + solution = Matrix[[1, 2, 3, 4], [0, 1, 2, 3], [-1, -2, -3, -4]] + values = Matrix[[-2, 4, 10, 16], [-37, -28, -19, -10], [-135, -188, -241, -294]] # == @a * solution + @lu.solve(values).should == solution + end + + it "raises an error when given a matrix of the wrong size" do + values = Matrix[[1, 2, 3, 4], [0, 1, 2, 3]] + -> { + @lu.solve(values) + }.should raise_error(Matrix::ErrDimensionMismatch) + end + + it "returns the right vector when given a vector of the appropriate size" do + solution = Vector[1, 2, -1] + values = Vector[14, 55, 29] # == @a * solution + @lu.solve(values).should == solution + end + + it "raises an error when given a vector of the wrong size" do + values = Vector[14, 55] + -> { + @lu.solve(values) + }.should raise_error(Matrix::ErrDimensionMismatch) + end + end + end +end diff --git a/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb b/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb new file mode 100644 index 0000000000..9b1dccbbac --- /dev/null +++ b/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb @@ -0,0 +1,33 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::LUPDecomposition#to_a" do + before :each do + @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]] + @lu = Matrix::LUPDecomposition.new(@a) + @to_a = @lu.to_a + @l, @u, @p = @to_a + end + + it "returns an array of three matrices" do + @to_a.should be_kind_of(Array) + @to_a.length.should == 3 + @to_a.each{|m| m.should be_kind_of(Matrix)} + end + + it "returns [l, u, p] such that l*u == a*p" do + (@l * @u).should == (@p * @a) + end + + it "returns the right values for rectangular matrices" do + [ + Matrix[[7, 8, 9], [14, 46, 51]], + Matrix[[4, 11], [5, 8], [3, 4]], + ].each do |a| + l, u, p = Matrix::LUPDecomposition.new(a).to_a + (l * u).should == (p * a) + end + end + + it "has other properties implied by the specs of #l, #u and #p" +end diff --git a/spec/ruby/library/matrix/lup_decomposition/u_spec.rb b/spec/ruby/library/matrix/lup_decomposition/u_spec.rb new file mode 100644 index 0000000000..ca3dfc1f00 --- /dev/null +++ b/spec/ruby/library/matrix/lup_decomposition/u_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::LUPDecomposition#u" do + before :each do + @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]] + @lu = Matrix::LUPDecomposition.new(@a) + @u = @lu.u + end + + it "returns the second element of to_a" do + @u.should == @lu.to_a[1] + end + + it "returns an upper triangular matrix" do + @u.upper_triangular?.should be_true + end +end diff --git a/spec/ruby/library/matrix/map_spec.rb b/spec/ruby/library/matrix/map_spec.rb new file mode 100644 index 0000000000..bc07c48cda --- /dev/null +++ b/spec/ruby/library/matrix/map_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/collect' + +describe "Matrix#map" do + it_behaves_like :collect, :map +end diff --git a/spec/ruby/library/matrix/minor_spec.rb b/spec/ruby/library/matrix/minor_spec.rb new file mode 100644 index 0000000000..009826c3d6 --- /dev/null +++ b/spec/ruby/library/matrix/minor_spec.rb @@ -0,0 +1,85 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix#minor" do + before :each do + @matrix = Matrix[ [1,2], [3,4], [5,6] ] + end + + describe "with start_row, nrows, start_col, ncols" do + it "returns the given portion of the Matrix" do + @matrix.minor(0,1,0,2).should == Matrix[ [1, 2] ] + @matrix.minor(1,2,1,1).should == Matrix[ [4], [6] ] + end + + it "returns an empty Matrix if nrows or ncols is 0" do + @matrix.minor(0,0,0,0).should == Matrix[] + @matrix.minor(1,0,1,0).should == Matrix[] + @matrix.minor(1,0,1,1).should == Matrix.columns([[]]) + @matrix.minor(1,1,1,0).should == Matrix[[]] + end + + it "returns nil for out-of-bounds start_row/col" do + r = @matrix.row_size + 1 + c = @matrix.column_size + 1 + @matrix.minor(r,0,0,10).should == nil + @matrix.minor(0,10,c,9).should == nil + @matrix.minor(-r,0,0,10).should == nil + @matrix.minor(0,10,-c,9).should == nil + end + + it "returns nil for negative nrows or ncols" do + @matrix.minor(0,1,0,-1).should == nil + @matrix.minor(0,-1,0,1).should == nil + end + + it "start counting backwards for start_row or start_col below zero" do + @matrix.minor(0, 1, -1, 1).should == @matrix.minor(0, 1, 1, 1) + @matrix.minor(-1, 1, 0, 1).should == @matrix.minor(2, 1, 0, 1) + end + + it "returns empty matrices for extreme start_row/col" do + @matrix.minor(3,10,1,10).should == Matrix.columns([[]]) + @matrix.minor(1,10,2,10).should == Matrix[[], []] + @matrix.minor(3,0,0,10).should == Matrix.columns([[], []]) + end + + it "ignores big nrows or ncols" do + @matrix.minor(0,1,0,20).should == Matrix[ [1, 2] ] + @matrix.minor(1,20,1,1).should == Matrix[ [4], [6] ] + end + end + + describe "with col_range, row_range" do + it "returns the given portion of the Matrix" do + @matrix.minor(0..0, 0..1).should == Matrix[ [1, 2] ] + @matrix.minor(1..2, 1..2).should == Matrix[ [4], [6] ] + @matrix.minor(1...3, 1...3).should == Matrix[ [4], [6] ] + end + + it "returns nil if col_range or row_range is out of range" do + r = @matrix.row_size + 1 + c = @matrix.column_size + 1 + @matrix.minor(r..6, c..6).should == nil + @matrix.minor(0..1, c..6).should == nil + @matrix.minor(r..6, 0..1).should == nil + @matrix.minor(-r..6, -c..6).should == nil + @matrix.minor(0..1, -c..6).should == nil + @matrix.minor(-r..6, 0..1).should == nil + end + + it "start counting backwards for col_range or row_range below zero" do + @matrix.minor(0..1, -2..-1).should == @matrix.minor(0..1, 0..1) + @matrix.minor(0..1, -2..1).should == @matrix.minor(0..1, 0..1) + @matrix.minor(-2..-1, 0..1).should == @matrix.minor(1..2, 0..1) + @matrix.minor(-2..2, 0..1).should == @matrix.minor(1..2, 0..1) + end + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.ins.minor(0, 1, 0, 1).should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/minus_spec.rb b/spec/ruby/library/matrix/minus_spec.rb new file mode 100644 index 0000000000..95cf4a6072 --- /dev/null +++ b/spec/ruby/library/matrix/minus_spec.rb @@ -0,0 +1,42 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix#-" do + before :each do + @a = Matrix[ [1, 2], [3, 4] ] + @b = Matrix[ [4, 5], [6, 7] ] + end + + it "returns the result of subtracting the corresponding elements of other from self" do + (@a - @b).should == Matrix[ [-3,-3], [-3,-3] ] + end + + it "returns an instance of Matrix" do + (@a - @b).should be_kind_of(Matrix) + end + + it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do + -> { @a - Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch) + end + + it "raises a ExceptionForMatrix::ErrOperationNotDefined if other is a Numeric Type" do + -> { @a - 2 }.should raise_error(Matrix::ErrOperationNotDefined) + -> { @a - 1.2 }.should raise_error(Matrix::ErrOperationNotDefined) + -> { @a - bignum_value }.should raise_error(Matrix::ErrOperationNotDefined) + end + + it "raises a TypeError if other is of wrong type" do + -> { @a - nil }.should raise_error(TypeError) + -> { @a - "a" }.should raise_error(TypeError) + -> { @a - [ [1, 2] ] }.should raise_error(TypeError) + -> { @a - Object.new }.should raise_error(TypeError) + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + m = MatrixSub.ins + (m-m).should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/multiply_spec.rb b/spec/ruby/library/matrix/multiply_spec.rb new file mode 100644 index 0000000000..206868af92 --- /dev/null +++ b/spec/ruby/library/matrix/multiply_spec.rb @@ -0,0 +1,69 @@ +require_relative '../../spec_helper' + +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix#*" do + before :each do + @a = Matrix[ [1, 2], [3, 4] ] + @b = Matrix[ [4, 5], [6, 7] ] + end + + it "returns the result of multiplying the corresponding elements of self and a Matrix" do + (@a * @b).should == Matrix[ [16,19], [36,43] ] + end + + it "returns the result of multiplying the corresponding elements of self and a Vector" do + (@a * Vector[1,2]).should == Vector[5, 11] + end + + it "returns the result of multiplying the elements of self and a Fixnum" do + (@a * 2).should == Matrix[ [2, 4], [6, 8] ] + end + + it "returns the result of multiplying the elements of self and a Bignum" do + (@a * bignum_value).should == Matrix[ + [18446744073709551616, 36893488147419103232], + [55340232221128654848, 73786976294838206464] + ] + end + + it "returns the result of multiplying the elements of self and a Float" do + (@a * 2.0).should == Matrix[ [2.0, 4.0], [6.0, 8.0] ] + end + + it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do + -> { @a * Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch) + end + + it "returns a zero matrix if (nx0) * (0xn)" do + (Matrix[[],[],[]] * Matrix.columns([[],[],[]])).should == Matrix.zero(3) + end + + it "returns an empty matrix if (0xn) * (nx0)" do + (Matrix.columns([[],[],[]]) * Matrix[[],[],[]]).should == Matrix[] + end + + it "returns a mx0 matrix if (mxn) * (nx0)" do + (Matrix[[1,2],[3,4],[5,6]] * Matrix[[],[]]).should == Matrix[[],[],[]] + end + + it "returns a 0xm matrix if (0xm) * (mxn)" do + (Matrix.columns([[], [], []]) * Matrix[[1,2],[3,4],[5,6]]).should == Matrix.columns([[],[]]) + end + + it "raises a TypeError if other is of wrong type" do + -> { @a * nil }.should raise_error(TypeError) + -> { @a * "a" }.should raise_error(TypeError) + -> { @a * [ [1, 2] ] }.should raise_error(TypeError) + -> { @a * Object.new }.should raise_error(TypeError) + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + m = MatrixSub.ins + (m*m).should be_an_instance_of(MatrixSub) + (m*1).should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/new_spec.rb b/spec/ruby/library/matrix/new_spec.rb new file mode 100644 index 0000000000..3005066846 --- /dev/null +++ b/spec/ruby/library/matrix/new_spec.rb @@ -0,0 +1,8 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix.new" do + it "is private" do + Matrix.should have_private_method(:new) + end +end diff --git a/spec/ruby/library/matrix/normal_spec.rb b/spec/ruby/library/matrix/normal_spec.rb new file mode 100644 index 0000000000..a9e6c645fa --- /dev/null +++ b/spec/ruby/library/matrix/normal_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix.normal?" do + # it "returns false for non normal matrices" do + # Matrix[[0, 1], [1, 2]].should_not.normal? + # end + + it "returns true for normal matrices" do + Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should.normal? + Matrix[[0, Complex(0, 2)], [Complex(0, -2), 0]].should.normal? + end + + it "raises an error for rectangular matrices" do + [ + Matrix[[0], [0]], + Matrix[[0, 0]], + Matrix.empty(0, 2), + Matrix.empty(2, 0), + ].each do |rectangular_matrix| + -> { + rectangular_matrix.normal? + }.should raise_error(Matrix::ErrDimensionMismatch) + end + end +end diff --git a/spec/ruby/library/matrix/orthogonal_spec.rb b/spec/ruby/library/matrix/orthogonal_spec.rb new file mode 100644 index 0000000000..26afe89ff0 --- /dev/null +++ b/spec/ruby/library/matrix/orthogonal_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix.orthogonal?" do + it "returns false for non orthogonal matrices" do + Matrix[[0, 1], [1, 2]].should_not.orthogonal? + Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should_not.orthogonal? + end + + it "returns true for orthogonal matrices" do + Matrix[[0, 1], [1, 0]].should.orthogonal? + end + + it "raises an error for rectangular matrices" do + [ + Matrix[[0], [0]], + Matrix[[0, 0]], + Matrix.empty(0, 2), + Matrix.empty(2, 0), + ].each do |rectangular_matrix| + -> { + rectangular_matrix.orthogonal? + }.should raise_error(Matrix::ErrDimensionMismatch) + end + end +end diff --git a/spec/ruby/library/matrix/permutation_spec.rb b/spec/ruby/library/matrix/permutation_spec.rb new file mode 100644 index 0000000000..825a9d982c --- /dev/null +++ b/spec/ruby/library/matrix/permutation_spec.rb @@ -0,0 +1,32 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#permutation?" do + it "returns true for a permutation Matrix" do + Matrix[[0, 1, 0], [0, 0, 1], [1, 0, 0]].permutation?.should be_true + end + + it "returns false for a non permutation square Matrix" do + Matrix[[0, 1], [0, 0]].permutation?.should be_false + Matrix[[-1, 0], [0, -1]].permutation?.should be_false + Matrix[[1, 0], [1, 0]].permutation?.should be_false + Matrix[[1, 0], [1, 1]].permutation?.should be_false + end + + it "returns true for an empty 0x0 matrix" do + Matrix.empty(0,0).permutation?.should be_true + end + + it "raises an error for rectangular matrices" do + [ + Matrix[[0], [0]], + Matrix[[0, 0]], + Matrix.empty(0, 2), + Matrix.empty(2, 0), + ].each do |rectangular_matrix| + -> { + rectangular_matrix.permutation? + }.should raise_error(Matrix::ErrDimensionMismatch) + end + end +end diff --git a/spec/ruby/library/matrix/plus_spec.rb b/spec/ruby/library/matrix/plus_spec.rb new file mode 100644 index 0000000000..2706bad060 --- /dev/null +++ b/spec/ruby/library/matrix/plus_spec.rb @@ -0,0 +1,42 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix#+" do + before :each do + @a = Matrix[ [1,2], [3,4] ] + @b = Matrix[ [4,5], [6,7] ] + end + + it "returns the result of adding the corresponding elements of self and other" do + (@a + @b).should == Matrix[ [5,7], [9,11] ] + end + + it "returns an instance of Matrix" do + (@a + @b).should be_kind_of(Matrix) + end + + it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do + -> { @a + Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch) + end + + it "raises a ExceptionForMatrix::ErrOperationNotDefined if other is a Numeric Type" do + -> { @a + 2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined) + -> { @a + 1.2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined) + -> { @a + bignum_value }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined) + end + + it "raises a TypeError if other is of wrong type" do + -> { @a + nil }.should raise_error(TypeError) + -> { @a + "a" }.should raise_error(TypeError) + -> { @a + [ [1, 2] ] }.should raise_error(TypeError) + -> { @a + Object.new }.should raise_error(TypeError) + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + m = MatrixSub.ins + (m+m).should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/rank_spec.rb b/spec/ruby/library/matrix/rank_spec.rb new file mode 100644 index 0000000000..d4403d23ed --- /dev/null +++ b/spec/ruby/library/matrix/rank_spec.rb @@ -0,0 +1,19 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#rank" do + it "returns the rank of the Matrix" do + Matrix[ [7,6], [3,9] ].rank.should == 2 + end + + it "doesn't loop forever" do + Matrix[ [1,2,3], [4,5,6], [7,8,9] ].rank.should == 2 + Matrix[ [1, 2, 0, 3], [1, -2, 3, 0], [0, 0, 4, 8], [2, 4, 0, 6] ].rank. + should == 3 + end + + it "works for some easy rectangular matrices" do + Matrix[[0,0],[0,0],[1,0]].rank.should == 1 + Matrix[[0,1],[0,0],[1,0]].rank.should == 2 + end +end diff --git a/spec/ruby/library/matrix/real_spec.rb b/spec/ruby/library/matrix/real_spec.rb new file mode 100644 index 0000000000..38033c63c8 --- /dev/null +++ b/spec/ruby/library/matrix/real_spec.rb @@ -0,0 +1,43 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix#real?" do + it "returns true for matrices with all real entries" do + Matrix[ [1, 2], [3, 4] ].real?.should be_true + Matrix[ [1.9, 2], [3, 4] ].real?.should be_true + end + + it "returns true for empty matrices" do + Matrix.empty.real?.should be_true + end + + it "returns false if one element is a Complex" do + Matrix[ [Complex(1,1), 2], [3, 4] ].real?.should be_false + end + + # Guard against the Mathn library + guard -> { !defined?(Math.rsqrt) } do + it "returns false if one element is a Complex whose imaginary part is 0" do + Matrix[ [Complex(1,0), 2], [3, 4] ].real?.should be_false + end + end +end + +describe "Matrix#real" do + it "returns a matrix with the real part of the elements of the receiver" do + Matrix[ [1, 2], [3, 4] ].real.should == Matrix[ [1, 2], [3, 4] ] + Matrix[ [1.9, Complex(1,1)], [Complex(-0.42, 0), 4] ].real.should == Matrix[ [1.9, 1], [-0.42, 4] ] + end + + it "returns empty matrices on the same size if empty" do + Matrix.empty(0, 3).real.should == Matrix.empty(0, 3) + Matrix.empty(3, 0).real.should == Matrix.empty(3, 0) + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.ins.real.should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/rect_spec.rb b/spec/ruby/library/matrix/rect_spec.rb new file mode 100644 index 0000000000..83a0404e47 --- /dev/null +++ b/spec/ruby/library/matrix/rect_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/rectangular' + +describe "Matrix#rect" do + it_behaves_like :matrix_rectangular, :rect +end diff --git a/spec/ruby/library/matrix/rectangular_spec.rb b/spec/ruby/library/matrix/rectangular_spec.rb new file mode 100644 index 0000000000..a235fac640 --- /dev/null +++ b/spec/ruby/library/matrix/rectangular_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/rectangular' + +describe "Matrix#rectangular" do + it_behaves_like :matrix_rectangular, :rectangular +end diff --git a/spec/ruby/library/matrix/regular_spec.rb b/spec/ruby/library/matrix/regular_spec.rb new file mode 100644 index 0000000000..3699d0ef8b --- /dev/null +++ b/spec/ruby/library/matrix/regular_spec.rb @@ -0,0 +1,31 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#regular?" do + + it "returns false for singular matrices" do + m = Matrix[ [1,2,3], [3,4,3], [0,0,0] ] + m.regular?.should be_false + + m = Matrix[ [1,2,9], [3,4,9], [1,2,9] ] + m.regular?.should be_false + end + + it "returns true if the Matrix is regular" do + Matrix[ [0,1], [1,0] ].regular?.should be_true + end + + it "returns true for an empty 0x0 matrix" do + Matrix.empty(0,0).regular?.should be_true + end + + it "raises an error for rectangular matrices" do + -> { + Matrix[[1], [2], [3]].regular? + }.should raise_error(Matrix::ErrDimensionMismatch) + + -> { + Matrix.empty(3,0).regular? + }.should raise_error(Matrix::ErrDimensionMismatch) + end +end diff --git a/spec/ruby/library/matrix/round_spec.rb b/spec/ruby/library/matrix/round_spec.rb new file mode 100644 index 0000000000..1dc29df890 --- /dev/null +++ b/spec/ruby/library/matrix/round_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix#round" do + it "returns a matrix with all entries rounded" do + Matrix[ [1, 2.34], [5.67, 8] ].round.should == Matrix[ [1, 2], [6, 8] ] + Matrix[ [1, 2.34], [5.67, 8] ].round(1).should == Matrix[ [1, 2.3], [5.7, 8] ] + end + + it "returns empty matrices on the same size if empty" do + Matrix.empty(0, 3).round.should == Matrix.empty(0, 3) + Matrix.empty(3, 0).round(42).should == Matrix.empty(3, 0) + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.ins.round.should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/row_size_spec.rb b/spec/ruby/library/matrix/row_size_spec.rb new file mode 100644 index 0000000000..eb3aef2e2f --- /dev/null +++ b/spec/ruby/library/matrix/row_size_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#row_size" do + it "returns the number rows" do + Matrix[ [1,2], [3, 4], [5, 6] ].row_size.should == 3 + end + + it "returns the number rows even for some empty matrices" do + Matrix[ [], [], [] ].row_size.should == 3 + end + +end diff --git a/spec/ruby/library/matrix/row_spec.rb b/spec/ruby/library/matrix/row_spec.rb new file mode 100644 index 0000000000..00b1f02a8e --- /dev/null +++ b/spec/ruby/library/matrix/row_spec.rb @@ -0,0 +1,36 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#row" do + before :all do + @m = Matrix[ [1, 2], [2, 3], [3, 4] ] + end + + it "returns a Vector when called without a block" do + @m.row(0).should == Vector[1,2] + end + + it "yields the elements of the row when called with a block" do + a = [] + @m.row(0) {|x| a << x} + a.should == [1,2] + end + + it "counts backwards for negative argument" do + @m.row(-1).should == Vector[3, 4] + end + + it "returns self when called with a block" do + @m.row(0) { |x| x }.should equal(@m) + end + + it "returns nil when out of bounds" do + @m.row(3).should == nil + @m.row(-4).should == nil + end + + it "never yields when out of bounds" do + -> { @m.row(3){ raise } }.should_not raise_error + -> { @m.row(-4){ raise } }.should_not raise_error + end +end diff --git a/spec/ruby/library/matrix/row_vector_spec.rb b/spec/ruby/library/matrix/row_vector_spec.rb new file mode 100644 index 0000000000..341437ee05 --- /dev/null +++ b/spec/ruby/library/matrix/row_vector_spec.rb @@ -0,0 +1,24 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix.row_vector" do + + it "returns a Matrix" do + Matrix.row_vector([]).should be_an_instance_of(Matrix) + end + + it "returns a single-row Matrix with the specified values" do + Matrix.row_vector([1,2]).should == Matrix[ [1,2] ] + end + + it "returns a 1x0 matrix when called with an empty Array" do + Matrix.row_vector([]).should == Matrix[ [] ] + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.row_vector([1]).should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/row_vectors_spec.rb b/spec/ruby/library/matrix/row_vectors_spec.rb new file mode 100644 index 0000000000..6f99c439a6 --- /dev/null +++ b/spec/ruby/library/matrix/row_vectors_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#row_vectors" do + + before :each do + @vectors = Matrix[ [1,2], [3,4] ].row_vectors + end + + it "returns an Array" do + Matrix[ [1,2], [3,4] ].row_vectors.should be_an_instance_of(Array) + end + + it "returns an Array of Vectors" do + @vectors.all? {|v| v.should be_an_instance_of(Vector)} + end + + it "returns each row as a Vector" do + @vectors.should == [Vector[1,2], Vector[3,4]] + end + + it "returns an empty Array for empty matrices" do + Matrix[].row_vectors.should == [] + Matrix[ [] ].row_vectors.should == [ Vector[] ] + end +end diff --git a/spec/ruby/library/matrix/rows_spec.rb b/spec/ruby/library/matrix/rows_spec.rb new file mode 100644 index 0000000000..41ba635775 --- /dev/null +++ b/spec/ruby/library/matrix/rows_spec.rb @@ -0,0 +1,41 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix.rows" do + before :each do + @a = [1, 2] + @b = [3, 4] + @m = Matrix.rows([@a, @b]) + end + + it "returns a Matrix" do + @m.should be_kind_of(Matrix) + end + + it "creates a matrix from argument rows" do + @m.row(0).to_a.should == @a + @m.row(1).to_a.should == @b + end + + it "copies the original rows by default" do + @a << 3 + @b << 6 + @m.row(0).should_not equal(@a) + @m.row(1).should_not equal(@b) + end + + it "references the original rows if copy is false" do + @m_ref = Matrix.rows([@a, @b], false) + @a << 3 + @b << 6 + @m_ref.row(0).to_a.should == @a + @m_ref.row(1).to_a.should == @b + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.rows([[0, 1], [0, 1]]).should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/scalar/Fail_spec.rb b/spec/ruby/library/matrix/scalar/Fail_spec.rb new file mode 100644 index 0000000000..9d8f9bd5e8 --- /dev/null +++ b/spec/ruby/library/matrix/scalar/Fail_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#Fail" do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/library/matrix/scalar/Raise_spec.rb b/spec/ruby/library/matrix/scalar/Raise_spec.rb new file mode 100644 index 0000000000..27e11c1f77 --- /dev/null +++ b/spec/ruby/library/matrix/scalar/Raise_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#Raise" do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/library/matrix/scalar/divide_spec.rb b/spec/ruby/library/matrix/scalar/divide_spec.rb new file mode 100644 index 0000000000..5d726943fe --- /dev/null +++ b/spec/ruby/library/matrix/scalar/divide_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#/" do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/library/matrix/scalar/exponent_spec.rb b/spec/ruby/library/matrix/scalar/exponent_spec.rb new file mode 100644 index 0000000000..8e9ef52ff2 --- /dev/null +++ b/spec/ruby/library/matrix/scalar/exponent_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#**" do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/library/matrix/scalar/included_spec.rb b/spec/ruby/library/matrix/scalar/included_spec.rb new file mode 100644 index 0000000000..cb3beb2ecd --- /dev/null +++ b/spec/ruby/library/matrix/scalar/included_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar.included" do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/library/matrix/scalar/initialize_spec.rb b/spec/ruby/library/matrix/scalar/initialize_spec.rb new file mode 100644 index 0000000000..23145ad0de --- /dev/null +++ b/spec/ruby/library/matrix/scalar/initialize_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#initialize" do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/library/matrix/scalar/minus_spec.rb b/spec/ruby/library/matrix/scalar/minus_spec.rb new file mode 100644 index 0000000000..c727ea1659 --- /dev/null +++ b/spec/ruby/library/matrix/scalar/minus_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#-" do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/library/matrix/scalar/multiply_spec.rb b/spec/ruby/library/matrix/scalar/multiply_spec.rb new file mode 100644 index 0000000000..1a2a83d83e --- /dev/null +++ b/spec/ruby/library/matrix/scalar/multiply_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#*" do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/library/matrix/scalar/plus_spec.rb b/spec/ruby/library/matrix/scalar/plus_spec.rb new file mode 100644 index 0000000000..c94689a702 --- /dev/null +++ b/spec/ruby/library/matrix/scalar/plus_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Matrix::Scalar#+" do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/library/matrix/scalar_spec.rb b/spec/ruby/library/matrix/scalar_spec.rb new file mode 100644 index 0000000000..7fdd64c9d9 --- /dev/null +++ b/spec/ruby/library/matrix/scalar_spec.rb @@ -0,0 +1,67 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix.scalar" do + + before :each do + @side = 3 + @value = 8 + @a = Matrix.scalar(@side, @value) + end + + it "returns a Matrix" do + @a.should be_kind_of(Matrix) + end + + it "returns a n x n matrix" do + @a.row_size.should == @side + @a.column_size.should == @side + end + + it "initializes diagonal to value" do + (0...@a.row_size).each do |i| + @a[i, i].should == @value + end + end + + it "initializes all non-diagonal values to 0" do + (0...@a.row_size).each do |i| + (0...@a.column_size).each do |j| + if i != j + @a[i, j].should == 0 + end + end + end + end + + before :each do + @side = 3 + @value = 8 + @a = Matrix.scalar(@side, @value) + end + + it "returns a Matrix" do + @a.should be_kind_of(Matrix) + end + + it "returns a square matrix, where the first argument specifies the side of the square" do + @a.row_size.should == @side + @a.column_size.should == @side + end + + it "puts the second argument in all diagonal values" do + (0...@a.row_size).each do |i| + @a[i, i].should == @value + end + end + + it "fills all values not on the main diagonal with 0" do + (0...@a.row_size).each do |i| + (0...@a.column_size).each do |j| + if i != j + @a[i, j].should == 0 + end + end + end + end +end diff --git a/spec/ruby/library/matrix/shared/collect.rb b/spec/ruby/library/matrix/shared/collect.rb new file mode 100644 index 0000000000..852f7fd6cf --- /dev/null +++ b/spec/ruby/library/matrix/shared/collect.rb @@ -0,0 +1,26 @@ +require_relative '../fixtures/classes' +require 'matrix' + +describe :collect, shared: true do + before :all do + @m = Matrix[ [1, 2], [1, 2] ] + end + + it "returns an instance of Matrix" do + @m.send(@method){|n| n * 2 }.should be_kind_of(Matrix) + end + + it "returns a Matrix where each element is the result of the block" do + @m.send(@method) { |n| n * 2 }.should == Matrix[ [2, 4], [2, 4] ] + end + + it "returns an enumerator if no block is given" do + @m.send(@method).should be_an_instance_of(Enumerator) + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.ins.send(@method){1}.should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/shared/conjugate.rb b/spec/ruby/library/matrix/shared/conjugate.rb new file mode 100644 index 0000000000..d87658f855 --- /dev/null +++ b/spec/ruby/library/matrix/shared/conjugate.rb @@ -0,0 +1,20 @@ +require_relative '../fixtures/classes' +require 'matrix' + +describe :matrix_conjugate, shared: true do + it "returns a matrix with all entries 'conjugated'" do + Matrix[ [1, 2], [3, 4] ].send(@method).should == Matrix[ [1, 2], [3, 4] ] + Matrix[ [1.9, Complex(1,1)], [3, 4] ].send(@method).should == Matrix[ [1.9, Complex(1,-1)], [3, 4] ] + end + + it "returns empty matrices on the same size if empty" do + Matrix.empty(0, 3).send(@method).should == Matrix.empty(0, 3) + Matrix.empty(3, 0).send(@method).should == Matrix.empty(3, 0) + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.ins.send(@method).should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/shared/determinant.rb b/spec/ruby/library/matrix/shared/determinant.rb new file mode 100644 index 0000000000..9e0528c24b --- /dev/null +++ b/spec/ruby/library/matrix/shared/determinant.rb @@ -0,0 +1,38 @@ +require 'matrix' + +describe :determinant, shared: true do + it "returns the determinant of a square Matrix" do + m = Matrix[ [7,6], [3,9] ] + m.send(@method).should == 45 + + m = Matrix[ [9, 8], [6,5] ] + m.send(@method).should == -3 + + m = Matrix[ [9,8,3], [4,20,5], [1,1,1] ] + m.send(@method).should == 95 + end + + it "returns the determinant of a single-element Matrix" do + m = Matrix[ [2] ] + m.send(@method).should == 2 + end + + it "returns 1 for an empty Matrix" do + m = Matrix[ ] + m.send(@method).should == 1 + end + + it "returns the determinant even for Matrices containing 0 as first entry" do + Matrix[[0,1],[1,0]].send(@method).should == -1 + end + + it "raises an error for rectangular matrices" do + -> { + Matrix[[1], [2], [3]].send(@method) + }.should raise_error(Matrix::ErrDimensionMismatch) + + -> { + Matrix.empty(3,0).send(@method) + }.should raise_error(Matrix::ErrDimensionMismatch) + end +end diff --git a/spec/ruby/library/matrix/shared/equal_value.rb b/spec/ruby/library/matrix/shared/equal_value.rb new file mode 100644 index 0000000000..2b2311d49e --- /dev/null +++ b/spec/ruby/library/matrix/shared/equal_value.rb @@ -0,0 +1,33 @@ +require_relative '../fixtures/classes' +require 'matrix' + +describe :equal, shared: true do + before do + @matrix = Matrix[ [1, 2, 3, 4, 5], [2, 3, 4, 5, 6] ] + end + + it "returns true for self" do + @matrix.send(@method, @matrix).should be_true + end + + it "returns true for equal matrices" do + @matrix.send(@method, Matrix[ [1, 2, 3, 4, 5], [2, 3, 4, 5, 6] ]).should be_true + end + + it "returns false for different matrices" do + @matrix.send(@method, Matrix[ [42, 2, 3, 4, 5], [2, 3, 4, 5, 6] ]).should be_false + @matrix.send(@method, Matrix[ [1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7] ]).should be_false + @matrix.send(@method, Matrix[ [1, 2, 3], [2, 3, 4] ]).should be_false + end + + it "returns false for different empty matrices" do + Matrix.empty(42, 0).send(@method, Matrix.empty(6, 0)).should be_false + Matrix.empty(0, 42).send(@method, Matrix.empty(0, 6)).should be_false + Matrix.empty(0, 0).send(@method, Matrix.empty(6, 0)).should be_false + Matrix.empty(0, 0).send(@method, Matrix.empty(0, 6)).should be_false + end + + it "doesn't distinguish on subclasses" do + MatrixSub.ins.send(@method, Matrix.I(2)).should be_true + end +end diff --git a/spec/ruby/library/matrix/shared/identity.rb b/spec/ruby/library/matrix/shared/identity.rb new file mode 100644 index 0000000000..114f86e7b0 --- /dev/null +++ b/spec/ruby/library/matrix/shared/identity.rb @@ -0,0 +1,19 @@ +require_relative '../fixtures/classes' +require 'matrix' + +describe :matrix_identity, shared: true do + it "returns a Matrix" do + Matrix.send(@method, 2).should be_kind_of(Matrix) + end + + it "returns a n x n identity matrix" do + Matrix.send(@method, 3).should == Matrix.scalar(3, 1) + Matrix.send(@method, 100).should == Matrix.scalar(100, 1) + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.send(@method, 2).should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/shared/imaginary.rb b/spec/ruby/library/matrix/shared/imaginary.rb new file mode 100644 index 0000000000..d28ecc69f1 --- /dev/null +++ b/spec/ruby/library/matrix/shared/imaginary.rb @@ -0,0 +1,20 @@ +require_relative '../fixtures/classes' +require 'matrix' + +describe :matrix_imaginary, shared: true do + it "returns a matrix with the imaginary part of the elements of the receiver" do + Matrix[ [1, 2], [3, 4] ].send(@method).should == Matrix[ [0, 0], [0, 0] ] + Matrix[ [1.9, Complex(1,1)], [Complex(-2,0.42), 4] ].send(@method).should == Matrix[ [0, 1], [0.42, 0] ] + end + + it "returns empty matrices on the same size if empty" do + Matrix.empty(0, 3).send(@method).should == Matrix.empty(0, 3) + Matrix.empty(3, 0).send(@method).should == Matrix.empty(3, 0) + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.ins.send(@method).should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/shared/inverse.rb b/spec/ruby/library/matrix/shared/inverse.rb new file mode 100644 index 0000000000..c8a6b90da5 --- /dev/null +++ b/spec/ruby/library/matrix/shared/inverse.rb @@ -0,0 +1,38 @@ +require_relative '../fixtures/classes' +require 'matrix' + +describe :inverse, shared: true do + + it "returns a Matrix" do + Matrix[ [1,2], [2,1] ].send(@method).should be_an_instance_of(Matrix) + end + + it "returns the inverse of the Matrix" do + Matrix[ + [1, 3, 3], [1, 4, 3], [1, 3, 4] + ].send(@method).should == + Matrix[ + [7, -3, -3], [-1, 1, 0], [-1, 0, 1] + ] + end + + it "returns the inverse of the Matrix (other case)" do + Matrix[ + [1, 2, 3], [0, 1, 4], [5, 6, 0] + ].send(@method).should be_close_to_matrix([ + [-24, 18, 5], [20, -15, -4], [-5, 4, 1] + ]) + end + + it "raises a ErrDimensionMismatch if the Matrix is not square" do + ->{ + Matrix[ [1,2,3], [1,2,3] ].send(@method) + }.should raise_error(Matrix::ErrDimensionMismatch) + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.ins.send(@method).should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/shared/rectangular.rb b/spec/ruby/library/matrix/shared/rectangular.rb new file mode 100644 index 0000000000..3d9a0dfe8a --- /dev/null +++ b/spec/ruby/library/matrix/shared/rectangular.rb @@ -0,0 +1,18 @@ +require_relative '../fixtures/classes' +require 'matrix' + +describe :matrix_rectangular, shared: true do + it "returns [receiver.real, receiver.imag]" do + m = Matrix[ [1.2, Complex(1,2)], [Complex(-2,0.42), 4] ] + m.send(@method).should == [m.real, m.imag] + + m = Matrix.empty(3, 0) + m.send(@method).should == [m.real, m.imag] + end + + describe "for a subclass of Matrix" do + it "returns instances of that subclass" do + MatrixSub.ins.send(@method).each{|m| m.should be_an_instance_of(MatrixSub) } + end + end +end diff --git a/spec/ruby/library/matrix/shared/trace.rb b/spec/ruby/library/matrix/shared/trace.rb new file mode 100644 index 0000000000..57b89863f8 --- /dev/null +++ b/spec/ruby/library/matrix/shared/trace.rb @@ -0,0 +1,12 @@ +require 'matrix' + +describe :trace, shared: true do + it "returns the sum of diagonal elements in a square Matrix" do + Matrix[[7,6], [3,9]].trace.should == 16 + end + + it "returns the sum of diagonal elements in a rectangular Matrix" do + ->{ Matrix[[1,2,3], [4,5,6]].trace}.should raise_error(Matrix::ErrDimensionMismatch) + end + +end diff --git a/spec/ruby/library/matrix/shared/transpose.rb b/spec/ruby/library/matrix/shared/transpose.rb new file mode 100644 index 0000000000..89b1d025be --- /dev/null +++ b/spec/ruby/library/matrix/shared/transpose.rb @@ -0,0 +1,19 @@ +require_relative '../fixtures/classes' +require 'matrix' + +describe :matrix_transpose, shared: true do + it "returns a transposed matrix" do + Matrix[[1, 2], [3, 4], [5, 6]].send(@method).should == Matrix[[1, 3, 5], [2, 4, 6]] + end + + it "can transpose empty matrices" do + m = Matrix[[], [], []] + m.send(@method).send(@method).should == m + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.ins.send(@method).should be_an_instance_of(MatrixSub) + end + end +end diff --git a/spec/ruby/library/matrix/singular_spec.rb b/spec/ruby/library/matrix/singular_spec.rb new file mode 100644 index 0000000000..7bba36a54a --- /dev/null +++ b/spec/ruby/library/matrix/singular_spec.rb @@ -0,0 +1,31 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#singular?" do + it "returns true for singular matrices" do + m = Matrix[ [1,2,3], [3,4,3], [0,0,0] ] + m.singular?.should be_true + + m = Matrix[ [1,2,9], [3,4,9], [1,2,9] ] + m.singular?.should be_true + end + + it "returns false if the Matrix is regular" do + Matrix[ [0,1], [1,0] ].singular?.should be_false + end + + it "returns false for an empty 0x0 matrix" do + Matrix.empty(0,0).singular?.should be_false + end + + it "raises an error for rectangular matrices" do + -> { + Matrix[[1], [2], [3]].singular? + }.should raise_error(Matrix::ErrDimensionMismatch) + + -> { + Matrix.empty(3,0).singular? + }.should raise_error(Matrix::ErrDimensionMismatch) + end + +end diff --git a/spec/ruby/library/matrix/spec_helper.rb b/spec/ruby/library/matrix/spec_helper.rb new file mode 100644 index 0000000000..d44612981a --- /dev/null +++ b/spec/ruby/library/matrix/spec_helper.rb @@ -0,0 +1,35 @@ +class BeCloseToMatrixMatcher + def initialize(expected, tolerance = TOLERANCE) + SpecExpectation.matcher! rescue "Used with the balance_should_and_match branch of mspec" + @expected = Matrix[*expected] + @tolerance = tolerance + end + + def matches?(actual) + @actual = actual + return false unless @actual.is_a? Matrix + return false unless @actual.row_size == @expected.row_size + @actual.row_size.times do |i| + a, e = @actual.row(i), @expected.row(i) + return false unless a.size == e.size + a.size.times do |j| + return false unless (a[j] - e[j]).abs < @tolerance + end + end + true + end + + def failure_message + ["Expected #{@expected}", "to be within +/- #{@tolerance} of #{@actual}"] + end + + def negative_failure_message + ["Expected #{@expected}", "not to be within +/- #{@tolerance} of #{@actual}"] + end +end + +class Object + def be_close_to_matrix(expected, tolerance = TOLERANCE) + BeCloseToMatrixMatcher.new(expected, tolerance) + end +end diff --git a/spec/ruby/library/matrix/square_spec.rb b/spec/ruby/library/matrix/square_spec.rb new file mode 100644 index 0000000000..25d2d1ad9c --- /dev/null +++ b/spec/ruby/library/matrix/square_spec.rb @@ -0,0 +1,28 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#square?" do + + it "returns true when the Matrix is square" do + Matrix[ [1,2], [2,4] ].square?.should be_true + Matrix[ [100,3,5], [9.5, 4.9, 8], [2,0,77] ].square?.should be_true + end + + it "returns true when the Matrix has only one element" do + Matrix[ [9] ].square?.should be_true + end + + it "returns false when the Matrix is rectangular" do + Matrix[ [1, 2] ].square?.should be_false + end + + it "returns false when the Matrix is rectangular" do + Matrix[ [1], [2] ].square?.should be_false + end + + it "returns handles empty matrices" do + Matrix[].square?.should be_true + Matrix[[]].square?.should be_false + Matrix.columns([[]]).square?.should be_false + end +end diff --git a/spec/ruby/library/matrix/symmetric_spec.rb b/spec/ruby/library/matrix/symmetric_spec.rb new file mode 100644 index 0000000000..6f2a99276a --- /dev/null +++ b/spec/ruby/library/matrix/symmetric_spec.rb @@ -0,0 +1,29 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix.symmetric?" do + it "returns true for a symmetric Matrix" do + Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, 3), 5, 6]].symmetric?.should be_true + end + + it "returns true for a 0x0 empty matrix" do + Matrix.empty.symmetric?.should be_true + end + + it "returns false for an asymmetric Matrix" do + Matrix[[1, 2],[-2, 1]].symmetric?.should be_false + end + + it "raises an error for rectangular matrices" do + [ + Matrix[[0], [0]], + Matrix[[0, 0]], + Matrix.empty(0, 2), + Matrix.empty(2, 0), + ].each do |rectangular_matrix| + -> { + rectangular_matrix.symmetric? + }.should raise_error(Matrix::ErrDimensionMismatch) + end + end +end diff --git a/spec/ruby/library/matrix/t_spec.rb b/spec/ruby/library/matrix/t_spec.rb new file mode 100644 index 0000000000..6f1a5178e0 --- /dev/null +++ b/spec/ruby/library/matrix/t_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/transpose' + +describe "Matrix#transpose" do + it_behaves_like :matrix_transpose, :t +end diff --git a/spec/ruby/library/matrix/to_a_spec.rb b/spec/ruby/library/matrix/to_a_spec.rb new file mode 100644 index 0000000000..b5d55c5d67 --- /dev/null +++ b/spec/ruby/library/matrix/to_a_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#to_a" do + it "returns the array of arrays that describe the rows of the matrix" do + Matrix[].to_a.should == [] + Matrix[[]].to_a.should == [[]] + Matrix[[1]].to_a.should == [[1]] + Matrix[[1, 2], [3, 4]].to_a.should == [[1, 2],[3, 4]] + end +end diff --git a/spec/ruby/library/matrix/to_s_spec.rb b/spec/ruby/library/matrix/to_s_spec.rb new file mode 100644 index 0000000000..f529fe3bcd --- /dev/null +++ b/spec/ruby/library/matrix/to_s_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix#to_s" do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/library/matrix/tr_spec.rb b/spec/ruby/library/matrix/tr_spec.rb new file mode 100644 index 0000000000..e17bd790d7 --- /dev/null +++ b/spec/ruby/library/matrix/tr_spec.rb @@ -0,0 +1,7 @@ +require_relative '../../spec_helper' +require_relative 'shared/trace' +require 'matrix' + +describe "Matrix#tr" do + it_behaves_like :trace, :tr +end diff --git a/spec/ruby/library/matrix/trace_spec.rb b/spec/ruby/library/matrix/trace_spec.rb new file mode 100644 index 0000000000..290e7cb1f7 --- /dev/null +++ b/spec/ruby/library/matrix/trace_spec.rb @@ -0,0 +1,7 @@ +require_relative '../../spec_helper' +require_relative 'shared/trace' +require 'matrix' + +describe "Matrix#trace" do + it_behaves_like :trace, :trace +end diff --git a/spec/ruby/library/matrix/transpose_spec.rb b/spec/ruby/library/matrix/transpose_spec.rb new file mode 100644 index 0000000000..79600dd439 --- /dev/null +++ b/spec/ruby/library/matrix/transpose_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/transpose' + +describe "Matrix#transpose" do + it_behaves_like :matrix_transpose, :transpose +end diff --git a/spec/ruby/library/matrix/unit_spec.rb b/spec/ruby/library/matrix/unit_spec.rb new file mode 100644 index 0000000000..6a41d729c7 --- /dev/null +++ b/spec/ruby/library/matrix/unit_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative 'shared/identity' + +describe "Matrix.unit" do + it_behaves_like :matrix_identity, :unit +end diff --git a/spec/ruby/library/matrix/unitary_spec.rb b/spec/ruby/library/matrix/unitary_spec.rb new file mode 100644 index 0000000000..c214ee9b2f --- /dev/null +++ b/spec/ruby/library/matrix/unitary_spec.rb @@ -0,0 +1,32 @@ +require_relative '../../spec_helper' + +require 'matrix' + +describe "Matrix.unitary?" do + it "returns false for non unitary matrices" do + Matrix[[0, 1], [1, 2]].should_not.unitary? + Matrix[[0, Complex(0, 2)], [Complex(0, 2), 0]].should_not.unitary? + Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should_not.unitary? + end + + it "returns true for unitary matrices" do + Matrix[[0, Complex(0, 1)], [Complex(0, 1), 0]].should.unitary? + end + + it "returns true for unitary matrices with a Complex and a negative #imag" do + Matrix[[0, Complex(0, 1)], [Complex(0, -1), 0]].should.unitary? + end + + it "raises an error for rectangular matrices" do + [ + Matrix[[0], [0]], + Matrix[[0, 0]], + Matrix.empty(0, 2), + Matrix.empty(2, 0), + ].each do |rectangular_matrix| + -> { + rectangular_matrix.unitary? + }.should raise_error(Matrix::ErrDimensionMismatch) + end + end +end diff --git a/spec/ruby/library/matrix/upper_triangular_spec.rb b/spec/ruby/library/matrix/upper_triangular_spec.rb new file mode 100644 index 0000000000..2514294a80 --- /dev/null +++ b/spec/ruby/library/matrix/upper_triangular_spec.rb @@ -0,0 +1,24 @@ +require_relative '../../spec_helper' +require 'matrix' + +describe "Matrix.upper_triangular?" do + it "returns true for an upper triangular Matrix" do + Matrix[[1, 2, 3], [0, 2, 3], [0, 0, 3]].upper_triangular?.should be_true + Matrix.diagonal([1, 2, 3]).upper_triangular?.should be_true + Matrix[[1, 2], [0, 2], [0, 0], [0, 0]].upper_triangular?.should be_true + Matrix[[1, 2, 3, 4], [0, 2, 3, 4]].upper_triangular?.should be_true + end + + it "returns false for a non upper triangular square Matrix" do + Matrix[[0, 0], [1, 0]].upper_triangular?.should be_false + Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].upper_triangular?.should be_false + Matrix[[0, 0], [0, 0], [0, 0], [0, 1]].upper_triangular?.should be_false + Matrix[[0, 0, 0, 0], [1, 0, 0, 0]].upper_triangular?.should be_false + end + + it "returns true for an empty matrix" do + Matrix.empty(3,0).upper_triangular?.should be_true + Matrix.empty(0,3).upper_triangular?.should be_true + Matrix.empty(0,0).upper_triangular?.should be_true + end +end diff --git a/spec/ruby/library/matrix/vector/cross_product_spec.rb b/spec/ruby/library/matrix/vector/cross_product_spec.rb new file mode 100644 index 0000000000..c2698ade4c --- /dev/null +++ b/spec/ruby/library/matrix/vector/cross_product_spec.rb @@ -0,0 +1,14 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Vector#cross_product" do + it "returns the cross product of a vector" do + Vector[1, 2, 3].cross_product(Vector[0, -4, 5]).should == Vector[22, -5, -4] + end + + it "raises an error unless both vectors have dimension 3" do + -> { + Vector[1, 2, 3].cross_product(Vector[0, -4]) + }.should raise_error(Vector::ErrDimensionMismatch) + end +end diff --git a/spec/ruby/library/matrix/vector/each2_spec.rb b/spec/ruby/library/matrix/vector/each2_spec.rb new file mode 100644 index 0000000000..10d2fc404d --- /dev/null +++ b/spec/ruby/library/matrix/vector/each2_spec.rb @@ -0,0 +1,49 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Vector.each2" do + before :all do + @v = Vector[1, 2, 3] + @v2 = Vector[4, 5, 6] + end + + it "requires one argument" do + -> { @v.each2(@v2, @v2){} }.should raise_error(ArgumentError) + -> { @v.each2(){} }.should raise_error(ArgumentError) + end + + describe "given one argument" do + it "accepts an Array argument" do + a = [] + @v.each2([7, 8, 9]){|x, y| a << x << y} + a.should == [1, 7, 2, 8, 3, 9] + end + + it "raises a DimensionMismatch error if the Vector size is different" do + -> { @v.each2(Vector[1,2]){} }.should raise_error(Vector::ErrDimensionMismatch) + -> { @v.each2(Vector[1,2,3,4]){} }.should raise_error(Vector::ErrDimensionMismatch) + end + + it "yields arguments in sequence" do + a = [] + @v.each2(@v2){|first, second| a << [first, second]} + a.should == [[1, 4], [2, 5], [3, 6]] + end + + it "yield arguments in pairs" do + a = [] + @v.each2(@v2){|*pair| a << pair} + a.should == [[1, 4], [2, 5], [3, 6]] + end + + it "returns self when given a block" do + @v.each2(@v2){}.should equal(@v) + end + + it "returns an enumerator if no block given" do + enum = @v.each2(@v2) + enum.should be_an_instance_of(Enumerator) + enum.to_a.should == [[1, 4], [2, 5], [3, 6]] + end + end +end diff --git a/spec/ruby/library/matrix/vector/eql_spec.rb b/spec/ruby/library/matrix/vector/eql_spec.rb new file mode 100644 index 0000000000..eb2451b550 --- /dev/null +++ b/spec/ruby/library/matrix/vector/eql_spec.rb @@ -0,0 +1,16 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Vector#eql?" do + before do + @vector = Vector[1, 2, 3, 4, 5] + end + + it "returns true for self" do + @vector.eql?(@vector).should be_true + end + + it "returns false when there are a pair corresponding elements which are not equal in the sense of Kernel#eql?" do + @vector.eql?(Vector[1, 2, 3, 4, 5.0]).should be_false + end +end diff --git a/spec/ruby/library/matrix/vector/inner_product_spec.rb b/spec/ruby/library/matrix/vector/inner_product_spec.rb new file mode 100644 index 0000000000..1cf8771e04 --- /dev/null +++ b/spec/ruby/library/matrix/vector/inner_product_spec.rb @@ -0,0 +1,22 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Vector#inner_product" do + it "returns the inner product of a vector" do + Vector[1, 2, 3].inner_product(Vector[0, -4, 5]).should == 7 + end + + it "returns 0 for empty vectors" do + Vector[].inner_product(Vector[]).should == 0 + end + + it "raises an error for mismatched vectors" do + -> { + Vector[1, 2, 3].inner_product(Vector[0, -4]) + }.should raise_error(Vector::ErrDimensionMismatch) + end + + it "uses the conjugate of its argument" do + Vector[Complex(1,2)].inner_product(Vector[Complex(3,4)]).should == Complex(11, 2) + end +end diff --git a/spec/ruby/library/matrix/vector/normalize_spec.rb b/spec/ruby/library/matrix/vector/normalize_spec.rb new file mode 100644 index 0000000000..527c9260de --- /dev/null +++ b/spec/ruby/library/matrix/vector/normalize_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' +require 'matrix' + +describe "Vector#normalize" do + it "returns a normalized copy of the vector" do + x = 0.2672612419124244 + Vector[1, 2, 3].normalize.should == Vector[x, x * 2, x * 3] + end + + it "raises an error for zero vectors" do + -> { + Vector[].normalize + }.should raise_error(Vector::ZeroVectorError) + -> { + Vector[0, 0, 0].normalize + }.should raise_error(Vector::ZeroVectorError) + end +end diff --git a/spec/ruby/library/matrix/zero_spec.rb b/spec/ruby/library/matrix/zero_spec.rb new file mode 100644 index 0000000000..68e8567c26 --- /dev/null +++ b/spec/ruby/library/matrix/zero_spec.rb @@ -0,0 +1,52 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require 'matrix' + +describe "Matrix.zero" do + it "returns an object of type Matrix" do + Matrix.zero(3).should be_kind_of(Matrix) + end + + it "creates a n x n matrix" do + m3 = Matrix.zero(3) + m3.row_size.should == 3 + m3.column_size.should == 3 + + m8 = Matrix.zero(8) + m8.row_size.should == 8 + m8.column_size.should == 8 + end + + it "initializes all cells to 0" do + size = 10 + m = Matrix.zero(size) + + (0...size).each do |i| + (0...size).each do |j| + m[i, j].should == 0 + end + end + end + + describe "for a subclass of Matrix" do + it "returns an instance of that subclass" do + MatrixSub.zero(3).should be_an_instance_of(MatrixSub) + end + end +end + +describe "Matrix.zero?" do + it "returns true for empty matrices" do + Matrix.empty.should.zero? + Matrix.empty(3,0).should.zero? + Matrix.empty(0,3).should.zero? + end + + it "returns true for matrices with zero entries" do + Matrix.zero(2,3).should.zero? + end + + it "returns false for matrices with non zero entries" do + Matrix[[1]].should_not.zero? + end +end |
