0

Is it possible to do in-place matrix transpose of an M*N matrix in Java? I don't think it's possible in Java because, in a 3*5 matrix, the element at 3*5 would ideally be swapped with the element at 5*3, but such a position does not exist. In say, C/C++, it would be possible since memory is contiguous.

Also, there are other algorithms like the one posted here for M*N matrices, which I believe are not applicable to Java, but how's it any different from swapping elements at A[i][j] with A[j][i] since even the rolling window algorithm in the link above takes auxiliary memory?

saltandwater
  • 791
  • 2
  • 9
  • 25
  • How are you representing your matrix? If by "matrix", you mean an array of arrays, then no. But if you are defining a matrix class with some internal representation, e.g. a single array, or an array of arrays, then there are many approaches that don't involve create entire new representations. – James_D Aug 02 '16 at 17:42
  • @James_D, Thanks. Like I asked one of the other users, what is the purpose of the algorithm here - http://www.geeksforgeeks.org/inplace-m-x-n-size-matrix-transpose/ . How's it any better than swapping - Both of them traverse every element at least once, and they both require auxiliary storage – saltandwater Aug 02 '16 at 17:45
  • you can use ArrayList, which has no per-declared size. – Kaushal28 Aug 02 '16 at 17:46
  • @Kaushal28, please can you elaborate? But how would I fit it in back to the original array? – saltandwater Aug 02 '16 at 17:52
  • In the answer it is said that we cannot change the size of array after declaring it. But in `arrayList` you can increase the size when it is needed. Similar to linked lists. – Kaushal28 Aug 02 '16 at 17:55
  • Why would you need to increase the size of the backing array? You've got exactly as many elements before and after. – biziclop Aug 02 '16 at 17:57
  • Not an expert on that, but 1. the algorithm assumes a linear representation of a matrix, which is really not the same as a Java representation by an array of arrays (which is what I think you are assuming here). 2. I *think* that algorithm involves fewer operations than a straightforward pairwise swap of the elements. – James_D Aug 02 '16 at 17:58
  • @James_D ,Hmm.. I'm not convinced about the algorithm requiring fewer operations. It still visits every element once, which is basically O(n^2), correct? – saltandwater Aug 02 '16 at 18:02
  • If it visits every element once, it's `O(n)`. – biziclop Aug 02 '16 at 18:37

3 Answers3

2

You have to be careful with the term in-place. Strictly speaking, the transpose operator 'creates' a new matrix with potentially new dimensions. In the case of the article you linked, in-place just means using the same memory for the initial and final matrices, which is of course possible with a clever representation.

A trivial solution might be:

public class Matrix {
    private int[][] backingArray;
    private boolean transposed;
    public Matrix(int[][] _backingArray) {
        this.backingArray = _backingArray
    }

    public Matrix(int[] data, rows, columns) {
        backingArray = new int[rows][columns]
        for (int i = 0; i < rows; i++)
            for (int j = 0; j < columns; j++)
                backingArray[i][j] = data[i*columns + j]
    }

    public int getElement(i, j) {
        if (transposed)
            return backingArray[j][i];
        return backingArray[i][j];
    }

    public void transpose() {
        transpose = !transpose;
    }
}

EDIT: Corrected some bad syntax

EDIT: Made it so that a 1-D matrix can be read in as per the OPs question (?)

Checkmate
  • 1,074
  • 9
  • 16
  • Nice. A slightly more roundabout solution would be using a one-dimensional backing array. – biziclop Aug 02 '16 at 17:58
  • @Checkmate, I understand, but I don't understand how it's any better than just swapping. Both, this algorithm(linked article) as well as swapping traverse every element at least once, and they both require auxiliary storage – saltandwater Aug 02 '16 at 17:59
  • @biziclop Yeah, fair enough, I was just looking for something intuitive. You'd obviously want to make this generic and able to take on higher dimensions if you wanted to generalize – Checkmate Aug 02 '16 at 18:00
  • @saltandwater The problem with swapping is that you need to create an entirely new array. Suppose you transpose a 50x70 matrix. You would need to create an entirely new 70x50 array in memory, which is super expensive. This is an O(1) operation that requires much less memory – Checkmate Aug 02 '16 at 18:01
  • @saltandwater Also, rather cleverly, this algorithm never has to visit an element to do the transposition, so it's O(1). Now, there are obviously potential problems with this, and we're not being as memory efficient as the algorithm linked, but it's still fast and (in my opinion) pretty – Checkmate Aug 02 '16 at 18:04
  • @Checkmate , thanks for the insights. Have a couple of questions (I'm speaking from the implementation I linked). 1. What is the size of the bit vector required for this matrix, isn't it M*N, which is basically same as the 50*70 matrix maintained in the naive swapping implementation? 2.You say, "this algorithm never has to visit an element to do the transposition". Hmm.. I feel it does have to. If you look at the implementation, inside the do-while loop, it does i = next; and then repeats the process. So, I feel it IS visiting EVERY element. Please clarify. – saltandwater Aug 02 '16 at 18:09
  • @saltandwater (2) Sorry, I wasn't clear. My "algorithm" never has to visit an element since we're just changing how we represent the matrix. The algorithm you linked obviously does. – Checkmate Aug 02 '16 at 18:10
  • @saltandwater (1) Yeah, but the point is that you don't have to make a new array. You're just reusing the memory from the original, so no new memory has to be allocated (which is in itself can be expensive). Further, you don't end up with two big blocks of memory used while running the transpose operasion. – Checkmate Aug 02 '16 at 18:12
  • @Checkmate, sorry reusing the memory from the original? Aren't we creating a new bit array in the imlpementation? Again, are you talking about the wikipedia article or the geeksforgeeks implementation? Also, from your previous reply, I've begun to feel that the geeksforgeeks implementation is incorrect, and I should only follow the wikipedia article, correct? – saltandwater Aug 02 '16 at 18:16
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/118943/discussion-between-checkmate-and-saltandwater). – Checkmate Aug 02 '16 at 18:27
  • @saltandwater I edited the code so that you can directly make an object of your array (closer to James_D's solution). It might be a bit faster too. As a point of clarification, using objects like this is very standard in Java and is probably the best solution rather than using a 1-D array like you are. – Checkmate Aug 02 '16 at 19:48
1

Your question doesn't really make too much sense without specifying considerably more of the context: the algorithms are assuming a linear representation of the data (which, since languages such as C[++] essentially directly access memory, makes sense in those contexts). Note that for this kind of representation, you need to represent the number of rows and columns externally to the data. So the data representation for a 3x4 matrix could equally well be used for a 4x3 (or 2x6, etc) matrix, you would just have different values for numberCols and numberRows (in pseudocode). So the transposition algorithms here use the same memory allocation, but re-order the elements and re-interpret the number of rows and columns.

If you represent a (integer) matrix in Java as int[][], then you can't use the same algorithm, or indeed any in-place transposition, because the number of rows and columns are fixed for that particular representation: arrays in Java are not resizable. The algorithm doesn't apply because the data representation is not linear in the same way.

But if you chose to represent your matrix using a single-dimension array:

public class IntMatrix {

    private final int numColumns ;
    private final int numRows ;

    private final int[] data ;

    public IntMatrix(int numColumns, int numRows, int... data) {
        if (data.length != numColumns*numRows) {
            throw new IllegalArgumentException("...");
        }
        this.numColumns = numColumns ;
        this.numRows = numRows ;
        this.data = new data[numColumns * numRows] ;
        System.arrayCopy(data, 0, this.data, 0, this.data.length);
    }

    public int getElement(int row, int column) {
        return data[column*numRows+row];
    }

    public int getNumRows() {
        return numRows ;
    }

    public int getNumColumns() {
        return numColumns ;
    }
}

then you could certainly implement an in-place transpose with exactly the same algorithms.

However, you almost certainly wouldn't: you'd do the following:

public class IntMatrix {

    // code as before...

    public IntMatrix transpose() {
        return new Transpose(this);
    }

    private static class Transpose extends IntMatrix {
        private IntMatrix original ;
        Transpose(IntMatrix original) { 
            this.original = original ;
        }
        @Override
        public int getElement(int row, int column) {
            return original.getElement(column, row) ;
        }
        @Override
        public IntMatrix transpose() {
            return original ;
        }
        @Override
        public int getNumRows() {
            return original.getNumColumns();
        }
        @Override
        public int getNumColumns() {
            return original.getNumRows();
        }
    }
}

which (for this immutable representation) creates a transpose with O(1) operations and O(1) additional memory. You can create mutable representations similarly, with a little more work, and possibly higher cost depending exactly on what exact behavior you want (transpose view of the original mutable matrix, etc).

James_D
  • 201,275
  • 16
  • 291
  • 322
  • thanks for the explanation. But stil don't see how the implementation at http://www.geeksforgeeks.org/inplace-m-x-n-size-matrix-transpose/ adds anything. It visits every element once O(M*N) and maintains an auxiliary memory of size O(M*N), both of which are the same as a naive mapping between A[i][j] and A[j][i] which needs O(M*N) time and O(M*N) space. Please clarify – saltandwater Aug 02 '16 at 18:27
  • @saltandwater Well, I can't answer for that implementation with 100% confidence; I believe both that and simply swapping are O(mn) in operations, but the implementation you linked has fewer operations (i.e. small constant k for k*m*n). I'd have to do way more analysis than I have time for though. Again, though, in Java you simply wouldn't do any of that for a transpose; you'd just take whatever data representation you have and flip the interpretation of "row" and "column", as in my answer and Checkmate's answer. – James_D Aug 02 '16 at 18:30
0

You're right, it can't. In Java, once an array has been created, its length is fixed. So, if M and N are different, you can't swap them

alexgbelov
  • 3,032
  • 4
  • 28
  • 42
  • thanks. Also, what is the purpose of the algorithm in that link, or the one here http://www.geeksforgeeks.org/inplace-m-x-n-size-matrix-transpose/ . How's it any better than swapping - Both of them traverse every element at least once, and they both require auxiliary storage – saltandwater Aug 02 '16 at 17:44
  • It is possible using ArrayList in java. – Kaushal28 Aug 02 '16 at 17:45
  • I don't think that's really in place though. My impression is that the ArrayList allocates a new array, and copies over the existing values. – alexgbelov Aug 02 '16 at 19:30