我打算解决几个形式为d/dt (X) = F(X)
的矩阵微分方程,其中X
是一个大的复数矩阵,F
表示它的一些函数。我尝试将Boost的 odeint 与state_type
一起用作Armadillo的cx_mat
。但它会产生受控步进器类型的编译错误。我的示例代码如下
#include <armadillo>
#include <iostream>
#include <boost/numeric/odeint.hpp>
using namespace std;
using namespace arma;
using namespace boost::numeric::odeint;
using state_type = arma::cx_mat;
void ode(const state_type& X, state_type& derr, double) {
derr = X; // sample derivative, can be anything else
}
// define resizable and norm_inf
namespace boost { namespace numeric { namespace odeint {
template <>
struct is_resizeable<arma::cx_mat> {
typedef boost::true_type type;
const static bool value = type::value;
};
template <>
struct same_size_impl<arma::cx_mat, arma::cx_mat> {
static bool same_size(const arma::cx_mat& x, const arma::cx_mat& y)
{
return arma::size(x) == arma::size(y);
}
};
template<>
struct resize_impl<arma::cx_mat, arma::cx_mat> {
static void resize(arma::cx_mat& v1, const arma::cx_mat& v2) {
v1.resize(arma::size(v2));
}
};
template<>
struct vector_space_norm_inf<state_type> {
typedef double result_type;
result_type operator()(const state_type& p) const
{
return arma::norm(p, "inf");
}
};
} } } // namespace boost::numeric::odeint
using stepper = runge_kutta_dopri5<state_type, double, state_type, double, vector_space_algebra>;
int main () {
cx_mat A = randu<cx_mat>(4, 4);
integrate_adaptive( make_controlled<stepper>(1E-10, 1E-10), ode, A, 0.0 , 10.0, 0.1);
}
此代码提供以下编译错误:
/usr/include/armadillo_bits/Mat_meat.hpp:5153:3: error: static assertion failed: error: incorrect or unsupported type
arma_type_check(( is_same_type< eT, typename T1::elem_type >::no ));
我能理解的是,Armadillo不支持将真实矩阵(mat
)复制到复杂矩阵(cx_mat
)中,例如
mat Z = something;
cx_mat Y = Z; // ERROR
在 odeint 的某处发生了这种情况。现在我通过将整个矩阵复制到std::vector<std::complex<double> >
将其放入函数ode
来克服这个问题,然后在函数内再次将整个std::vector<std::complex<double> >
复制到cx_mat
中,计算{{1}然后将其复制到F(X)
并返回。显然,这是非常缓慢和低效的。
问题的任何简单解决方案? 如果可能的话,我可能想转移到Eigen,如果这有帮助的话。
答案 0 :(得分:0)
是的,复杂的状态类型不适合自适应步进器,因为odeint不区分state_type和error_type。即它也使用state_type来存储错误,但是这对于复数值state_types不起作用,而错误应该是双值矩阵。我不确定Eigen对此有多好,但值得一试。随意在https://github.com/headmyshoulder/odeint-v2上提交一张票,但这将是一个很大的变化......
答案 1 :(得分:0)
嗨,我知道这已经很老了,但是当我遇到相同的问题时偶然发现了它,所以我想分享我的解决方案。我使用了Eigen,并在Armadillo中添加了一些与您类似的小附加功能,它为我工作(使用icpc和g ++测试了编译)。 这里是一个最小的代码片段:
#include<Eigen/Eigen>
#include<boost/numeric/odeint.hpp>
#include<iostream>
#include<complex>
#include<boost/numeric/odeint/external/eigen/eigen_algebra.hpp>
typedef std::complex<double> cdoub;
typedef Eigen::MatrixXcd state_type;
namespace boost {
namespace numeric {
namespace odeint {
template<typename B,int S1,int S2,int O, int M1, int M2>
struct algebra_dispatcher< Eigen::Matrix<B,S1,S2,O,M1,M2> >
{
typedef vector_space_algebra algebra_type;
};
template<>
struct vector_space_norm_inf<state_type> {
typedef double result_type;
result_type operator()(const state_type& p) const
{
return p.lpNorm<Eigen::Infinity>();
}
};
}}}
namespace Eigen {
template<typename D, int Rows, int Cols>
Matrix<D, Rows, Cols> operator/(const Matrix<D, Rows, Cols>& v1, const Matrix<D, Rows, Cols>& v2)
{
return v1.array()/v2.array();
}
template<typename D, int Rows, int Cols>
Matrix<D, Rows, Cols>
abs(Matrix<D, Rows, Cols> const& m) {
return m.cwiseAbs();
}
}
/* The rhs of x' = f(x) */
void harmonic_oscillator( const state_type &x , state_type &dxdt , const double /* t */ )
{
dxdt = x;
}
//]
int main() {
using namespace boost::numeric::odeint;
state_type X0(3,3);
X0 = state_type::Random(3,3);
state_type xout = X0;
typedef runge_kutta_dopri5<state_type,double,state_type,double,vector_space_algebra> error_stepper_type;
typedef controlled_runge_kutta< error_stepper_type > controlled_stepper_type;
controlled_stepper_type controlled_stepper;
double t =0.0;
double dt = 0.1;
controlled_stepper.try_step(harmonic_oscillator, X0, t, dt);
std::cout << X0 << std::endl;
}
也许问题已经解决了,但是五天前在这里再次提出问题时,https://gist.github.com/jefftrull/5625b77c0f86c439f29f我想与大家分享一下,希望能有所帮助:)