summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Wolfsteller <felix.wolfsteller@gmail.com>2020-12-21 18:28:55 +0100
committerMarc-Andre Lafortune <github@marc-andre.ca>2021-01-21 13:22:25 -0500
commite34f51fe609d6be48b655695dd8c15e17694242e (patch)
treebb623e8537aae815ad22cf73340062ff33372415
parent0130e17a410d60a10e7041ce98748b8de6946971 (diff)
[ruby/matrix] Add `Matrix#rotate_entries` [#19]
Co-authored-by: Marc-André Lafortune <github@marc-andre.ca>
-rw-r--r--lib/matrix.rb29
-rw-r--r--test/matrix/test_matrix.rb56
2 files changed, 85 insertions, 0 deletions
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