You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过SparseSolverBase基类指针调用Eigen库任意类型稀疏线性求解器

错误原因

Eigen 的 SparseSolverBase 是 CRTP(奇异递归模板模式)实现的静态多态基类,它的模板参数是派生求解器类型本身,而非矩阵类型。比如 Eigen::SimplicialLLT<Eigen::SparseMatrix<double>> 实际继承的是 SparseSolverBase<Eigen::SimplicialLLT<Eigen::SparseMatrix<double>>>, 和你声明的 Eigen::SparseSolverBase<Eigen::SparseMatrix<double>> 是完全不同的两个类型,自然无法直接做指针转换。

实现方案

通过手动实现类型擦除层,构造运行时多态接口适配所有Eigen稀疏求解器,步骤如下:

  1. 定义抽象求解器接口基类,声明所有求解器需要的公共方法(compute、solve 等)
  2. 编写模板派生类,适配任意Eigen稀疏求解器,转发调用对应求解器的实现
  3. LinearSolver 类中存储抽象基类的智能指针,根据枚举值实例化对应模板派生类对象

修改后完整可运行代码

#pragma once
#include <Eigen/SparseCore>
#include <Eigen/SparseCholesky>
#include <Eigen/SparseQR>
#include <Eigen/SparseLU>
#include <Eigen/IterativeLinearSolvers>
#include <iostream>
#include <unsupported/Eigen/SparseExtra>
#include <memory>

enum solverType
{
    SimplicialLLT,
    SimplicialLDLT,
    SparseLU,
    ConjugateGradient,
    LeastSquaresConjugateGradient,
    BiCGSTAB
};

// 抽象求解器接口
class SolverInterface {
public:
    virtual ~SolverInterface() = default;
    virtual void compute(const Eigen::SparseMatrix<double>& A) = 0;
    virtual Eigen::VectorXd solve(const Eigen::VectorXd& b) const = 0;
    // 可按需补充更多接口,比如获取迭代次数、计算状态、设置公差等
};

// 模板派生类,适配任意Eigen稀疏求解器
template<typename SolverType>
class SolverImpl : public SolverInterface {
private:
    SolverType m_solver;
public:
    void compute(const Eigen::SparseMatrix<double>& A) override {
        m_solver.compute(A);
    }
    Eigen::VectorXd solve(const Eigen::VectorXd& b) const override {
        return m_solver.solve(b);
    }
    // 转发基类声明的其他接口
};

class LinearSolver
{
public:
    LinearSolver(Eigen::SparseMatrix<double> &A, Eigen::VectorXd &b, solverType type) : A(A), b(b) {
        switch (type) {
            case SimplicialLLT:
                solver = std::make_unique<SolverImpl<Eigen::SimplicialLLT<Eigen::SparseMatrix<double>>>>();
                break;
            case SimplicialLDLT:
                solver = std::make_unique<SolverImpl<Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>>>>();
                break;
            case SparseLU:
                solver = std::make_unique<SolverImpl<Eigen::SparseLU<Eigen::SparseMatrix<double>>>>();
                break;
            case ConjugateGradient:
                solver = std::make_unique<SolverImpl<Eigen::ConjugateGradient<Eigen::SparseMatrix<double>>>>();
                break;
            case LeastSquaresConjugateGradient:
                solver = std::make_unique<SolverImpl<Eigen::LeastSquaresConjugateGradient<Eigen::SparseMatrix<double>>>>();
                break;
            case BiCGSTAB:
                solver = std::make_unique<SolverImpl<Eigen::BiCGSTAB<Eigen::SparseMatrix<double>>>>();
                break;
        }
        solver->compute(A);
    };
    ~LinearSolver() = default;

    // 对外暴露求解方法
    Eigen::VectorXd solve() const {
        return solver->solve(b);
    }

private:
    Eigen::SparseMatrix<double> A;
    Eigen::VectorXd b;
    std::unique_ptr<SolverInterface> solver;
};
额外注意事项
  • 原代码的switch语句未加break,会导致匹配到对应case后仍执行所有后续case的赋值逻辑,必须补充break避免bug
  • 用std::unique_ptr管理内存,无需手动释放,析构时自动调用对应资源的释放逻辑
  • 如果需要支持更多求解器的特殊配置,只需要在SolverInterface中补充虚方法声明,在SolverImpl中转发调用即可

内容的提问来源于stack exchange,提问作者ElPotac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 00:18:04