我需要访问包含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后,似乎我的表现不如建议的答案。
答案 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;