C++ 修改/收缩本征置换矩阵

C++ 修改/收缩本征置换矩阵,c++,c++11,matrix,eigen,qr-decomposition,C++,C++11,Matrix,Eigen,Qr Decomposition,我很难解决我认为应该是一个相当简单的问题。基本问题是我想修改一个特征置换矩阵,但我不知道如何修改 我用C++本征库对某个矩阵 x进行qr分解。我在秩亏矩阵上做这个,我需要一个特殊的输出。具体来说,我需要 R^{-1}*t(R^{-1}) 问题在于,使用Eigen::ColPivHouseholderQR会返回R的置换版本。当X为满秩时,这很容易修复,但我希望在秩不足时使用最快的解决方案。让我示范一下: 使用名称空间特征; //做QR ColPivHouseholderQR PQR(X); //求

我很难解决我认为应该是一个相当简单的问题。基本问题是我想修改一个特征置换矩阵,但我不知道如何修改

我用C++本征库对某个矩阵<代码> x<代码>进行qr分解。我在秩亏矩阵上做这个,我需要一个特殊的输出。具体来说,我需要

R^{-1}*t(R^{-1})

问题在于,使用
Eigen::ColPivHouseholderQR
会返回
R
的置换版本。当
X
为满秩时,这很容易修复,但我希望在秩不足时使用最快的解决方案。让我示范一下:

使用名称空间特征;
//做QR
ColPivHouseholderQR PQR(X);
//求置换矩阵
ColPivHouseholderQR::置换类型Pmat(PQR.colpermutation());
intr(PQR.rank());
int p(X.cols());
//注意,我只得到r元素,所以r\u inv是r乘以r
MatrixXd R_inv=PQR.matrixQR().topLeftCorner(R,R).triangularView().solve(MatrixXd::Identity(R,R));
//这仅在r=p且X为满秩时有效
R_inv=Pmat*R_inv*Pmat;
XtX_inv=R_inv*R_inv.transpose();
所以基本的问题是,我想修改Pmat,使它只排列我从
PQR.matrixQR()
中提取的r\u inv的r列。我的基本问题是,我不知道如何修改特征置换矩阵,因为它似乎没有任何正规矩阵的方法或属性

一个可能的解决方案是:当我乘以
Pmat*MatrixXd::Identity(p,p)
时,我得到一个有用的矩阵

例如,我得到如下结果:

[0, 1, 0, 0,
 1, 0, 0, 0,
 0, 0, 0, 1,
 0, 0, 1, 0]
如果p=4,r=3,那么我只需要这个子视图,在这个子视图中,我将所有列放在前r列的右侧,然后删除所有都为0的行:

[0, 1, 0,
 1, 0, 0,
 0, 0, 1]
因此,我可以做以下工作:

P = Pmat * MatrixXd::Identity(p, p)
P.leftCols(p);
MatrixXd P = Pmat * Eigen::MatrixXd::Identity(p, p);

// https://stackoverflow.com/questions/41305178/removing-zero-columns-or-rows-using-eigen
// find non-zero columns:
Matrix<bool, 1, Dynamic> non_zeros = P.leftCols(r).cast<bool>().rowwise().any();

// allocate result matrix:
MatrixXd res(non_zeros.count(), r);

// fill result matrix:
Index j=0;
for(Index i=0; i<P.rows(); ++i)
{
  if(non_zeros(i))
    res.row(j++) = P.row(i).leftCols(r);
}

R_inv = res * R_inv * res;

XtX_inv = R_inv * R_inv.transpose();
// Get all column indices
ArrayXi Pmat_indices = Pmat.indices();
// Get the order for the columns you are keeping
ArrayXi Pmat_keep = Pmat_indices.head(r);
// Get the indices for columns you are discarding
ArrayXi Pmat_toss = Pmat_indices.tail(p - r);

// this code takes the indices you are keeping, and, while preserving order, keeps them in the range [0, r-1]
// For each one, see how many dropped indices are smaller, and subtract that difference
// Ex: p = 4, r = 2
// Pmat_indices = {3, 1, 0, 2}
// Pmat_keep = {3, 1}
// Pmat_toss = {0, 2}
// Now we go through each keeper, count how many in toss are smaller, and then modify accordingly
// 3 - 2 and 1 - 1
// Pmat_keep = {1, 0}
for(Index i=0; i<r; ++i)
{
  Pmat_keep(i) = Pmat_keep(i) - (Pmat_toss < Pmat_keep(i)).count();
}

// Now this will order just the first few columns in the right order
PermutationMatrix<Dynamic, Dynamic> P = PermutationWrapper<ArrayXi>(Pmat_keep);

R_inv = P * R_inv * P;