Search code examples
eigen

Repeating each elements of an Eigen Matrix both row wise and column wise


Given an Eigen Matrix, say

Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> A(2, 2);
A << 11, 12, 21, 22;

what is the most elegant way to obtain a matrix B of dimensions 4x4 from A, where each element of A is repeated once both row wise and column wise.

11 11 12 12
11 11 12 12
21 21 22 22
21 21 22 22

I am looking for a generic solution that could scale to any given row and column sizes of A.


Solution

  • Using the head of Eigen you write such a repelem in a few lines of code:

    template<typename XprType, typename RowFactorType, typename ColFactorType>
    auto repelem(const XprType &xpr, RowFactorType row_factor, ColFactorType col_factor) {
        using namespace Eigen;
    
        const int RowFactor = internal::get_fixed_value<RowFactorType>::value;
        const int ColFactor = internal::get_fixed_value<ColFactorType>::value;
        const int NRows = XprType::RowsAtCompileTime == Dynamic || RowFactor == Dynamic ? Dynamic : XprType::RowsAtCompileTime*RowFactor;
        const int NCols = XprType::ColsAtCompileTime == Dynamic || ColFactor == Dynamic ? Dynamic : XprType::ColsAtCompileTime*ColFactor;
        const int nrows = internal::get_runtime_value(row_factor) * xpr.rows();
        const int ncols = internal::get_runtime_value(col_factor) * xpr.cols();
    
        return xpr(
            Array<int,NRows,1>::LinSpaced(nrows,0,xpr.rows()-1),
            Array<int,NCols,1>::LinSpaced(ncols,0,xpr.cols()-1)
        );
    }
    

    Usage:

    Array22i A;
    A << 1, 2, 3, 4;
    std::cout << repelem(A,2,2) << "\n";
    

    Full demo: https://godbolt.org/z/rYgDxF

    This code might look a bit complicated but it is so to preserve compile-time sizes as proved by the following test:

    Array22i A;
    static_assert(decltype(repelem(A,fix<2>,fix<2>))::RowsAtCompileTime==4,"Bad compile-time size");
    

    People can track its inclusion within Eigen there.