2017-09-21 21 views
0

Eigen :: Refを使用して、Eigen :: Matrix引数を使用してテンプレート以外の関数を使用したいとします。私の問題は、これらの関数では、Eigen :: Refによって参照される行列のサイズを変更する必要があるかもしれないということです。一般的にEigen :: Refは式や行列ブロックにマップできるのでサイズを変更してはいけませんが、私の場合はEigen :: Refの背後にあるものがEigen :: Matrixであると確信しています。この説明するためにEigen :: Refのサイズ変更の回避策

#include "Eigen/Dense" 

void add(Eigen::Ref<Eigen::MatrixXd> M, const Eigen::Ref<const Eigen::MatrixXd> &A, const Eigen::Ref<const Eigen::MatrixXd> &B) { 
    M=A+B; 
} 

int main() { 
    Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::ColMajor, 32, 32> M(2,3); 
    Eigen::Matrix<double, 2, 2> A; 
    Eigen::Matrix<double, 2, 2> B; 

    add(M,A,B); 
} 

は、実行時に提供します:

void add(Eigen::Ref<Eigen::MatrixXd> M, const Eigen::Ref<const Eigen::MatrixXd> &A, const Eigen::Ref<const Eigen::MatrixXd> &B) { 
    Eigen::Ref<Eigen::Matrix<double,2,2>> MM(M); 
    MM=A+B; 
} 

が、私は、実行時に得た:

void Eigen::DenseBase<Derived>::resize(Eigen::Index, Eigen::Index) [with Derived = Eigen::Ref<Eigen::Matrix<double, -1, -1> >; Eigen::Index = long int]: Assertion `rows == this->rows() && cols == this->cols() && "DenseBase::resize() does not actually allow to resize."' failed. 

私はそれをカンニングしようとした

Eigen::internal::variable_if_dynamic<T, Value>::variable_if_dynamic(T) [with T = long int; int Value = 2]: Assertion `v == T(Value)' failed. 

これを処理するにはどうすればよいですか? Eigenのドキュメントでは、サイズ変更の問題は引数としてMatrixBaseを使用するテンプレート関数に対して扱いますが、Eigen :: Ref?ここで

+1

:: MatrixXd& M? – chtz

+0

申し訳ありませんが、あなたの質問を完全に読んだことはありません。 '32'が常に同じではないと仮定すると、テンプレートパラメータとして渡すことができます。さもなければ、私はこれを実装する安全な方法を見ません。 – chtz

+0

私はそれを仮想化したいので、私はテンプレート関数を望んでいません。 – janou195

答えて

1

は、メンバ関数ポインタと残忍なキャストを使用してハックソリューションです:

#include <iostream> 
#include <Eigen/Core> 
template<class MatrixType> 
struct ResizableRef 
{ 
    typedef typename MatrixType::Scalar Scalar; 
    class MatrixDummy; 
    typedef void (MatrixDummy::*ResizeFunctor)(Eigen::Index rows, Eigen::Index Cols); 
    typedef Scalar* (MatrixDummy::*DataGetter)(); 

    MatrixDummy *m; 
    const ResizeFunctor resizer; 
    const DataGetter getData; 

    template<class Derived> 
    ResizableRef(Eigen::MatrixBase<Derived>& M) 
     : m(reinterpret_cast<MatrixDummy*>(&M)) 
     , resizer(reinterpret_cast<ResizeFunctor>((void (Derived::*)(Eigen::Index, Eigen::Index)) &Derived::resize)) 
     , getData(reinterpret_cast<DataGetter>((Scalar* (Derived::*)()) &Derived::data)) 
    { } 

    template<class Derived> 
    ResizableRef& operator=(const Eigen::EigenBase<Derived>& other) 
    { 
     (m->*resizer)(other.rows(), other.cols()); 
     MatrixType::Map((m->*getData)(), other.rows(), other.cols()) = other; 
    } 
}; 

void foo(ResizableRef<Eigen::MatrixXd> A) 
{ 
    A = Eigen::Matrix2d::Identity(); 
} 

int main(int argc, char *argv[]) 
{ 
    using namespace Eigen; 
    MatrixXd A; 
    Matrix<double, Dynamic, Dynamic, Eigen::ColMajor, 20, 12> B; 
    Matrix<double, 2, Dynamic, Eigen::ColMajor, 2, 4> C; 
    Matrix2d D; 
    foo(A); 
    foo(B); 
    foo(C); 
    foo(D); 

    std::cout << A << "\n\n" << B << "\n\n" << C << "\n\n" << D << '\n'; 
} 

これはおそらく、厳密なエイリアシング規則を破ると私は一般的に再考してデザインに助言します。しかし、不要な実行時の割り当てなしで動作するはずですし、それはいくつかの間違った使用法に対して安全である:あなたはそれが `固有に合格していない理由を`アイゲン:: MatrixXd`を、参照することが確実な場合

MatrixXf fail1; 
    Matrix3d fail2; 
    foo(fail1); // fails at compile time 
    foo(fail2); // fails at runtime