Some time ago I invented an algorithm for in-place matrix transposition using rotations.
A matrix of size N×M is represented as a one-dimensional array of size N*M, which is also the future storage for the corresponding transposed M×N matrix.
The algorithm moves an element to its proper position in the representation for the transposed matrix rotating the sub-array of the array 1 element right, starting at the correct and ending at the current position of the element.
Let matrix be the array of size N*M, where N and M are the number of rows and columns in the original matrix (and the number of columns and rows in the transposed). Array indices are from 0 to N*M-1.
Let dst be the proper position for the element in the array for the transposed matrix, src — its current position, src_inc is the value addet to src to point to the "current position" of the next element to be moved. The algorithm starts with dst = 1, src_inc = M and src = dst + src_inc - 1 (which is equal to M) (The element at the 0-th position is already in its right place). After the first rotation, we increment dst by 1 and src by src_inc (which is M) until dst points to an element which should not be moved. This happens when (dst + 1) % N is 0. In this case we skip the element (incrementing dst again), decrease src_inc by one and restore the initial relation between src and dst — src = dst + src_inc - 1.
Let me, instead of writing a pseudo-code, show the C++ code and add a state of the array before each rotation (plus the final result)
#include <algorithm>
template<typename T>
void inplace_transpose_using_rotations(T* matrix, int N, int M)
{
int dst = 1;
int src_inc = M;
int src = dst + src_inc - 1;
while (src < N*M && dst < src)
{
std::rotate(matrix + dst, matrix + src, matrix + src + 1); // rotate right for 1 position
if ((dst + 1) % N != 0) {
dst += 1;
src += src_inc;
} else {
dst += 2;
src_inc -= 1;
src = dst + src_inc - 1;
}
}
}
(https://wandbox.org/permlink/XAWE1Fn64SxvEvth)
Original 3×5 matrix:
11 12 13 14 15
21 22 23 24 25
31 32 33 34 35
The trace (the first row is indices, the matrix is represented linearly, dst and src to the right are shown before the rotation, the result of the rotation is on the next line):
00 01 02 03 04 05 06 07 08 09 10 11 12 13 14
11 12 13 14 15 21 22 23 24 25 31 32 33 34 35 | dst = 01, src = 05
11 21 12 13 14 15 22 23 24 25 31 32 33 34 35 | dst = 02, src = 10
11 21 31 12 13 14 15 22 23 24 25 32 33 34 35 | dst = 04, src = 07
11 21 31 12 22 13 14 15 23 24 25 32 33 34 35 | dst = 05, src = 11
11 21 31 12 22 32 13 14 15 23 24 25 33 34 35 | dst = 07, src = 09
11 21 31 12 22 32 13 23 14 15 24 25 33 34 35 | dst = 08, src = 12
11 21 31 12 22 32 13 23 33 14 15 24 25 34 35 | dst = 10, src = 11
11 21 31 12 22 32 13 23 33 14 24 15 25 34 35 | dst = 11, src = 13
11 21 31 12 22 32 13 23 33 14 24 34 15 25 35 | final array
(the code producing the trace https://wandbox.org/permlink/3nhlwYoSz5GnWuUP)
And transposed matrix (reinterpretation of the array as a representation for a 5×3 matrix):
11 21 31
12 22 32
13 23 33
14 24 34
15 25 35
The algorithm is not optimal, it does
swaps (assuming the rotation is implemented as a chain of swaps), but it is short and seems to work.
However, I couldn't prove why it should work. I was just curious to try to transpose a matrix using rotations instead of chain of swaps following cycles and discovered that there is a relatively simple law how to select the next sub-array for rotation. Is this algorithm published anywhere?