Eigen::Ref for concatenating matrices

前端 未结 2 1127
野性不改
野性不改 2020-12-10 21:45

If I want to concatenate two matrices A and B, I would do

using Eigen::MatrixXd;
const MatrixXd A(n, p);
const MatrixXd B(n, q);
Ma         


        
相关标签:
2条回答
  • 2020-12-10 22:20

    I'll add the C++14 version of @ggaels horizcat as an answer. The implementation is a bit sloppy in that it does not consider the Eigen compile-time constants, but in return it's only a two-liner:

    auto horizcat = [](auto expr1, auto expr2)
    {
        auto get = [expr1=std::move(expr1),expr2=std::move(expr2)](auto row, auto col)
                { return col<expr1.cols() ? expr1(row, col) : expr2(row, col - expr1.cols());};
        return Eigen::Matrix<decltype(get(0,0)), Eigen::Dynamic, Eigen::Dynamic>::NullaryExpr(expr1.rows(), expr1.cols() + expr2.cols(), get);
    };
    
    int main()
    {
      Eigen::MatrixXd mat(3, 3);
      mat << 0, 1, 2, 3, 4, 5, 6, 7, 8;
    
      auto example1 = horizcat(mat,2*mat);
      std::cout << example1 << std::endl;
    
      auto example2 = horizcat(Eigen::MatrixXd::Identity(3,3), mat);
      std::cout << example2 << std::endl;
      return 0;
    }
    

    Note that the code is untested.

    That should be appropriate for most applications. However, in case you're using compile-time matrix dimensions and require maximum performance, prefer ggaels answer. In all other cases, also prefer ggaels answer, because he is the developer of Eigen :-)

    0 讨论(0)
  • 2020-12-10 22:37

    No, Ref is not designed for that. We/You would need to define a new expression for that, that could be called Cat. If you only need to concatenate two matrices horizontally, in Eigen 3.3, this can be implemented in less than a dozen of lines of code as a nullary expression, see some exemple there.

    Edit: here is a self-contained example showing that one can mix matrices and expressions:

    #include <iostream>
    #include <Eigen/Core>
    
    using namespace Eigen;
    
    template<typename Arg1, typename Arg2>
    struct horizcat_helper {
      typedef Matrix<typename Arg1::Scalar,
        Arg1::RowsAtCompileTime,
        Arg1::ColsAtCompileTime==Dynamic || Arg2::ColsAtCompileTime==Dynamic
        ? Dynamic : Arg1::ColsAtCompileTime+Arg2::ColsAtCompileTime,
        ColMajor,
        Arg1::MaxRowsAtCompileTime,
        Arg1::MaxColsAtCompileTime==Dynamic || Arg2::MaxColsAtCompileTime==Dynamic
        ? Dynamic : Arg1::MaxColsAtCompileTime+Arg2::MaxColsAtCompileTime> MatrixType;
    };
    
    template<typename Arg1, typename Arg2>
    class horizcat_functor
    {
      const typename Arg1::Nested m_mat1;
      const typename Arg2::Nested m_mat2;
    
    public:
      horizcat_functor(const Arg1& arg1, const Arg2& arg2)
        : m_mat1(arg1), m_mat2(arg2)
      {}
    
      const typename Arg1::Scalar operator() (Index row, Index col) const {
        if (col < m_mat1.cols())
          return m_mat1(row,col);
        return m_mat2(row, col - m_mat1.cols());
      }
    };
    
    template <typename Arg1, typename Arg2>
    CwiseNullaryOp<horizcat_functor<Arg1,Arg2>, typename horizcat_helper<Arg1,Arg2>::MatrixType>
    horizcat(const Eigen::MatrixBase<Arg1>& arg1, const Eigen::MatrixBase<Arg2>& arg2)
    {
      typedef typename horizcat_helper<Arg1,Arg2>::MatrixType MatrixType;
      return MatrixType::NullaryExpr(arg1.rows(), arg1.cols()+arg2.cols(),
                                    horizcat_functor<Arg1,Arg2>(arg1.derived(),arg2.derived()));
    }
    
    int main()
    {
      MatrixXd mat(3, 3);
      mat << 0, 1, 2, 3, 4, 5, 6, 7, 8;
    
      auto example1 = horizcat(mat,2*mat);
      std::cout << example1 << std::endl;
    
      auto example2 = horizcat(VectorXd::Ones(3),mat);
      std::cout << example2 << std::endl;
      return 0;
    }
    
    0 讨论(0)
提交回复
热议问题