From e34f51fe609d6be48b655695dd8c15e17694242e Mon Sep 17 00:00:00 2001 From: Felix Wolfsteller Date: Mon, 21 Dec 2020 18:28:55 +0100 Subject: [ruby/matrix] Add `Matrix#rotate_entries` [#19] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marc-André Lafortune --- lib/matrix.rb | 29 ++++++++++++++++++++++++ test/matrix/test_matrix.rb | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/lib/matrix.rb b/lib/matrix.rb index 8c636f61e8..0a17678972 100644 --- a/lib/matrix.rb +++ b/lib/matrix.rb @@ -1458,6 +1458,35 @@ class Matrix rank end + # + # Returns a new matrix with rotated elements. + # The argument specifies the rotation (defaults to `:clockwise`): + # * :clockwise, 1, -3, etc.: "turn right" - first row becomes last column + # * :half_turn, 2, -2, etc.: first row becomes last row, elements in reverse order + # * :counter_clockwise, -1, 3: "turn left" - first row becomes first column + # (but with elements in reverse order) + # + # m = Matrix[ [1, 2], [3, 4] ] + # r = m.rotate_entries(:clockwise) + # # => Matrix[[3, 1], [4, 2]] + # + def rotate_entries(rotation = :clockwise) + rotation %= 4 if rotation.respond_to? :to_int + + case rotation + when 0 + dup + when 1, :clockwise + new_matrix @rows.transpose.each(&:reverse!), row_count + when 2, :half_turn + new_matrix @rows.map(&:reverse).reverse!, column_count + when 3, :counter_clockwise + new_matrix @rows.transpose.reverse!, row_count + else + raise ArgumentError, "expected #{rotation.inspect} to be one of :clockwise, :counter_clockwise, :half_turn or an integer" + end + end + # Returns a matrix with entries rounded to the given precision # (see Float#round) # diff --git a/test/matrix/test_matrix.rb b/test/matrix/test_matrix.rb index 04e8a5bf34..53887729ef 100644 --- a/test/matrix/test_matrix.rb +++ b/test/matrix/test_matrix.rb @@ -829,4 +829,60 @@ class TestMatrix < Test::Unit::TestCase assert_same obj1, obj2 RUBY end + + def test_rotate_with_symbol + assert_equal(Matrix[[4, 1], [5, 2], [6, 3]], @m1.rotate_entries) + assert_equal(@m1.rotate_entries, @m1.rotate_entries(:clockwise)) + assert_equal(Matrix[[4, 1], [5, 2], [6, 3]], + @m1.rotate_entries(:clockwise)) + assert_equal(Matrix[[3, 6], [2, 5], [1, 4]], + @m1.rotate_entries(:counter_clockwise)) + assert_equal(Matrix[[6, 5, 4], [3, 2, 1]], + @m1.rotate_entries(:half_turn)) + assert_equal(Matrix[[6, 5, 4], [3, 2, 1]], + @m1.rotate_entries(:half_turn)) + assert_equal(Matrix.empty(0,2), + @e1.rotate_entries(:clockwise)) + assert_equal(Matrix.empty(0,2), + @e1.rotate_entries(:counter_clockwise)) + assert_equal(Matrix.empty(2,0), + @e1.rotate_entries(:half_turn)) + assert_equal(Matrix.empty(0,3), + @e2.rotate_entries(:half_turn)) + end + + def test_rotate_with_numeric + assert_equal(Matrix[[4, 1], [5, 2], [6, 3]], + @m1.rotate_entries(1)) + assert_equal(@m2.rotate_entries(:half_turn), + @m2.rotate_entries(2)) + assert_equal(@m2.rotate_entries(:half_turn), + @m1.rotate_entries(2)) + assert_equal(@m1.rotate_entries(:counter_clockwise), + @m1.rotate_entries(3)) + assert_equal(@m1, + @m1.rotate_entries(4)) + assert_equal(@m1, + @m1.rotate_entries(4)) + assert_not_same(@m1, + @m1.rotate_entries(4)) + assert_equal(@m1.rotate_entries(:clockwise), + @m1.rotate_entries(5)) + assert_equal(Matrix.empty(0,2), + @e1.rotate_entries(1)) + assert_equal(@e2, + @e2.rotate_entries(2)) + assert_equal(@e2.rotate_entries(1), + @e2.rotate_entries(3)) + assert_equal(@e2.rotate_entries(:counter_clockwise), + @e2.rotate_entries(-1)) + assert_equal(@m1.rotate_entries(:counter_clockwise), + @m1.rotate_entries(-1)) + assert_equal(Matrix[[6, 5, 4], [3, 2, 1]], + @m1.rotate_entries(-2)) + assert_equal(@m1, + @m1.rotate_entries(-4)) + assert_equal(@m1.rotate_entries(-1), + @m1.rotate_entries(-5)) + end end -- cgit v1.2.3