(c++, armadillo) Replace a part of column vector from a matrix - c++

I'm using Rcpp with Armadillo library. My algorithm has a for-loop where I updates j-th column without j-th element at every step. Therefore, after a cycle, the input matrix will have all off-diagonal elements replaced with new values. To this end, I write Rcpp code like below.
arma::mat submatrix(
arma::mat A,
arma::uvec rowid){
for(int j = 0; j < A.n_rows; j++){
A.submat(rowid, "j") = randu(A.n_rows - 1);
}
return A;
}
However, I'm not sure how the submatrix view will work in the for-loop.
If you replace "j" in the above code with any of below, then this toy example
submatrix(matrix(rnorm(3 * 4), nrow = 3, ncol = 4), c(1:2))
will return an error message.
(uvec) j :
error: Mat::elem(): incompatible matrix dimensions: 2x0 and 2x1
j or (unsigned int) j : no matching member function for call to 'submat'
How could I handle this issue? Any comment would be very appreciated!

I have to confess that you do not fully understand your question -- though I think I get the idea of replace 'all but one' elements of a given row or column.
But your code has a number of problems. The following code is simpliefied (as I replace the full row), but it assigns row by row. You probably want something like this X.submat( first_row, first_col, last_row, last_col ), possibly in two chunks (assign above diagonal, then below). There is a bit more in the Armadillo documentation about indexing, and there is more too at the Rcpp Gallery.
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
arma::mat submatrix(arma::mat A, arma::uvec rowid, int k) {
for (arma::uword j = 0; j < A.n_rows; j++) {
A.row(j) = arma::randu(A.n_rows).t();
}
return A;
}
/*** R
M <- matrix(1:16,4,4)
submatrix(M, 1, 1)
*/

Related

Diagonal matrix properly in armadillo

My code works but I'm just curious to see if someone knows how to do this but properly using Armadillo library.
Thanks for your time :)
arma::mat W = arma::mat(4, 4, arma::fill::ones);
arma::mat D = arma::mat(4, 4, arma::fill::zeros);
for (size_t i = 0; i < W.n_rows; i++)
{
for (size_t j = 0; j < W.n_cols; j++)
{
D(i, i) += W(i, j);
}
}
std::cout<< "W = \n"<< W <<std::endl;
std::cout<< "D = \n"<< D <<std::endl;
It seems you are summing the elements in each row in the W matrix and putting the result in the diagonal of the D matrix. That is, you are summing elements over the "columns" dimension. This is very easy to do in armadillo and does not require any manual loop.
Armadillo has a sum function with a few overloads. One of these overloads receives a second parameter that you can use to specify in which dimension you want to perform the sum. Just specify the second dimension (index 1) and you get the proper result.
However, the result you get from arma::sum(W, 1) will be a vector. It makes sense, since you are summing over one of the dimensions of the matrix. Just pass the result to arma::diagmat and you get the same D matrix as with you original code. Your code can then be replaced by
arma::mat W = arma::mat(4, 4, arma::fill::ones);
arma::mat D = arma::mat(4, 4, arma::fill::zeros);
W.print("W");
arma::diagmat(arma::sum(W, 1)).print("D");
Note: I have used the .print method to print the matrices, in case you don't know about it. It is easier to use than using std::cout;

Permute Columns of Matrix in Eigen

I read this answer Randomly permute rows/columns of a matrix with eigen
But they initialize the permutation matrix as the identity matrix and do a random shuffle. I'm wondering how I can initialize the matrix to a specific permutation.
For example, if I have a vector of integers where each (index, value) pair means I want to move column "index" to column "value" how can I do this?
Eigen::MatrixXi M = Eigen::MatrixXi::Random(3,3);
std::vector<int> my_perm = {1,2,0};
some_function to return Matrix [M.col(1), M.col(2), M.col(0)]
EDIT: dtell kindly answered my original question below.
ADDITIONAL INFO:
For anyone else looking at this -- if you want to permute a matrix with a vector of unknown (at compile time) quanties, you can do the following:
Eigen::VectorXi indices(A.cols());
for(long i = 0; i < indices.size(); ++i) {
indices[i] = vector_of_indices[i];
}
Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic> perm;
perm.indices() = indices;
Eigen::MatrixXd A_permute = A * perm; \\ permute the columns
If I understand you correctly, the answer to your question is this slight modification of the answer you have linked
Matrix3i A = Matrix3i::Random();
PermutationMatrix<3, 3> perm;
// Your permutation
perm.indices() = { 1, 2, 0 };
// Permutate rows
A = perm * A;

Applying a function over columns of matrix using RcppArmadillo works but returns error when applied over rows

I coded a function qSelectMbycol in Rcpp that returns the kth largest element of each column in O(n) time. This function works OK. If I try to do the same but work over rows instead of columns (function qSelectMbyrow) it returns the error "error: Mat::init(): requested size is not compatible with column vector layout". Anybody any thoughts what I am doing wrong? I saved this file as "qselect.cpp" :
// [[Rcpp::depends(RcppArmadillo)]]
#define RCPP_ARMADILLO_RETURN_COLVEC_AS_VECTOR
#include <RcppArmadillo.h>
using namespace arma;
// [[Rcpp::export]]
arma::vec qSelectMbycol(arma::mat& M, const int k) {
// ARGUMENTS
// M: matrix for which we want to find the k-th largest elements of each column
// k: k-th statistic to look up
arma::mat Y(M.memptr(), M.n_rows, M.n_cols);
// we apply over columns
int c = M.n_cols;
arma::vec out(c);
int i;
for (i = 0; i < c; i++) {
arma::vec y = Y.col(i);
std::nth_element(y.begin(), y.begin() + k - 1, y.end());
out(i) = y(k-1); // the k-th largest value of each column
}
return out;
}
// [[Rcpp::export]]
arma::vec qSelectMbyrow(arma::mat& M, const int k) {
// ARGUMENTS
// M: matrix for which we want to find the k-th largest elements of each row
// k: k-th statistic to look up
arma::mat Y(M.memptr(), M.n_rows, M.n_cols);
// we apply over rows
int r = M.n_rows;
arma::vec out(r);
int i;
for (i = 0; i < r; i++) {
arma::vec y = Y.row(i); // this line throws the error "error: Mat::init(): requested size is not compatible with column vector layout"
std::nth_element(y.begin(), y.begin() + k - 1, y.end());
out(i) = y(k-1); // should give k-th largest value of each row
}
return out;
}
Example:
n=500
p=100
set.seed(1)
M=matrix(rnorm(n, mean = 100, sd = 1),n,1)
library(Rcpp)
library(RcppArmadillo)
Rcpp::sourceCpp('qselect.cpp')
qSelectMbycol(M,5) # works OK
qSelectMbyrow(M,5) # throws error "error: Mat::init(): requested size is not compatible with column vector layout"
I also tried inserting
typedef std::vector<double> stdvec;
and replacing the line setting vector y by
arma::vec y = arma::conv_to<stdvec>::from(Y.row(i));
in my qSelectMbyrow function and although the function then runs, it runs slowly compared to applying over columns, and also crashes my R session if I run it 100 times.
The issue is that an arma::vec is actually an arma::colvec (see the docs). So, we can solve this issue by changing
arma::vec y = Y.row(i);
(which is incompatible because it thinks you want a matrix with one column but you're trying to give it a matrix with one row) to
arma::rowvec y = Y.row(i);

In-Place CUDA Kernel for Rectangular Matrix Transpose

I have perused around for a while, but was unable to find a proper answer for this:
Is there an implementation for in-place diagonal matrix transpose in CUDA?
I am aware of cublas geam, but that requires creating another matrix. I tried a naive implementation from: CUDA In-place Transpose Error
However, that only works for square matrices. Can someone explain to me why exactly this logic does not work for diagonal matrices? The 'naive' approach for transposition works though, however it is not in place.
After looking around for a while I found the following github page which does have code related to the nvidia research paper for an in-place transpose:
https://github.com/BryanCatanzaro/inplace
This seems to be the correct way to solve this question.
Have a look at the following paper: A Decomposition for In-place Matrix Transposition
Sequential algorithm for in-place matrix transpose is as follows (> O(n*m) running time):
// in: n rows; m cols
// out: n cols; m rows
void matrix_transpose(int *a, int n, int m) {
int i, j;
for(int k = 0; k < n*m; k++) {
int idx = k;
do { // calculate index in the original array
idx = (idx % n) * m + (idx / n);
} while(idx < k); // make sure we don't swap elements twice
std::swap(a[k], a[idx]);
}
}

Eigen SparseMatrix - set row values

I write a simulation with Eigen and now I need to set a list of rows of my ColumnMajor SparseMatrix like this:
In row n:
for column elements m:
if m == n set value to one
else set value to zero
There is always the element with column index = row index inside the sparse matrix. I tried to use the InnerIterator but it did not work well since I have a ColumnMajor matrix. The prune method that was suggested in https://stackoverflow.com/a/21006998/3787689 worked but i just need to set the non-diagonal elements to zero temporarily and prune seems to actually delete them which slows a different part of the program down.
How should I proceed in this case?
Thanks in advance!
EDIT: I forgot to make clear: the sparse matrix is already filled with values.
Use triplets for effective insertion:
const int N = 5;
const int M = 10;
Eigen::SparseMatrix<double> myMatrix(N,M); // N by M matrix with no coefficient, hence this is the null matrix
std::vector<Eigen::Triplet<double>> triplets;
for (int i=0; i<N; ++i) {
triplets.push_back({i,i,1.});
}
myMatrix.setFromTriplets(triplets.begin(), triplets.end());
I solved it like this: Since I want to stick to a ColumnMajor matrix I do a local RowMajor version and use the InnerIterator to assign the values to the specific rows. After that I overwrite my matrix with the result.
Eigen::SparseMatrix<float, Eigen::RowMajor> rowMatrix;
rowMatrix = colMatrix;
for (uint i = 0; i < rowTable.size(); i++) {
int rowIndex = rowTable(i);
for (Eigen::SparseMatrix<float, Eigen::RowMajor>::InnerIterator
it(rowMatrix, rowIndex); it; ++it) {
if (it.row() == it.col())
it.valueRef() = 1.0f;
else
it.valueRef() = 0.0f;
}
}
colMatrix = rowMatrix;
For beginners, the simplest way set to zero a row/column/block is just to multiply it by 0.0.
So to patch an entire row in the way you desire it is enough to do:
A.row(n) *= 0; //Set entire row to 0
A.coeffRef(n,n) = 1; //Set diagonal to 1
This way you don't need to change your code depending of RowMajor/ColMajor orders. Eigen will do all the work in a quick way.
Also, if you are really interested in freeing memory after setting the row to 0, just add a A.prune(0,0) after you have finished editing all the rows in your matrix.