Eigen,如何访问MatrixBase <derived> </derived>的底层数组

时间:2014-08-02 12:17:49

标签: c++ eigen

我需要访问包含MatrixBase Eigen矩阵数据的数组。

Eigen库具有data()方法,该方法返回指向数组的指针,但只能从Matrix type访问。 MatrixBase没有类似的方法,即使MatrixBase类应该作为模板,实际类型应该只是一个矩阵。如果我尝试访问MatrixBase.data(),我会收到编译时错误:

template <typename ScalarA, typename Index, typename DerivedB, typename DerivedC>
void uscgemv(float alpha, 
     const USCMatrix<ScalarA,Index> &a,
     const MatrixBase<DerivedB> &b,
     const MatrixBase<DerivedC> &c_const)
{
    //...some code
    float * bMat = b.data();
    ///more code
}

此代码产生以下编译时错误。

error: ‘const class Eigen::MatrixBase<Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<float>, Eigen::Matrix<float, -1, 1> > >’ has no member named ‘data’
 float * bMat = b.data();

所以我不得不诉诸诸如......之类的噱头。

float * bMat;
int bRows = b.rows();
int bCols = b.cols();
mallocPinnedMemory(&bMat, bRows*bCols*sizeof(float));
Eigen::Map<Matrix<float, Dynamic, Dynamic> > bmat_temp(bMat, bRows, bCols);
bmat_temp = b;  //THis is SLOW, we should avoid it.

然后我可以访问bMat数组......

这些副本来回是gpu矩阵乘法中的最大成本,因为我基本上需要制作一个额外的副本,甚至在应用到设备之前......

我不能使用Eigen-magma,因为这是一种稀疏矩阵 - 奇怪的格式到密集矩阵(或有时是向量)乘法,所以我不能使用任何自动gpu功能那里。另外,我宁愿不将矩阵声明为其他东西,因为这需要在整个程序中更改大量代码(我没有写过)。

编辑:提出了静态演员解决方案:

float * bMat = (static_cast<Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> >(b)).data();

然而,当我第一次尝试访问数组bMat的元素时,我得到段错误。

编辑2:我正在寻找一种零拷贝方式来访问底层阵列。我只需要能够读取b,但我还需要能够写入c。目前c与以下宏不一致:

#define UNCONST(t,c,uc) Eigen::MatrixBase<t> &uc = const_cast<Eigen::MatrixBase<t>&>(c);

编辑3:在交叉发布到Eigen Forums后,似乎我的表现不如建议的答案。

3 个答案:

答案 0 :(得分:7)

MatrixBase是任何密集表达式的基类。它不一定对应于具有存储的对象。例如,可以是A+B的抽象表示,或者在您的情况下是具有常量值的向量的抽象表示。您可以使uscgemv仅使用Ref<>类接受具有适当存储空间的表达式,例如:

template <typename ScalarA, typename Index>
void uscgemv(float alpha, 
 const USCMatrix<ScalarA,Index> &a,
 Ref<const VectorXf> b,
 Ref<VectorXf> c);

如果第三个参数与VectorXf的存储不匹配,那么它将为您进行评估。然后你可以安全地拨打b.data()。要保持b通用的标量类型,您仍然可以将其声明为MatrixBase<DerivedB>&,然后将其复制到Ref<const Matrix<typename DerivedB::Scalar, DerivedB::RowsAtCompileTime, DerivedB::ColsAtCompileTime> >

typedef Ref<const Matrix<typename DerivedB::Scalar,  DerivedB::RowsAtCompileTime, DerivedB::ColsAtCompileTime> > RefB;
RefB actual_b(b);
actual_b.data();

答案 1 :(得分:0)

我想问题是:你不能获得指向MatrixBase<Derived>数据的指针,因为后者可以是Eigen中的任何一种表达式,就像矩阵的乘积一样例。要获得指针,您可能必须先将MatrixBase<Derived>隐式转换为Matrix<Scalar, Dynamic, Dynamic>,然后使用后者的data()成员。

因此,您可以创建表达式的深层副本,即使用类似

的内容
Eigen::Matrix<typename Derived::Scalar, Eigen::Dynamic, Eigen::Dynamic tmp = b;

然后使用

tmp.data()

此代码现在可以使用

#include <Eigen/Dense>
#include <iostream>

template<typename Derived>
void use_data\
(const Eigen::MatrixBase<Derived>& mat)
{

    Eigen::Matrix<typename Derived::Scalar, Eigen::Dynamic, Eigen::Dynamic>tmp = mat();
    typename Derived::Scalar* p = tmp.data();

    std::cout << std::endl;
    for(std::size_t i = 0; i < tmp.size(); i++)
        std::cout << *(p+i) << " ";

}

int main()
{
    Eigen::MatrixXd A = Eigen::MatrixXd::Random(2, 2); 
    Eigen::MatrixXd B = Eigen::MatrixXd::Random(2, 2); 

    // now A*B is an expression, of type MatrixBase<EigenSum....>
    use_data(A + B);
}

答案 2 :(得分:0)

有一个简单的解决方案可以解决你的问题,结合EigenMap,&amp; a(0,0)和const_cast你可以重新启动MatrixBase的缓冲区。

示例:

template<typename Derived1,
         typename Derived2>
void example(Eigen::MatrixBase<Derived1> const &input,
             Eigen::MatrixBase<Derived2> const &output)
{
    static_assert(std::is_same<Derived1::Scalar, Derived2::Scalar>::value,
                  "Data type of matrix input, weight, bias and output should be the same");   

        using Scalar = typename Derived3::Scalar;
        using MatType = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
        using Mapper = Eigen::Map<const MatType, Eigen::Aligned>;

        //in the worst case, you can do const_cast<Scalar *> on
        //&bias(0, 0).That is, if you cannot explicitly define the Map
        //type as const        
        Mapper Map(&input(0, 0), input.size());
        output.colwise() += Map; 
    }
}

我在windows 8上尝试,vc2013 32bits,Eigen版本是3.2.5,没有出现分段错误(还),每个东西看起来都很好。我还检查了Map的地址,它与原始输入相同。您可以使用其他示例进行验证

#include <Eigen/Dense>

#include <iostream>

template<typename Derived>
void example_2(Eigen::MatrixBase<Derived> &input)
{
    using Scalar = decltype(input[0]);

    Eigen::Map<Derived> map(&input(0, 0),
                            input.rows(),
                            input.cols());
    map(0, 0) = 300;
}

int main()
{           
    Eigen::MatrixXd mat(2, 2);
    mat<<0, 1, 2, 3;
    example_2(mat);
    std::cout<<mat<<"\n\n";    

    return 0;
}

mat的第一个元素是&#34; 300&#34;