Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions lib/matrix.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1435,6 +1435,58 @@ def rank_e
rank
end

#
# Returns a new matrix where elements are rotated.
# The +quarter_turns+ option defines the direction of the rotation (defaults
# to :clockwise):
# * :clockwise: "turn right" - first row becomes last column
# * :counter_clockwise: "turn left" - first row becomes first column
# (but with elements in reverse order)
# * :half_turn: first row becomes last row, elements in reverse order
#
# m = Matrix[ [1, 2], [3, 4] ]
# r = m.rotate_entries(:clockwise)
# # => Matrix[[3, 1], [4, 2]]
#
def rotate_entries(quarter_turns=:clockwise)
if quarter_turns.is_a? Integer
quarter_turns = case quarter_turns % 4
when 0
:dup
when 1
:clockwise
when 2
:half_turn
when 3
:counter_clockwise
end
end

if empty?
case quarter_turns
when :clockwise, :counter_clockwise
return Matrix.empty(column_count, row_count)
when :half_turn, :dup
return Matrix.empty(row_count, column_count)
else
raise ArgumentError, "expected #{quarter_turns.inspect} to be one of :clockwise, :counter_clockwise, :half_turn or an integer (assuming clockwise rotation)"
end
end

case quarter_turns
when :dup
self.dup
when :clockwise
Matrix[*column_vectors.map{|c| c.to_a.reverse}]
when :counter_clockwise
Matrix[*column_vectors.map{|c| c}.reverse]
when :half_turn
Matrix[*row_vectors.map{|c| c.to_a.reverse}.reverse]
else
raise ArgumentError, "expected #{quarter_turns.inspect} to be one of :clockwise, :counter_clockwise, :half_turn or an integer (assuming clockwise rotation)"
end
end

# Returns a matrix with entries rounded to the given precision
# (see Float#round)
#
Expand Down
56 changes: 56 additions & 0 deletions test/matrix/test_matrix.rb
Original file line number Diff line number Diff line change
Expand Up @@ -821,4 +821,60 @@ def test_ractor
end.take
assert_same obj1, obj2
end if defined?(Ractor)

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