Reputation: 3256
I'm trying to recreate the following Python numpy code:
num_rows, num_cols = data.shape
N = 4
data = data.reshape(N, num_rows/N, num_cols)
in C++ using Armadillo matrices and cubes? How can this be done most efficiently. I dont think the resize/reshape operations are supported directly for moving from a 2d matrix to 3d cube?
Upvotes: 4
Views: 1904
Reputation: 6440
The fastest way to construct such a cube is to use one of the advanced constructors. These allow you to directly create a new object from an arbitrary section of memory, even without copying any of the data. This is closest in spirit to the way NumPy does reshaping, in which a view of the original data is returned, rather than a copy.
You'd use the constructor like so:
// Assuming a is an arma::mat.
int N = 4;
arma::cube c(a.memptr(), N, a.n_rows / N, a.n_cols, false);
This takes the memory directly from a
, without copying, and uses it as c
's data.
Of course, this is fast, but dangerous. You are responsible for guaranteeing that the pointed-to memory is valid as long as c
is around. This means that the lifetime of c
must be strictly nested in the lifetime of a
. This can be hard to ensure, especially when a
and c
are both created on the heap.
You can also allow c
to copy a
's data, by leaving off the last argument or setting it to true
. This takes more time than the no-copy constructor, but probably less than assigning each slice from a
's data, since this constructor does a single bulk memcpy
of the underlying data.
All of this is subject to the row- vs. column-major point brought up by @ewcz's answer. Make sure you know what you get when you reshape, especially if you're using the advanced constructors.
Upvotes: 2
Reputation: 13087
Since armadillo uses column major ordering of data (in contrast to numpy which relies on row major ordering), simply putting the matrix into a cube with 1 slice and reshaping it will produce different result (the matrix B
below). An alternative might be to construct the slices manually:
#include <iostream>
#include <armadillo>
int main(){
const arma::uword N = 2;
const arma::uword num_rows = 4;
const arma::uword num_cols = 3;
arma::mat A(num_rows, num_cols, arma::fill::randu);
std::cout << A;
arma::cube B(num_rows, num_cols, 1);
B.slice(0) = A;
B.reshape(num_rows/N, num_cols, N);
std::cout << B;
arma::cube C(num_rows/N, num_cols, N);
for(arma::uword i = 0; i < N; ++i){
C.slice(i) = A.rows(i*N, (i+1)*N-1);
}
std::cout << C;
return 0;
}
Upvotes: 1