C++ 特征只读稀疏块子表达式?怎么写?

C++ Eigen read-only sparse block subexpression? How to write?

提问人:Cedric Martens 提问时间:11/10/2023 更新时间:11/10/2023 访问量:59

问:

我想使用 Eigen 的块表达式从四个不同的矩阵创建一个大矩阵。

但是,在左上角添加第一个矩阵会导致错误:

error: static assertion failed: THIS_SPARSE_BLOCK_SUBEXPRESSION_IS_READ_ONLY
  451 |       EIGEN_STATIC_ASSERT(sizeof(T)==0, THIS_SPARSE_BLOCK_SUBEXPRESSION_IS_READ_ONLY);

我无法找到导致此问题的确切原因。不要将矩阵转换为密集表示,这一点非常重要。这是我的代码:

 Eigen::SparseMatrix<double> top_left = K + Eigen::SparseMatrix<double>(K.transpose());

 Eigen::SparseMatrix<double> block_laplacian_sq;
 block_laplacian_sq.resize(top_left.rows() + C.rows(), top_left.cols() + C.rows());
 block_laplacian_sq.topLeftCorner(top_left.rows(), top_left.cols()) = top_left; 
//                                                       error here^^^
C++ 特征

评论

0赞 chtz 11/11/2023
要垂直堆叠稀疏矩阵,请检查以下答案:stackoverflow.com/a/41777589/6870253(这可以相对简单地扩展到堆叠多个矩阵)。另请参阅此功能请求:gitlab.com/libeigen/eigen/-/issues/1420

答:

2赞 Homer512 11/10/2023 #1

正如教程所解释的:

关于读取访问,稀疏矩阵公开的 API 与密集矩阵相同的 API 来访问子矩阵,例如块、列和行。有关详细介绍,请参阅块操作。但是,出于性能原因,写入次稀疏矩阵要有限得多,并且目前只有列主矩阵(或行主矩阵)的连续列集(或行)是可写的。此外,此信息必须在编译时已知,省略了 和 等方法。SparseMatrixblock(...)corner*(...)

对于要初始化左上角的特定用例,可以使用以下事实:调整大小后,未初始化的矩阵条目隐式为零。所以这有效:

top_left.conservativeResize(block_laplacian_sq.rows(), top_left.cols());
block_laplacian_sq.leftCols(top_left.cols()) = top_left;

但是,当您想要初始化底行时,这对您没有帮助。假设你想用子矩阵初始化所有 4 个角,我建议构建一个大的三元组向量(请参阅将特征矩阵转换为三元组形式的 C++),然后一次性初始化最终矩阵。

一种可能的替代方法是用完整逐列子矩阵的条目填充行主矩阵。我看不出这会如何更快,但对于您的用例来说,它可能更优雅。

Eigen::SparseMatrix<double, Eigen::RowMajor> left(
      block_laplacian_sq.rows(), top_left.cols());
left.topRows(top_left.rows()) = top_left;
left.bottomRows(bottom_left.rows()) = bottom_left;
block_laplacian_sq.leftCols(left.cols()) = left;

(显然,您会尝试重新排列表达式,以避免行优先<>列优先更改)