在Eigen中进行矢量拼接,返回一个表达式。

huangapple go评论63阅读模式
英文:

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';
}

huangapple
  • 本文由 发表于 2023年5月18日 10:32:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76277367.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定