I'm trying to set the values of an arma::mat
element-wise and the value of each element depends on the multi-index (row, column) of each element.
Is there a way to retrieve the current location of an element during iteration?
Basically, I'd like to be able to do something like in the sparse matrix iterator, where it.col()
and it.row()
allow to retrieve the current element's location.
For illustration, the example given in the arma::sp_mat
iterator documentation) is:
sp_mat X = sprandu<sp_mat>(1000, 2000, 0.1);
sp_mat::const_iterator it = X.begin();
sp_mat::const_iterator it_end = X.end();
for (; it != it_end; ++it) {
cout << "val: " << (*it) << endl;
cout << "row: " << it.row() << endl; // only available for arma::sp_mat, not arma::mat
cout << "col: " << it.col() << endl; // only available for arma::sp_mat, not arma::mat
}
Of course there are a number of workarounds to get element locations for arma::mat
iteration, the most straight-forward ones perhaps being:
for
-loops over the row and column sizes.for
loop and, using the matrix size, transform the iteration number to a row and column index.However, these seem rather hacky and error-prone to me, because they require to work with the matrix sizes or even do manual index juggling. I'm looking for a cleaner (and perhaps internally optimised) solution. It feels to me like there should be a way to achieve this ...
Apart from the solution used for arma::sp_mat
, other such "nice" solution for me would be using .imbue
or .for_each
but with a functor that accepts not only the element's current value but also its location as additional argument; this doesn't seem to be possible currently.
Looking at the armadillo source code, row_col_iterator provides row and column indices of each element. This works like the sparse matrix iterator, but doesn't skip zeros. Adapting your code:
mat X(10,10,fill::randu);
mat::const_row_col_iterator it = X.begin_row_col();
mat::const_row_col_iterator it_end = X.end_row_col();
for (; it != it_end; ++it) {
cout << "val: " << (*it) << endl;
cout << "row: " << it.row() << endl;
cout << "col: " << it.col() << endl;
}