简体   繁体   中英

Eigen3: defining a variable size matrix

I want to write a routine to create the transpose of a matrix as a row major double matrix using Eigen3 (inside RcppEigen ). In the main I will use it for matrices of different size.

In Eigen3 the template Matrix takes 6 arguments:

  • Three are compulsory:
    (Scalar, RowsAtCompileTime and ColsAtCompileTime)

  • Three are optional:
    (Options, MaxRowsAtCompileTime and MaxColsAtCompileTime)
    Options can be RowMajor or ColMajor

I prefer to dynamically assign the dimensions to matrices because I work with large datasets and I want to avoid wasting RAM.

So, I wrote the following

Eigen::MatrixXd mktrasp(Eigen::MatrixXd X const int n, const int p){
  Eigen::Matrix<double, p, n, RowMajor> T;
  T = X.transpose();
  return T;
}

But I get the compiler errors

error: 'p' cannot appear in a constant-expression
error: 'n' cannot appear in a constant-expression

I imagine this happens because n and p are not known at compile time.

So I tried this solution

Eigen::MatrixXd mktrasp(Eigen::MatrixXd X, const int n, const int p){
  Eigen::Matrix<double, Dynamic, Dynamic, RowMajor> T(p, n);
  T = X.transpose();
  return T;
}

This works but I have completely lost the plot. Is T a dynamic matrix or fixed size now? Is it safe to do this? Can someone suggest a better approach?

In many cases it makes a lot of sense to dynamically allocate arrays/matrices. In addition to the advantage of not over-claiming memory I would say that the greatest advantage is that the dimensions of the matrix propagate though your code, since it is an attribute to your matrix. For your example you can at any point get the dimensions by

A.rows(); // number of rows    (at runtime)
A.cols(); // number of columns (at runtime)
A.size(); // total size of the 'plain storage' (at runtime)

Your example now becomes as simple as

#include <iostream>
#include <Eigen/Eigen>

typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> MatD;

MatD mktrasp(const MatD &X)
{
  return X.transpose();
}

int main()
{
  MatD A = MatD::Random(5,5);

  MatD B = mktrasp(A);

  std::cout << "A = " << std::endl << A << std::endl;
  std::cout << "B = " << std::endl << B << std::endl;
}

If you would like to work with some temporary variable, as featured in your example, you can also use:

MatD mktrasp(const MatD &X)
{
  // copies the transpose of "X" -> T
  // N.B. the dimensions (and possible other attributes) are also copied
  // you would thus find that "T.rows() == X.cols()"
  // (or if you would do "MatD A = X": "T.rows() == X.rows()")
  MatD T = X.transpose(); 

  return T;
}

BTW you got very close, but you were overcomplicating / overthinking. In many (almost all) cases you can and should really avoid passing array sizes in C++. It makes your code more readable, more maintainable, and less error prone.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM