重用Eigen :: SimplicialLLT的符号分解

时间:2017-01-27 17:25:37

标签: eigen eigen3

我正在努力使用特征库的API,即用于稀疏矩阵的Cholesky分解的SimplicialLLT类。 我有三个矩阵,我需要考虑并稍后用于解决许多方程式系统(仅改变右侧) - 因此我想将这些矩阵仅考虑一次,然后重新使用它们。而且,它们都具有相同的稀疏模式,所以我只想进行一次符号分解,然后将其用于所有三个矩阵的数值分解。根据文档,这正是SimplicialLLT::analyzePatternSimplicialLLT::factor方法的用途。 但是,我似乎无法找到将所有这三个因素保留在记忆中的方法。 这是我的代码:

我在课堂上有这些成员变量我想填写因素:

Eigen::SimplicialLLT<Eigen::SparseMatrix<double>> choleskyA;
Eigen::SimplicialLLT<Eigen::SparseMatrix<double>> choleskyB;
Eigen::SimplicialLLT<Eigen::SparseMatrix<double>> choleskyC;

然后我创建了三个稀疏矩阵A,B和C,并想要考虑它们:

choleskyA.analyzePattern(A);
choleskyA.factorize(A);
choleskyB.analyzePattern(B); // this has already been done!
choleskyB.factorize(B);
choleskyC.analyzePattern(C); // this has already been done!
choleskyC.factorize(C);

后来我可以一遍又一遍地使用它们来解决问题,改变右边的b向量:

xA = choleskyA.solve(bA);
xB = choleskyB.solve(bB);
xC = choleskyC.solve(bC);

这可行(我认为),但对analyzePattern的第二次和第三次调用是多余的。我想做的是:

choleskyA.analyzePattern(A);
choleskyA.factorize(A);
choleskyB = choleskyA.factorize(B);
choleskyC = choleskyA.factorize(C);

但这不是当前API的选项(我们使用Eigen 3.2.3,但如果我看到正确的话,3.3.2中的这方面没有变化)。 这里的问题是后来对SimplicialLLT的同一个实例进行分解的调用将覆盖先前计算的因子,同时,我无法找到一种方法来保留它的副本。我看了一下这些消息来源,但我不得不承认这没什么用,因为我看不到任何复制底层数据结构的简单方法。在我看来,这是一个相当普遍的用法,所以我觉得我错过了一些明显的东西,请帮忙。

我尝试了什么:

我尝试使用简单的choleskyB = choleskyA,希望默认的复制构造函数能完成任务,但我发现基类的设计是不可复制的。

我可以从choleskyA获取L和U矩阵(它们有一个getter),制作它们的副本并仅存储它们然后基本上复制粘贴SimplicialCholeskyBase :: _ solve_impl()的内容(在下面复制粘贴)用直接使用先前存储的L和U编写解决自己的方法。

template<typename Rhs,typename Dest>
void _solve_impl(const MatrixBase<Rhs> &b, MatrixBase<Dest> &dest) const
{
  eigen_assert(m_factorizationIsOk && "The decomposition is not in a valid state for solving, you must first call either compute() or symbolic()/numeric()");
  eigen_assert(m_matrix.rows()==b.rows());

  if(m_info!=Success)
    return;

  if(m_P.size()>0)
    dest = m_P * b;
  else
    dest = b;

  if(m_matrix.nonZeros()>0) // otherwise L==I
    derived().matrixL().solveInPlace(dest);

  if(m_diag.size()>0)
    dest = m_diag.asDiagonal().inverse() * dest;

  if (m_matrix.nonZeros()>0) // otherwise U==I
    derived().matrixU().solveInPlace(dest);

  if(m_P.size()>0)
    dest = m_Pinv * dest;
}

...但这是一个非常丑陋的解决方案加上我可能搞砸了,因为我对这个过程没有那么好的理解(我不需要上面代码中的m_diag,因为我正在做LLT,对吧?只有在我使用LDLT时这才有意义吗?)。我希望这不是我需要做的......

最后一点 - 将必要的getter / setter添加到Eigen类并编译“my own”Eigen不是一个选项(好吧,不是一个好选项),因为这个代码将(希望)进一步重新分配为开源,所以这很麻烦。

1 个答案:

答案 0 :(得分:3)

这是一种非常不寻常的模式。在实践中,与数值分解相比,符号分解非常便宜,所以我不确定它是否值得打扰。解决这种模式的最干净的解决方案是让SimplicialL?LT可以复制。