German Capuano
German Capuano

Reputation: 5393

Unclear return type for function taking eigen types as parameters

I'm trying to use the Eigen3 library in a scientific program but I'm struggling to make some simple functions and member functions. For example, I'm not certain what kind of return type should I choose for something like the following:

template <typename DerivedA,typename DerivedB>
inline **something** mult(const MatrixBase<DerivedA>& p1,
                          const MatrixBase<DerivedB>& p2)
  {
  return p1*p2;
  }

I assume that there is some class, say productOp, that I could return without a problem. I still could not imagine what would happen in a function involving a large number of operations, or even worse, an iteration that depends on the input:

template <typename Derived>
**something** foo(const MatrixBase<Derived>& p1))
  {
  **something** p2;
  p2.setZero();
  while(p2(0,0) < 1)
    p2 += p1; 
  return p2;
  }

My questions are:

  1. Is the second example even possible?
  2. How can I figure the type of an operation like p1*p2?
  3. How can I figure the return type in the case of elaborate functions?

Upvotes: 5

Views: 844

Answers (3)

ggael
ggael

Reputation: 29205

In the first example, returning auto will works well because it is a single expression that does not reference any local temporary.

In the second, you need to create and return an actual matrix/vector with its own storage, for instance:

typename Derived::PlainObject p2;
p2.resizeLike(p1);

and the return type will be typename Derived::PlainObject.

Upvotes: 3

chtz
chtz

Reputation: 18807

Here is a manual solution for the first expression, in case you don't want to use C++11 or you want to be sure that the expression is actually evaluated:

template<class DerivedA, class DerivedB>
Eigen::Matrix<typename Eigen::ScalarBinaryOpTraits<typename DerivedA::Scalar, typename DerivedB::Scalar>::ReturnType, 
              DerivedA::RowsAtCompileTime, DerivedB::ColsAtCompileTime>
mult(const Eigen::MatrixBase<DerivedA>& p1, const Eigen::MatrixBase<DerivedB>& p2)
{
    return p1*p2;
}

ScalarBinarayOpTraits is used to determine if two different scalar types can be combined (e.g., double and std::complex<double>).

Example usage:

Eigen::Matrix3Xcd M1 = mult(Eigen::Matrix3d(), Eigen::Matrix3Xcd(3,20));

This is also safer, if you pass temporary objects to mult and store the result in an auto variable, e.g.:

double *someData = ...;
Eigen::MatrixXd someMatrix = ...; 
auto result = mult(Eigen::Matrix3d::Map(someData), someMatrix.topLeftCorner<3,4>());

For the second example, as ggael wrote typename Derived::PlainObject would be sufficient. And you can use p2.setZero(p1.rows(), p2.cols()); to initializep2`;

Upvotes: 1

NathanOliver
NathanOliver

Reputation: 180500

One thing you could do if the documentation does not like auto for the return type is use trailing return type and get they type of DerivedA * DerivedB. That would look like

inline auto mult(...) -> MatrixBase<decltype(std::declval<DerivedA>() * std::decval<DerivedB>())>

Upvotes: 1

Related Questions