Suppose I have an array in C++ such as the following:
1 2 3 4 = arr
5 6 7 8
9 9 8 9
7 6 1 3
Is there a concise way to exclude any row and/or column?
For example, suppose I want to do an operation on the following array:
1 3 4
5 7 8
7 1 3
In other programming languages, I can obtain the above array fairly easy with arr[-3,-2] to exclude the third row and second column. However, I have been unable to find a concise way to exclude rows and columns in C++. How would you go about it?
Update:
I suppose this is an XY problem. Let me tell you why I want to do this.
I am running a statistical model, specifically a conditional autoregressive (CAR) model. In this Gaussian model, we need the mean function and covariance matrix.
We obtain the mean function as
mean = mu + Sig(i,-i) * inv(Sig(-i,-i)) * (v(i,-i) - mu)
and the covariance matrix as
s2 = Sig(i,i) - Sig(i,-i) * inv(Sig(-i,-i)) * Sig(-i,i)
So, I need to obtain three variants of the matrix Sig: Sig(l,-l), Sig(-l,-l), Sig(-l,l). This is why I'm hoping to find a simple way to exclude rows and columns. I would usually program this in R, but it's taking so long. So, I'm hoping to get it working in Rcpp.
Next Update:
I think I'm figuring it out, so thank you to the commenters. This is what I'm thinking. I need a vector that stores the indices that I want to keep in my submatrix. I plan on using Rcpp's X.submat() function.
Suppose the I want to obtain the submatrix of Sig that excludes the ith row and ith column. Then I must have a vector of indices that contains {0,1,...,(i-2),i,...,(L-1)}, since C++ indexing starts at 0. To obtain this vector of indices, I have the following code:
// We need to get the vector of indices excluding i
arma::vec vece = arma::zeros(L-1); // vector to exclude the ith index
for(int k = 0; k < (L-1); k++){ // we have a vector of length L-1
if(k < (i-1)){
vece(k)=k;
}
else if(k == (i-1)){
// do not add the ith index
}
else{ // k > (i-1)
vece(k-1) = k;
}
}
// We need to make Sig(-i,-i)
arma::mat Sigee = arma::zeros(L-1,L-1); // ee for exclude,exclude
Sigee = Sig.submat(vece,vece)
However, this does not appear to work when i = 0. I have this code within the following for-loop, so I need this to work when i=0.
for(int l = 0; l < L; l++){ }
To me, it seems a more straightforward approach is to fill an n-1
length uvec
with sequential integers, just skipping i
, like so:
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
// [[Rcpp::export]]
arma::mat exclude_one_row_and_col(const arma::mat& X, arma::uword i) {
arma::uword n = X.n_rows; // X should be square so only need # rows
arma::uvec idx(n-1); // vector of indices to subset by
arma::uword ii = 0; // the integer we'll add at each elem of idx
for ( arma::uword j = 0; j < (n-1); ++j ) { // for each elem of idx
if ( ii == i ) { // if ii equals i, we need to skip i
ii += 1; // (i.e., add 1 to ii)
}
idx[j] = ii; // then we store ii for this elem
ii += 1; // and increment ii
}
return X.submat(idx, idx); // finally we can subset the matrix
}
A simple demonstration shows this works as expected:
X <- diag(1:3)
X
# [,1] [,2] [,3]
# [1,] 1 0 0
# [2,] 0 2 0
# [3,] 0 0 3
exclude_one_row_and_col(X, 0)
# [,1] [,2]
# [1,] 2 0
# [2,] 0 3
exclude_one_row_and_col(X, 1)
# [,1] [,2]
# [1,] 1 0
# [2,] 0 3
exclude_one_row_and_col(X, 2)
# [,1] [,2]
# [1,] 1 0
# [2,] 0 2