Reputation: 19970
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
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
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
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
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
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
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
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