[eigen] generic argument declaration taking a matrix, vector or expression

[ Thread Index | Date Index | More lists.tuxfamily.org/eigen Archives ]


Hi all,

we are trying to implement functions, which can take a reference to a (templated) Eigen matrix, vector or an Eigen expression. At http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html it's documented how to achieve this, however this approach is not compiling in our case.

Assume the following:

Eigen::MatrixXf A; // float matrix
Eigen::MatrixXi B; // integer matrix
Eigen::VectorXf c; // float vector

Particularly we would like to call a templated function foo with all of the following statements

foo (A)
foo (B)
foo (A.col(i));
foo (c)

such that no data is copied and results can be written back to the particular matrix (or column of the matrix).
If we understand the tutorial correctly, foo should look like

template <typename TypeT>
void foo (const Eigen::MatrixBase<TypeT> &mat);

where a const cast needs to be used to write data back to mat.

I attached a an example, which should make more clear what we are trying to achieve.
The compiler error we get for this example reads as follows:

make test_eigen_matrices
[100%] Building CXX object CMakeFiles/test_eigen_matrices.dir/tests/test_eigen_matrices.cpp.o
tests/test_eigen_matrices.cpp: In function ‘int main(int, char**)’:
tests/test_eigen_matrices.cpp:65:38: error: no matching function for call to ‘solveLeastSquares(Eigen::MatrixXf&, Eigen::DenseBase<Eigen::Matrix<float, -0x00000000000000001, -0x00000000000000001> >::ColXpr, Eigen::VectorXf&)’ tests/test_eigen_matrices.cpp:73:47: error: no matching function for call to ‘solveLeastSquares(Eigen::MatrixXf&, Eigen::DenseBase<Eigen::Matrix<float, -0x00000000000000001, -0x00000000000000001> >::ColXpr, Eigen::DenseBase<Eigen::Matrix<float, -0x00000000000000001, -0x00000000000000001> >::ColXpr)’ make[3]: *** [CMakeFiles/test_eigen_matrices.dir/tests/test_eigen_matrices.cpp.o] Error 1
make[2]: *** [CMakeFiles/test_eigen_matrices.dir/all] Error 2
make[1]: *** [CMakeFiles/test_eigen_matrices.dir/rule] Error 2
make: *** [test_eigen_matrices] Error 2

Can you please help us to understand how the correct declaration would look like. Is such a generic declaration possible after all? If not, how can we avoid copying data and handle a matrix, vector or expression as possible argument.

Thanks for your help.

Cheers,
Bernhard
/*
 * test_eigen_matrices.cpp
 *
 *  Created on: Jan 10, 2012
 *      Author: bzeisl
 */

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

enum LEAST_SQUARES_METHOD {
  SVD = 0,
  CHOLESKY,
  PSEUDO_INVERSE
};

// template <typename TypeT> void
// solveLeastSquares (const Eigen::Matrix<TypeT, Eigen::Dynamic, Eigen::Dynamic> &A, const Eigen::Matrix<TypeT, Eigen::Dynamic, Eigen::Dynamic> &b,
//                    Eigen::Matrix<TypeT, Eigen::Dynamic, Eigen::Dynamic> &x, LEAST_SQUARES_METHOD method = SVD)

template <typename TypeT> void
solveLeastSquares (const Eigen::MatrixBase<TypeT> &A, const Eigen::MatrixBase<TypeT> &b, Eigen::MatrixBase<TypeT> const &x_, LEAST_SQUARES_METHOD method = SVD)

{
  Eigen::MatrixBase<TypeT> &x = const_cast<Eigen::MatrixBase<TypeT> &> (x_);

  switch (method)
  {
    case SVD:
      x = A.jacobiSvd (Eigen::ComputeThinU | Eigen::ComputeThinV).solve (b);
      break;
    case CHOLESKY:
      x = A.ldlt ().solve (b);
      break;
    case PSEUDO_INVERSE:
      x = (A.transpose() * A).inverse() * A.transpose() * b;
      break;
    default:
      std::cout << "[solveLeastSquares] Least squares method (" << (int)method << ") not known." << std::endl;
      break;
  }
}

int
main (int argc, char* argv[])
{
  /** objective: solve the least squares system
   *  arg min_{x_i} 1/2 sum_i || b_i - A x_i ||_2^2  =  arg min_X 1/2 || B - A X ||_F^2
   */

  Eigen::MatrixXf A = Eigen::MatrixXf::Random (1000,200);
  Eigen::MatrixXf B = Eigen::MatrixXf::Random (1000,100);
  Eigen::MatrixXf X (200,100);


  // 1st test: solve for whole matrices
  solveLeastSquares (A, B, X); // compiles fine
  // expected result: X contains the solution


  // 2nd test: loop over data vector B
  Eigen::VectorXf x;
  for (int i = 0; i < B.cols(); ++i)
  {
    solveLeastSquares (A, B.col(i), x); // compile error
    // expected result: x contains the solution for the data sample b_i = B.col(i)
  }


  // 3rd test: loop over data matrix B and over result matrix X
  for (int i = 0; i < B.cols(); ++i)
  {
      solveLeastSquares (A, B.col(i), X.col(i)); // compile error
  }
  // expected result: the solution x_i for b_i = B.col(i) is written consecutively in the ith column in X .
  //                   finally X contains the result.

  return EXIT_SUCCESS;
}




Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/