# What is the right way to rotate an array?

Suppose I have an array, not necessarily square:

a = $\left( \begin{array}{ccc} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{array} \right)$

I want to rotate it like one of these:

$\left( \begin{array}{ccc} 3 & 6 & 9 \\ 2 & 5 & 8 \\ 1 & 4 & 7 \end{array} \right)$     $\left( \begin{array}{ccc} 7 & 4 & 1 \\ 8 & 5 & 2 \\ 9 & 6 & 3 \end{array} \right)$     $\left( \begin{array}{ccc} 9 & 8 & 7 \\ 6 & 5 & 4 \\ 3 & 2 & 1 \end{array} \right)$

I have been using:

a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

Reverse[a, {2}]\[Transpose]

Reverse[a\[Transpose], {2}]

Reverse[a, {1, 2}]


Is there a cleaner, faster, or otherwise better way to do it?

I am more interested in a general solution rather than a compiled solution for an integer array, but if you have a nice compiled approach please make it work on version 7.

-
I know an uglier, slower or otherwise poorer solution: ImageRotate[Image[m], \[Pi]/2] // ImageData – Sjoerd C. de Vries Mar 3 '12 at 0:09
@Sjoerd you should have saved that for the an obfuscated code contest. :-) – Mr.Wizard Mar 3 '12 at 0:23
Table[Rotate[a // MatrixForm, k Degree], {k, {90, -90, 180}}] – DavidC Mar 3 '12 at 0:40
@David If you want to get away with that you'll need to counter-rotate the individual elements. :^) – Mr.Wizard Mar 3 '12 at 0:46
Like this? g[list_, theta_] := Rotate[#, -theta Degree] & /@ list h[m_, theta_] := Rotate[MatrixForm[g[#, theta] & /@ m], theta Degree] h[a, 90] h[a, -90] h[a, 180] – DavidC Mar 3 '12 at 1:10

I realise that this doesn't fully answer the question, but for the special case of square matrices, there's already a suitable function: ImageMorphologicalOperationsDumpSquareMatrixRotate (which, no doubt, is how Sjoerd's suggestion works internally). This is undocumented, of course!

The implementation is the following (modulo some bugs I've fixed--i and j were not localized in the original, leading to problems if you want to rotate a matrix containing these symbols, there were no conditions on the arguments, and [admittedly, a minor point] the rotation matrix was numericized only after inversion, which is inefficient):

SquareMatrixRotate[mat_?MatrixQ, angle_?NumericQ] /; Equal @@ Dimensions[mat] :=
Module[{
inv, dim, ct,
i, j,
ii, jj
},
inv = Inverse@RotationMatrix@N[angle];
dim = First@Dimensions[mat];
ct = (dim + 1)/2;
Table[
{ii, jj} = MapThread[
Clip[#1, {1, #2}, {1, 1}] &,
{Round[inv.{i - ct, j - ct} + {ct, ct}], {dim, dim}}
];
mat[[ii, jj]],
{i, dim}, {j, dim}
]
]


Is it in any sense better than your existing methods? Well, you can rotate by an arbitrary angle, although the results may not make much sense for angles for which no "natural" rotation is possible. Other than that, I would say no: personally, I would have used Reverse as you did.

-
+1 for Mathematica spelunking. – Mr.Wizard Mar 3 '12 at 1:01

I liked David's humorous method enough that I wondered what it would take to make it convincing. This is what I came up with:

a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

Table[
DisplayForm @
RowBox[{"(", "\[NoBreak]",
Rotate[Map[Rotate[#, -k] &, a, {2}] // Grid, k],
"\[NoBreak]", ")"}],
{k, {90 Degree, -90 Degree, 180 Degree}}
] // Row


-
Much better than mine. You even got the braces right! – DavidC Mar 3 '12 at 1:14
@David hide this one behind ReadProtected and befuddle novice users to no end. – Mr.Wizard Mar 3 '12 at 1:15
Good idea. I assume that ReadProtected hides the source code from prying eyes. – DavidC Mar 3 '12 at 1:35

FindPermutation may be useful as part of a yet-to-be-found general method as follows (using your examples as templates for the three rotations):

  a = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
b = (Reverse[a, {2}] // Transpose );
c = (Reverse[a // Transpose, {2}]);
d = Reverse[a, {1, 2}];
cntrclckws = FindPermutation[Flatten@a, Flatten@b];
clckws = Cycles[Reverse /@ RotateLeft /@ cntrclckws[[1]]];
flp = PermutationProduct[clckws, clckws]


With

  m = {{r, s, t}, {u, v, w}, {x, y, z}};


and

  {Permute[Flatten@m, cntrclckws] // Partition[#, 3] &,
Permute[Flatten@m, clckws] // Partition[#, 3] &,
Permute[Flatten@m, flp] // Partition[#, 3] &}


one can "rotate" m to :

 {{{t, w, z}, {s, v, y}, {r, u, x}},
{{x, u, r}, {y, v, s}, {z, w, t}},
{{z, y, x}, {w, v, u}, {t, s, r}}}

-
BLeerghahahrhhggghghghhhh puajjj (+1 due to something) – Rojo Mar 3 '12 at 2:57
@Rojo um... WHAT? kguler I actually was looking for a "better" method as there are so many functions in Mathematica that it seemed reasonable I have overlooked one that does exactly this, perhaps with some obscure option or by clever usage. – Mr.Wizard Mar 3 '12 at 6:57

I don't think of this as rotating in the sense of an angle, rather, the sequence of positions around the matrix. So I came up with a rather different solution.

First let's create the simple case:

test[3, 3] = Array[a, {3, 3}]


{{a[1, 1], a[1, 2], a[1, 3]}, {a[2, 1], a[2, 2], a[2, 3]}, {a[3, 1], a[3, 2], a[3, 3]}}

This is the list of positions that rotates

snake = Join[Table[{1, i}, {i, 3}], {{2, 3}},
Table[{3, i}, {i, 3, 1, -1}], {{2, 1}}]


{{1, 1}, {1, 2}, {1, 3}, {2, 3}, {3, 3}, {3, 2}, {3, 1}, {2, 1}}

RotateLeft[snake, 1]


{{1, 2}, {1, 3}, {2, 3}, {3, 3}, {3, 2}, {3, 1}, {2, 1}, {1, 1}}

output = test[3, 3];

ReplacePart[output,
1] -> (test[3, 3][[Sequence @@ #]] & /@ snake)] ] // MatrixForm


$$\left( \begin{array}{ccc} a[2,1] & a[1,1] & a[1,2] \\ a[3,1] & a[2,2] & a[1,3] \\ a[3,2] & a[3,3] & a[2,3] \\ \end{array} \right)$$

Demonstrating the cases asked for in the question:

aa = Partition[Range[9], 3];

rotateMatrix[aa, -2] // MatrixForm


$$\left( \begin{array}{ccc} 3 & 6 & 9 \\ 2 & 5 & 8 \\ 1 & 4 & 7 \\ \end{array} \right)$$

rotateMatrix[aa, 2] // MatrixForm


$$\left( \begin{array}{ccc} 7 & 4 & 1 \\ 8 & 5 & 2 \\ 9 & 6 & 3 \\ \end{array} \right)$$

rotateMatrix[aa, 4] // MatrixForm


$$\left( \begin{array}{ccc} 9 & 8 & 7 \\ 6 & 5 & 4 \\ 3 & 2 & 1 \\ \end{array} \right)$$

We can generalise this to the case where the matrix has either three rows or three columns pretty easily.

rotateMatrix[a_?MatrixQ, j_Integer] /; Length[a] == 3 || Length[a[[1]]] == 3 :=
Module[{output = a, m = Length[a], n = Length[a[[1]]], snake},
snake = Join[Table[{1, i}, {i, n}], Table[{i, n}, {i, 2, m - 1}],
Table[{m, i}, {i, n, 1, -1}], Table[{i, 1}, {i, m - 1, 2, -1}]];
ReplacePart[output,
Thread[RotateLeft[snake, j] -> (a[[Sequence @@ #]] & /@ snake)] ]
]

rotateMatrix[test[3, 3], 1] // MatrixForm


$$\left( \begin{array}{ccc} a[2,1] & a[1,1] & a[1,2] \\ a[3,1] & a[2,2] & a[1,3] \\ a[3,2] & a[3,3] & a[2,3] \\ \end{array} \right)$$

test[3, 4] = Array[b, {3, 4}]


{{b[1, 1], b[1, 2], b[1, 3], b[1, 4]}, {b[2, 1], b[2, 2], b[2, 3], b[2, 4]}, {b[3, 1], b[3, 2], b[3, 3], b[3, 4]}}

It works for both positive (rotate clockwise) and negative (rotate anti-clockwise) integers as the second argument.

rotateMatrix[test[3, 4], -2] // MatrixForm


$$\left( \begin{array}{cccc} b[1,3] & b[1,4] & b[2,4] & b[3,4] \\ b[1,2] & b[2,2] & b[2,3] & b[3,3] \\ b[1,1] & b[2,1] & b[3,1] & b[3,2] \\ \end{array} \right)$$

It would be possible to generalise this further to cases where neither the number of rows nor the number of columns is 3. One would have to specify what happens to the "inner rings" of positions that rotate. For example, in a 5 by 5 matrix, does the inner ring rotate three-fifths of the number of positions that the outer ring does?

-
This is not really what I had in mind, but it is an interesting interpretation of my question. +1 – Mr.Wizard Mar 4 '12 at 2:20