Dec 312012
 

Given a M*N order matrix, which is stored in an array in a row-major order. eg. if the  matrix is of order 2*4 with below elements

a b c d 
e f g h

Then it is stored in a one dimensional array as below:

a b c d e f g h

mat_transpose

Write a program which will convert this matrix to its transpose.

mat_transpose_1


Solution:

If the Matrix is symmetric (i.e number of rows & columns are equal), then calculating transpose is very easy. we just need to traverse the array and swap element at (i,j) position with element at (j,i) position.

mat_transpose_2

The code is also quite simple:

#define M 4
#define N 4
void transpose(int arr[M][N])
{
    for(int i=0; i<M;i++)
    {
        for(int j=0; i<N; j++)
        {
            int temp = arr[i][j];
            arr[i][j] = arr[j][i];
            arr[j][i] = temp;
        }
    }
}

The problem comes when the 2-dim array is not symmetric. Because in that case if an element goes at position (i, j), then is not necessary that the other element will come at it position. Hence, swapping is not possible.

Like in the above example: element ‘c‘ is moving from position (0, 2) to (2, 0).. but the position (2,0) was not present in the original array.. and hence there is no element to swap from that position.

In fact in case of a-symmetric arrays, its the cycle of element which is shifted. Lets look at it more closely. The below table shows the old position and new position of all the element in matrix:

mat_transpose_3

Note that the first and last elements stay in their original location. We can easily see the transformation forms new swapping cycles.

Element at 1 (b) moves to 2
Element at 2 (c) moves to 4
Element at 4 (e) moves to 1

Hence 1 -> 2 -> 4 -> 1 is one swap cycle

Another swap cycle is: 3 -> 6 -> 5 -> 3

And first and last element remains at their original positions. In case of any asymmetric matrix these cycles will be present (not the same order, but such cycles will be there). Now we have to move around the cycle. So we need to find a way to calculate the new position from the old position.

mat_transpose_4

Hence New position (in one dim array) can be found from old position and old i value. We can further remove the dependency on oi (because we are only given a one dimensional array) take modulo (N-1) on both sides of above result:

np mod (N-1) = (op*m - oi * (N-1)) mod (N-1)
             = (op*m) mod (N-1) - (oi * (N-1) mod (N-1) )
      Now, (N-1) mod (N-1) = 0, Hence
np mod (N-1) = (op*m) mod (N-1)

Now since np is always < (N-1) .. there are only N elements in the array, and last element is never considered because it is already at its right position. Hence

np mod (N-1) = np

therefore

np =  (op*m) mod (N-1)

Now let’s write the code:

/** Function to calculate the transpose of Matrix.
 *  It calculate the new position using the following formula:
 *    np = (op * m) % (N-1)    
 *  
 *  Also keeps a hash to see which locations are already considered.    
 */  
void MatrixTranspose(int *arr, int m, int n)
{
    int N = m*n;
    
    int hash[m*n] = {false}; // false means - location not considered.
    hash[0] = hash[m*n-1] = 1; // 1st & last elements does'nt change position.
    
    // Since first element does not move. Hence first position to move is 1.
    int posToMove = 1; 
    while (posToMove < N-1)
    {
        int startPos = posToMove;
        int value = arr[posToMove];
    
        // Loop iterate for one complete cycle
        do
        {
            int nextPos = (posToMove * m) % (N-1);
            
            // swap value & arr[nextPos] 
            int temp = value;
            value = arr[nextPos];
            arr[nextPos] = temp;
            
            hash[posToMove] = true;
            posToMove = nextPos;
        }while (posToMove != startPos);
 
        // Finding the start position for next cycle
        for (posToMove = 1; posToMove < N-1 && hash[posToMove]; posToMove++)
            ;
    }
}

Note that this code uses variable length arrays A feature which was introduced in C99 but not implemented by many compilers. If your compiler gives warning at the below code:

    int hash[m*n] = {false}; // false means - location not considered.

Then define it as dynamic array

    int * hash = (int*) malloc(sizeof(int) *(m*n));
    for(int i=0; i<m*n; i++)
        hash[i] = false;

In this case, also remember to deallocate memory the end (before function terminates)

    free(hash);

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)