英文:
Vector concatenation in Eigen returning an expression
问题
在Eigen中是否有一种方法可以在不复制数据的情况下连接向量?
在这里
https://stackoverflow.com/q/25691324/11000897
以及在这里
https://stackoverflow.com/q/21496157/11000897
连接是通过为新向量分配内存,然后复制数据来完成的。
我想问的是是否有一种方法可以创建一个表达式(包含对原始数据的引用),以便不会复制数据,也不会分配新内存。
英文:
Is there a way to concatenate vectors in Eigen without having to duplicate data?
Here
https://stackoverflow.com/q/25691324/11000897
and here
https://stackoverflow.com/q/21496157/11000897
concatenation is done by allocating memory for a new vector and then duplicating the data.
What I am asking is whether there is a way to create an expression instead (containing the references to the original data), so that data is not duplicated and no new memory allocated.
答案1
得分: 1
以下是您提供的内容的中文翻译:
不分配新向量的问题在于它会破坏向量化,除非编译器可以处理(这不太可能)。问题在于现在每次访问都有一个if-else。
因此,通常最好要么创建一个新的向量,要么分别循环遍历向量段。
如果您真的想要创建一个连接操作,可以使用nullary-expressions。这是它可能看起来的一个简要概述:
#include <Eigen/Dense>
template<class Arg1, class Arg2>
struct RowConcatFunctor
{
enum {
RowsAtCompileTime =
Arg1::RowsAtCompileTime == Eigen::Dynamic ||
Arg2::RowsAtCompileTime == Eigen::Dynamic ?
Eigen::Dynamic :
Arg1::RowsAtCompileTime + Arg2::RowsAtCompileTime,
ColsAtCompileTime = Arg1::ColsAtCompileTime,
IsRowMajor = Arg1::IsRowMajor
};
using Scalar = typename Arg1::Scalar;
using MatrixType = Eigen::Matrix<Scalar, RowsAtCompileTime,
ColsAtCompileTime, IsRowMajor ? Eigen::RowMajor : 0>;
const Arg1& first;
const Arg2& second;
const Scalar& operator()(Eigen::Index row, Eigen::Index col) const
{
return row < first.rows() ? first(row, col) :
second(row - first.rows(), col);
}
};
template <class Arg1, class Arg2>
Eigen::CwiseNullaryOp<RowConcatFunctor<Arg1, Arg2>,
typename RowConcatFunctor<Arg1, Arg2>::MatrixType>
concatRows(const Eigen::MatrixBase<Arg1>& first,
const Eigen::MatrixBase<Arg2>& second)
{
using Functor = RowConcatFunctor<Arg1, Arg2>;
using MatrixType = typename Functor::MatrixType;
const Eigen::Index rows = first.rows() + second.rows();
assert(first.cols() == second.cols());
return MatrixType::NullaryExpr(rows, first.cols(),
Functor{first.derived(), second.derived()});
}
#include <iostream>
int main()
{
Eigen::MatrixXd a = Eigen::MatrixXd::Random(3, 4);
Eigen::MatrixXd b = Eigen::MatrixXd::Random(2, 4);
std::cout << a << "\n\n" << b << "\n\n"
<< concatRows(a, b) << '\n';
}
英文:
The trouble with not allocating a new vector is that it defeats vectorization, unless the compiler can pick up the pieces (which I wouldn't count on). The issue is that now you have an if-else in every access.
Therefore it is usually better to either create a new vector or loop over the vector segments separately.
If you truly want to create a concat operation, you can use nullary-expressions. This is a quick outline of how it might look:
#include <Eigen/Dense>
template<class Arg1, class Arg2>
struct RowConcatFunctor
{
enum {
RowsAtCompileTime =
Arg1::RowsAtCompileTime == Eigen::Dynamic ||
Arg2::RowsAtCompileTime == Eigen::Dynamic ?
Eigen::Dynamic :
Arg1::RowsAtCompileTime + Arg2::RowsAtCompileTime,
ColsAtCompileTime = Arg1::ColsAtCompileTime,
IsRowMajor = Arg1::IsRowMajor
};
using Scalar = typename Arg1::Scalar;
using MatrixType = Eigen::Matrix<Scalar, RowsAtCompileTime,
ColsAtCompileTime, IsRowMajor ? Eigen::RowMajor : 0>;
const Arg1& first;
const Arg2& second;
const Scalar& operator()(Eigen::Index row, Eigen::Index col) const
{
return row < first.rows() ? first(row, col) :
second(row - first.rows(), col);
}
};
template <class Arg1, class Arg2>
Eigen::CwiseNullaryOp<RowConcatFunctor<Arg1, Arg2>,
typename RowConcatFunctor<Arg1, Arg2>::MatrixType>
concatRows(const Eigen::MatrixBase<Arg1>& first,
const Eigen::MatrixBase<Arg2>& second)
{
using Functor = RowConcatFunctor<Arg1, Arg2>;
using MatrixType = typename Functor::MatrixType;
const Eigen::Index rows = first.rows() + second.rows();
assert(first.cols() == second.cols());
return MatrixType::NullaryExpr(rows, first.cols(),
Functor{first.derived(), second.derived()});
}
#include <iostream>
int main()
{
Eigen::MatrixXd a = Eigen::MatrixXd::Random(3, 4);
Eigen::MatrixXd b = Eigen::MatrixXd::Random(2, 4);
std::cout << a << "\n\n" << b << "\n\n"
<< concatRows(a, b) << '\n';
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论