cdeterman
cdeterman

Reputation: 19970

How to reshape a matrix?

I am currently trying to convert some Python code into C++. One 'small' problem is changing the dimensions of a matrix. Is it possible to reshape a matrix in C++ similar to the Python reshape function?

For example, in Python I can easily create an array with numpy and easily reshape the dimensions.

a = np.array([[1,2,3],[4,5,6]])
>>> a.reshape(3,2)
array([[1, 2],
       [3, 4],
       [5, 6]])

How could I do this in C++? Perhaps this is a simple question but I am completely unable to do this. I have seen this within OpenCV library with the Mat class here however it is proving to be insanely difficult to work properly with MinGW, not to mention a very large addition for a single function. It would be ideal if this was possible with 'base' functions.

Upvotes: 9

Views: 15672

Answers (6)

x4444
x4444

Reputation: 2182

To reshape array you can use reinterpret_cast to a reference to the array with new shape. Stack frame will have one additional cell for z with sizeof(size_t). Asm code is equivalent to the code which takes a reference to the original array.

#include <iostream>
int main() {
    int x[2][3] = {0,1,2,3,4,5};
    std::cout << x[0][2] << std::endl;
    // reshape (2,3) to (3,2)
    int(&z)[3][2] = reinterpret_cast<int(&)[3][2]>(x);
    std::cout << z[1][0] << std::endl;
    return 0;
}

Program returned: 0
Program stdout
2
2

Upvotes: 0

Joseph Hansen
Joseph Hansen

Reputation: 13329

A very lightweight, easy-to-use C++ linear algebra library is Armadillo, and it provides reshape functionality.

#include <armadillo>
using namespace arma;
int main()
{
    // C++11
    // mat a = { { 1, 2, 3 },
    //    { 4, 5, 6 } };

    // C++98
    mat a;
    a << 1 << 2 << 3 << endr
        << 2 << 4 << 6 << endr;

    a.reshape(3, 2);
    a.print();

    return 0;
}

Note: I'd suggest not to do using namespace arma; and instead do arma::mat and arma::endr, etc. I did it in the example just for clarity.

Upvotes: 2

BartoszKP
BartoszKP

Reputation: 35921

Here's an example using boost::ublas:

#include <iostream>
#include <boost/numeric/ublas/matrix.hpp>

//...

using namespace boost::numeric::ublas;

matrix<double> a(2, 3);
a(0, 0) = 1;
a(0, 1) = 2;
a(0, 2) = 3;
a(1, 0) = 4;
a(1, 1) = 5;
a(1, 2) = 6;
matrix<double> r(3, 2, a.data());

for (int i = 0;i < 3;++i)
{
  for (int j = 0;j < 2;++j)
    std::cout << r(i, j) << ", ";
  std::cout << std::endl;
}

1, 2,

3, 4,

5, 6,

Upvotes: 4

doron
doron

Reputation: 28932

There is not standard matrix library in C++ so you are on your own when it comes to Matrices. One way of storing matrix data is in a simple array. You then have to do your own row and column arithmetic when accessing individual rows and column. In your case the reshape then comes for free by just swapping the row and column sizes.

If you want a matrix library, try: GLM.

Upvotes: 0

Marco A.
Marco A.

Reputation: 43662

As far as the memory is laid contiguously (e.g. plain C arrays), you can reinterpret the type with different indices:

int array[2][3] =   {   { 1, 2, 3 },
                        { 4, 5, 6 } 
                    };

// Reinterpret the array with different indices
int(*array_pointer)[3][2] = reinterpret_cast<int(*)[3][2]>(array);

for (int x = 0; x < 3; ++x) {
    for (int y = 0; y < 2; ++y)
        std::cout << (*array_pointer)[x][y] << " ";
    std::cout << std::endl;
}
// Output:
// 1 2
// 3 4
// 5 6

Example

The above is just an example to show that the issue really boils down to how memory is laid out in your matrix class.

In case your class uses a std::vector<int> internally with linear indices, it is sufficient to reinterpret those indices to suit your access patterns.

Upvotes: 7

James Kanze
James Kanze

Reputation: 154047

It depends on the matrix class you're using. If you write your own: there are two common implementation techniques: an std::vector<double>, with index calculations to find the flat index, and an std::vector<std::vector<double>>, with a class invariant that all of the members of the outer vector must have the same size. If you use the first, reshaping is easy, as long as the total size doesn't change (and it's hard to imagine what it would mean otherwise). If you use the second, reshaping would probably require constructing a copy with new shape.

Upvotes: 0

Related Questions