使用Eigen :: VectorXd(Eigen 3.3.4)作为boost :: numeric :: odeint中的状态类型(Boost 1.65.1)

时间:2017-10-31 15:49:00

标签: c++ boost eigen eigen3 odeint

在我工作期间,我需要使用Eigen :: VectorXcd作为状态类型来解决庞大的线性ODE系统。在该项目中,ODE系统中的矩阵是稀疏的。将它与密集矢量相乘可以使用Eigen以简单的方式并行计算。但是,我在这种情况下遇到了一些问题,我将在下面详细说明。目前我正在应用一个效率不高的解决方案,即我使用arma :: cx_vec作为状态类型,并声明对应于ode arma :: cx_mat的矩阵,这是一种密集矩阵类型。不幸的是,稀疏矩阵密集的向量乘法不能与Armadillo并行化,因为它只支持SuperLU的单线程版本。根据我的经验,在我的具体情况下,稀疏矩阵密集向量乘法比密集矩阵密集向量乘法快三倍。由于即使同时使用20个CPU内核,单次运行也会持续数十或数百小时,因此我非常需要能够使用Eigen库和boost :: odeint在运行时获得三倍的因子。 / p>

出于测试目的,我尝试使用Eigen :: VectorXd作为状态类型。我也发现了非常类似的情况,请参阅:Using Boost::odeint with Eigen::Matrix as a state vectorusing several eigen matrices as statetypes in boost/odeint.但是,没有一个解决方案适合我。在我的实际项目中,我必须使用Bulirsch-Stoer方法来集成我的ODE系统,因为高精度因此我需要错误控制。下面我将发布我的测试代码,对应于Eigen :: VectorXd状态类型。如您所见,首先,我遵循boost :: odeint文档中描述的步骤:受控步进器的I defined my state vector resizeableoverloaded the mathematical operators used by the vector space algebra。执行这些步骤后,代码仍然无法编译,overloading of the addition operator for adding vectors to scalars也是必需的。这是我的代码:

#include <iostream>
#include <vector>
#include <complex>

#include <Eigen/Eigen>
#include <boost/numeric/odeint.hpp>

namespace boost {
namespace numeric {
namespace odeint {

template<>
struct is_resizeable<Eigen::VectorXd>
{
    typedef boost::true_type type;
    static const bool value = type::value;
};

template<>
struct same_size_impl<Eigen::VectorXd, Eigen::VectorXd>
{
    static bool same_size(const Eigen::VectorXd& v1, const Eigen::VectorXd& v2)
    {
        std::cout << "same_size: " << v1.transpose() << " and " << v2.transpose() << std::endl;
        std::cout << "same_size: " << v1.rows() << " == " << v2.rows() << std::endl;
        return v1.rows() == v2.rows();
    }
};

template<>
struct resize_impl<Eigen::VectorXd, Eigen::VectorXd>
{
    static void resize(Eigen::VectorXd& v1, const Eigen::VectorXd& v2)
    {
        std::cout << "resize_impl: " << v1.transpose() << " and " << v2.transpose() << std::endl;
        std::cout << "resize_impl: (" << v1.rows() << " x " << v1.cols() << ") to (" << v2.rows() << " x " << v2.cols() << ")" << std::endl;
        v1.conservativeResize(v2.size());
        std::cout << "resize_impl: new size: " << v1.rows() << " x " << v1.cols() << std::endl;
    }
};

template<>
struct vector_space_norm_inf<Eigen::VectorXd>
{
    typedef double result_type;
    double operator()(const Eigen::VectorXd& v) const
    {
        std::cout << "vector_space_norm_inf(" << v.transpose() << ") = " << v.lpNorm<Eigen::Infinity>() << std::endl;
        return v.lpNorm<Eigen::Infinity>();
    }
};

}
}
}

namespace Eigen {
//VectorXd operator*(const double& a, const VectorXd& v)
//{
//  std::cout << a << "*(" << v.transpose() << ") = " << a*(v.transpose()) << std::endl;
//  return a*v;
//}
//
//VectorXd operator*(const VectorXd& v, const double& a)
//{
//  std::cout << "(" << v.transpose() << ")*" << v.transpose() << " = " << a*(v.transpose()) << std::endl;
//  return a*v;
//}
//
//VectorXd& operator*=(const double& a, VectorXd& v)
//{
//  std::cout << "operator*=(const double& a, VectorXd& v): (" << v.transpose() << ") *= " << a << ": ";
//  v *= a;
//  std::cout << v.transpose() << std::endl;
//  return v;
//}
//
//VectorXd& operator*=(VectorXd& v, const double& a)
//{
//  std::cout << "operator*=(VectorXd& v, const double& a): (" << v.transpose() << ") *= " << a << ": ";
//  v *= a;
//  std::cout << v.transpose() << std::endl;
//  return v;
//}
//
//VectorXd& operator+=(VectorXd& v1, const VectorXd& v2)
//{
//  std::cout << "(" << v1.transpose() << ") += (" << v2.transpose() << "): ";
//  v1 += v2;
//  std::cout << v1.transpose() << std::endl;
//  return v1;
//}

VectorXd operator/(const VectorXd& v1, const VectorXd& v2)
{
    const char* sizeeq;
    if(v1.size() == v2.size())
        sizeeq = "True";
    else
        sizeeq = "FALSE!";

    std::cout << "operator/: size check: " << v1.size() << " ?= " << v2.size() << ": " << sizeeq << std::endl;
    VectorXd result(v1.cwiseQuotient(v2));

    std::cout << "(" << v1.transpose() << ") / (" << v2.transpose() << ") = " << result.transpose() << std::endl;
    return result;
}

VectorXd operator+(double d, const VectorXd& v)
{
    std::cout << d << " + (" << v.transpose() << ") = " << d+v.transpose() << std::endl;
    return d+v;
}

VectorXd operator+(const VectorXd& v, double d)
{
    std::cout << "(" << v.transpose() << ") + " << d << " = " << d+v.transpose() << std::endl;
    return d+v;
}

VectorXd abs(const VectorXd& v)
{
    std::cout << "|(" << v.transpose() << ")| = " << v.cwiseAbs().transpose() << std::endl;
    return v.cwiseAbs();
}
}

typedef Eigen::VectorXd state_type;
typedef Eigen::MatrixXd coeff_matrix_type;

class lin_diff_eq
{
    public:
        lin_diff_eq(coeff_matrix_type gam): m_gam(gam) {}
        coeff_matrix_type get_matrix() const { return m_gam; }

        void operator()(const state_type& x, state_type& dxdt, const double t)
        {
            std::cout << "size: " << x.size() << std::endl;
            std::cout << x.transpose() << std::endl;
            dxdt = m_gam*x;
        }

    private:
        coeff_matrix_type m_gam;
};

using namespace boost::numeric::odeint;

int main()
{
    coeff_matrix_type A = coeff_matrix_type(2,2);
    state_type x = state_type(2);
    double epsabs = 1e-4;
    double epsrel = 1e-4;
    A << 0, 1,
        -2, 0;
    x << 1, 0;
    lin_diff_eq lde(A);
    std::cout << lde.get_matrix() << std::endl;

    integrate_adaptive(bulirsch_stoer<state_type, double, state_type, double, vector_space_algebra>(epsabs, epsrel), lin_diff_eq(A), x, 0.0, 1.0, 0.1);
}

所有这些步骤使我的代码编译,但是,在运行时我的程序崩溃与分段错误。正如您所看到的,我重载了所有操作符,使得它们生成某种非常简单的日志,我无法弄清楚如何生成更详细的日志以准确定位分段错误发生的位置和原因。根据boost :: odeint文档,这可能发生在运行时,当向量空间代数不知道如何调整向量的大小时,但我已经定义了如何做到这一点。在我的计算机上,可以看到boost :: odeint生成一些内部状态,正确调整它们的大小,正确计算elementwise abs(),但之后崩溃。

我接下来尝试的是使用boost :: odeint开发人员提供的对Eigen的支持。在这种情况下,我没有使用任何模板特化和上面提供的运算符重载,而是我包括

boost/numeric/odeint/external/eigen/eigen_algebra.hpp

包括odeint.hpp之后。代码没有编译,我得到以下错误消息:

/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|35|error: ‘scalar_add_op’ in namespace ‘Eigen::internal’ does not name a type|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|35|error: expected template-argument before ‘<’ token|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|35|error: expected ‘>’ before ‘<’ token|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|37|error: wrong number of template arguments (1, should be 2)|
/usr/local/include/Eigen/src/Core/util/ForwardDeclarations.h|91|error: provided for ‘template<class UnaryOp, class MatrixType> class Eigen::CwiseUnaryOp’|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|38|error: expected ‘::’ before ‘operator’|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|38|error: expected identifier before ‘operator’|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp||In function ‘const int Eigen::operator+(const Eigen::MatrixBase<Derived>&, const typename Eigen::internal::traits<T>::Scalar&)’:|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|41|error: ‘scalar_add_op’ in namespace ‘Eigen::internal’ does not name a type|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|41|error: expected template-argument before ‘<’ token|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|41|error: expected ‘>’ before ‘<’ token|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|43|error: wrong number of template arguments (1, should be 2)|
/usr/local/include/Eigen/src/Core/util/ForwardDeclarations.h|91|error: provided for ‘template<class UnaryOp, class MatrixType> class Eigen::CwiseUnaryOp’|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|43|error: expected ‘::’ before ‘(’ token|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|43|error: expected identifier before ‘(’ token|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|43|error: ‘scalar_add_op’ is not a member of ‘Eigen::internal’|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|44|error: expected ‘(’ before ‘>’ token|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|50|error: ‘scalar_add_op’ in namespace ‘Eigen::internal’ does not name a type|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|50|error: expected template-argument before ‘<’ token|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|50|error: expected ‘>’ before ‘<’ token|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|52|error: wrong number of template arguments (1, should be 2)|
/usr/local/include/Eigen/src/Core/util/ForwardDeclarations.h|91|error: provided for ‘template<class UnaryOp, class MatrixType> class Eigen::CwiseUnaryOp’|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|53|error: expected ‘::’ before ‘operator’|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|53|error: expected identifier before ‘operator’|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp||In function ‘const int Eigen::operator+(const typename Eigen::internal::traits<T>::Scalar&, const Eigen::MatrixBase<Derived>&)’:|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|56|error: ‘scalar_add_op’ in namespace ‘Eigen::internal’ does not name a type|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|56|error: expected template-argument before ‘<’ token|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|56|error: expected ‘>’ before ‘<’ token|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|58|error: wrong number of template arguments (1, should be 2)|
/usr/local/include/Eigen/src/Core/util/ForwardDeclarations.h|91|error: provided for ‘template<class UnaryOp, class MatrixType> class Eigen::CwiseUnaryOp’|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|58|error: expected ‘::’ before ‘(’ token|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|58|error: expected identifier before ‘(’ token|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|58|error: ‘scalar_add_op’ is not a member of ‘Eigen::internal’|
/usr/local/include/boost/numeric/odeint/external/eigen/eigen_algebra.hpp|59|error: expected ‘(’ before ‘>’ token|
||=== Build failed: 32 error(s), 0 warning(s) (0 minute(s), 7 second(s)) ===|

我也试图加入

boost/numeric/odeint/external/eigen/eigen.hpp

代替eigen_algebra.hpp并在包含eigen_algebra.hpp时收到相同的错误消息。似乎Boost :: odeint v1.65.1与Eigen v3.3.4不兼容。我的问题是,是否有一个(非)官方头文件提供了对Eost 3.3.4到Boost :: odeint 1.65.1的支持,或者我在向量空间代数的模板特化和/或运算符重载期间做错了什么?

I also found a solution for "typecasting" std std::vector<> to Eigen::VectorXd and vice versa,但我认为使用std :: vector作为状态stype,然后在内部&#34;转换它&#34;到Eigen :: VectorXd,然后&#34;将结果转回&#34;到std :: vector&lt;&gt;由于我的向量很大,并且需要10万或更多接受的步骤来执行集成,因此导致性能低于引言中提到的性能。我希望我的问题足够准确,社区可以帮助我解决问题。

0 个答案:

没有答案