How to rotate the positions of a matrix by 90 degrees

I have a 5x5 matrix of values. I'm looking for a simple formula that I can use to rotate the position of the values (not the values themselves) 90 degrees within the matrix.

For example, here is the original matrix:

01 02 03 04 05
06 07 08 09 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25

and then when the position of the values are rotated 90 degrees, it would look like this:

21 16 11 06 01
22 17 12 07 02
23 18 13 08 03
24 19 14 09 04
25 20 15 10 05

I found this post and this one, and I'm sure the answer I'm after is in there somewhere, but I've been out of university for quite a few years and am having trouble following the algorithm.

I need this for a C# program I'm writing and will be using Math.Net Numberics. I'm hoping there is just a simple rotation matrix/vector I can use to multiply my matrix with that will give me the result I'm after. Any suggestions are appreciated.


Solution 1:

The idea here is to find out where the values get shifted to. A location is given by two indices $(i,j)$. How to transform the indices?

Let us first try to rotate the indices around the center element:

Matrix Elements   Coordinates
01 02 03 04 05    (1,5) (2,5) (3,5) (4,5) (5,5)
06 07 08 09 10    (1,4) (2,4) (3,4) (4,4) (5,4)
11 12(13)14 15    (1,3) (2,3)((3,3))(4,3) (5,3)
16 17 18 19 20    (1,2) (2,2) (3,2) (4,2) (5,2)
21 22 23 24 25    (1,1) (2,1) (3,1) (4,1) (5,1)

Rotation by $\theta = -90^\circ$ around the origin is performed by $$ R = \left( \begin{array}{rr} \cos \theta & -\sin \theta \\ \sin \theta & \cos \theta \end{array} \right) = \left( \begin{array}{rr} 0 & 1 \\ -1 & 0 \end{array} \right) $$

Plus we need coordinate translations before and after the rotation, because our index center is $(3,3)$ and not $(0,0)$, so we need homogeneous coordinates to express translations by $(\Delta x, \Delta y)$ in matrix form. First we extend the rotation to homogeneous coordinates $$ R = \left( \begin{array}{rr} 0 & 1 & 0 \\ -1 & 0 & 0 \\ 0 & 0 & 1 \end{array} \right) $$ and the translation is $$ T = \left( \begin{array}{rr} 1 & 0 & \Delta x \\ 0 & 1 & \Delta y \\ 0 & 0 & 1 \end{array} \right) $$ It acts on coordinates like this: $$ \left( \begin{array}{c} x' \\ y' \\ 1 \end{array} \right) = \left( \begin{array}{ccc} 1 & 0 & \Delta x \\ 0 & 1 & \Delta y \\ 0 & 0 & 1 \end{array} \right) \left( \begin{array}{c} x \\ y \\ 1 \end{array} \right) = \left( \begin{array}{c} x + \Delta x \\ y + \Delta y \\ 1 \end{array} \right) $$ Combining these operations we get: \begin{align} A &= T^{-1} R T \\ &= \left( \begin{array}{rrr} 1 & 0 & 3\\ 0 & 1 & 3 \\ 0 & 0 & 1 \end{array} \right) \left( \begin{array}{rrr} 0 & 1 & 0\\ -1 & 0 & 0 \\ 0 & 0 & 1 \end{array} \right) \left( \begin{array}{rrr} 1 & 0 & -3 \\ 0 & 1 & -3 \\ 0 & 0 & 1 \end{array} \right) \\ &= \left( \begin{array}{rrr} 1 & 0 & 3 \\ 0 & 1 & 3 \\ 0 & 0 & 1 \end{array} \right) \left( \begin{array}{rrr} 0 & 1 & -3 \\ -1 & 0 & 3 \\ 0 & 0 & 1 \end{array} \right) \\ &= \left( \begin{array}{rrr} 0 & 1 & 0 \\ -1 & 0 & 6 \\ 0 & 0 & 1 \end{array} \right) \end{align} The final step is to change the $y$ order: $y' = 6 - y$:

Matrix Elements   Coordinates
01 02 03 04 05    (1,1) (2,1) (3,1) (4,1) (5,1)
06 07 08 09 10    (1,2) (2,2) (3,2) (4,2) (5,2)
11 12(13)14 15    (1,3) (2,3)((3,3))(4,3) (5,3)
16 17 18 19 20    (1,4) (2,4) (3,4) (4,4) (5,4)
21 22 23 24 25    (1,5) (2,5) (3,5) (4,5) (5,5)

This affine transformation can be written in matrix form as $$ Y = \left( \begin{array}{rrr} 1 & 0 & 0 \\ 0 & -1 & 6 \\ 0 & 0 & 1 \end{array} \right) = Y^{-1} $$ This leads to \begin{align} B & = Y T^{-1} R T Y \\ &= \left( \begin{array}{rrr} 1 & 0 & 0 \\ 0 & -1 & 6 \\ 0 & 0 & 1 \end{array} \right) \left( \begin{array}{rrr} 0 & 1 & 0 \\ -1 & 0 & 6 \\ 0 & 0 & 1 \end{array} \right) \left( \begin{array}{rrr} 1 & 0 & 0 \\ 0 & -1 & 6 \\ 0 & 0 & 1 \end{array} \right) \\ &= \left( \begin{array}{rrr} 1 & 0 & 0 \\ 0 & -1 & 6 \\ 0 & 0 & 1 \end{array} \right) \left( \begin{array}{rrr} 0 & -1 & 6 \\ -1 & 0 & 6 \\ 0 & 0 & 1 \end{array} \right) \\ &= \left( \begin{array}{rrr} 0 & -1 & 6 \\ 1 & 0 & 0 \\ 0 & 0 & 1 \end{array} \right) \end{align} A matrix element at indices $(i,j)$ ($i$-th row, $j$-th column) has coordinates $(j, i)$. Thus the index transformation $(i,j) \to (i', j')$ is $$ \left( \begin{array}{r} j' \\ i' \\ 1 \end{array} \right) = \left( \begin{array}{rrr} 0 & -1 & 6 \\ 1 & 0 & 0 \\ 0 & 0 & 1 \end{array} \right) \left( \begin{array}{r} j \\ i \\ 1 \end{array} \right) $$ or $$ \begin{align} i' &= j \\ j' &= 6 - i \end{align} $$

A possible algorithm to calculate the rotated matrix b from a given matrix a is:

(1,5).each do |i| 
  (1,5).each do |j| 
    b[j, 6-i] = a[i, j]
  end
end

Here is some test code online: (link) Click the tab marked "Execute" to run it.

Example:

Let us do the calculation for the 18-th element:

Matrix Elements   Matrix Indices
01 02 03 04 05    (1,1) (1,2) (1,3) (1,4) (1,5)
06 07 08 09 10    (2,1) (2,2) (2,3) (2,4) (2,5)
11 12 13 14 15    (3,1) (3,2) (3,3) (3,4) (3,5)
16 17(18)19 20    (4,1) (4,2)((4,3))(4,4) (4,5)
21 22 23 24 25    (5,1) (5,2) (5,3) (5,4) (5,5)

This entry is the matrix element $a_{4 3}$. The indices are $(i, j) = (4,3)$.

The rotated matrix is

21 16 11 06 01
22 17 12 07 02
23(18)13 08 03
24 19 14 09 04
25 20 15 10 05

The value is now at $b_{3 2}$, thus $(i', j') = (3,2)$. This agrees with the found transformation.

What did the transformation do? First, if the lower left element of the original matrix (the one containing value $21$) is at coordinates $(x,y) = (1,1)$, we want to have element $18$ at coordinates $(x, y) = (3,2)$. So original $(i,j) = (4,3)$ is interpreted as coordinates $(x,y)=(3,4)$ and flipped by $Y$ to coordinates $(3,2)$. Then $T$ translates it to coordinates $(0,-1)$, which is fine as it sits under the central element (center now at $(0,0)$). $R$ rotates it to $(-1,0)$, which is left from the central element (center now at $(0,0)$), fine again. $T^{-1}$ translates it back to $(x'.y')=(2,3)$ which is still left to the center. The final $Y^{-1} = Y$ changes nothing, as we are on the middle row. Final translation to matrix indices gives $(i',j') = (3,2)$.

Solution 2:

Transpose the matrix, then reverse the order of the columns. So $$M\mapsto M^T\begin{bmatrix}0&0&\cdots&0&1\\0&0&\cdots&1&0\\\vdots&\vdots&&\vdots&\vdots\\0&1&\cdots&0&0\\1&0&\cdots&0&0\end{bmatrix}$$ For instance $$\begin{bmatrix}a&b&c\\d&e&f\\g&h&i\end{bmatrix}\mapsto\begin{bmatrix}a&b&c\\d&e&f\\g&h&i\end{bmatrix}^T\begin{bmatrix}0&0&1\\0&1&0\\1&0&0\end{bmatrix}=\begin{bmatrix}a&d&g\\b&e&h\\c&f&i\end{bmatrix}\begin{bmatrix}0&0&1\\0&1&0\\1&0&0\end{bmatrix}=\begin{bmatrix}g&d&a\\h&e&b\\i&f&c\end{bmatrix}$$

Solution 3:

A rotation by 90 degrees can be accomplished by two reflections at a 45 degree angle so if you take the transpose of the matrix and then multiply it by the permutation matrix with all ones on the minor diagonal and all zeros everywhere else you will get a clockwise rotation by 90 degrees. For a 2x2 matrix this would look like:

A B
C D

Transpose:

A C
B D

Permute, reversing order of columns:

C A
D B

However, in a programming context, it would probably be better to solve this problem by moving the data around.