【发布时间】:2020-07-17 12:28:15
【问题描述】:
在我的应用程序中,除了类构造函数之外,我需要避免动态内存分配(类似 malloc)。 我有一个稀疏的半定矩阵 M,它的元素在程序执行期间会发生变化,但它具有固定的稀疏模式。
为了尽可能快地求解许多线性系统 M * x = b,想法是在我的类构造函数中使用 inplace 分解,如Inplace matrix decompositions 中所述,然后在任何时候调用 factorize 方法M 变化:
struct MyClass {
private:
SparseMatrix<double> As_;
SimplicialLDLT<Ref<SparseMatrix<double>>> solver_;
public:
/** Constructor */
MyClass( const SparseMatrix<double> &As )
: As_( As )
, solver_( As_ ) // Inplace decomposition
{}
void assign( const SparseMatrix<double> &As_new ) {
// Here As_new has the same sparsity pattern of As_
solver_.factorize( As_new );
}
void solve( const VectorXd &b, VectorXd &x )
{
x = solver_.solve( b );
}
}
然而,factorize 方法仍然会创建一个与 As_ 大小相同的临时文件,因此使用动态内存分配。
是否有可能以某种方式避免它?如果 Eigen API 不允许此功能,一个想法是创建 SimplicialLDLT 的派生类,以便仅在将在类构造函数中调用的 analyzePattern 方法中执行动态内存分配。欢迎提出建议...
【问题讨论】:
-
恐怕如果不对稀疏求解器逻辑进行几次更改,这是不可能的(最重要的是,您需要一种方法来在多个步骤中继续为临时对象重用内存)。不过,我必须再次检查来源以获得明确的答案。
-
如果有机会我可以在派生类中实现此功能。我认为它对于嵌入式和实时应用程序非常有用,在这些应用程序中,动态内存分配通常只允许在启动阶段进行。
-
另一种可能的解决方案是将自定义分配器添加到求解器构造函数。应该动态分配的临时矩阵和向量从分配器中检索内存。实时系统的分配器可以由固定大小的内存池表示。这种策略在其他情况下也很有用。
-
分析 SimplicialCholesky.h 可以避免使用 Upper 三角形部分和 NaturalOrdering 进行动态分配。准确地说,第一次调用 factorize 方法仍然是动态分配内存,但可以在 ctor 类中完成。关于排序,可以手动调用 ordering 方法(在 ctor 中),如link 所述,注意将排列应用于 rhs 和解决方案向量。唯一值得关注的是文档中的指示此模块目前仅供内部使用。
-
这个想法部分有效:使用 NaturalOrdering 防止因式分解方法分配内存。另一方面,我需要在运行 factorize 方法之前手动置换输入矩阵,即:
H.selfadjointView<Upper>() = As_new.selfadjointView<Upper>().twistedBy(P);它会创建临时对象。有什么建议可以避免吗?
标签: c++ sparse-matrix eigen eigen3 matrix-factorization