This forum has been archived. All content is frozen. Please use KDE Discuss instead.

Problem with template substitution of MatrixBase

Tags: None
(comma "," separated)
Horus
Registered Member
Posts
296
Karma
0
OS
Hello,

I have these two functions to approximatly compare objects:

Code: Select all
template <class DerivedA, class DerivedB>
constexpr bool equals (const Eigen::PlainObjectBase<DerivedA>& A,
                       const Eigen::PlainObjectBase<DerivedB>& B,
                       double tolerance = NUMERICAL_ZERO_DIFFERENCE)
{
  return A.isApprox(B, tolerance);
}

template<class A, class B>
constexpr bool equals(const A a, const B b, const double tolerance = NUMERICAL_ZERO_DIFFERENCE)
{
  return boost::math::relative_difference(a, b) <= tolerance;
}


https://eigen.tuxfamily.org/dox-devel/c ... xBase.html recommends using MatrixBase like that. However, the other template spezialization is always picked:

Code: Select all
In file included from src/mesh/Mesh.cpp:8:
In file included from src/math/math.hpp:3:
src/math/differences.hpp:53:49: error: invalid operands to binary expression ('typename
      boost::math::tools::promote_args<Matrix<double, -1, 1, 0, -1, 1>, Matrix<double, -1, 1, 0, -1, 1> >::type'
      (aka 'Eigen::Matrix<double, -1, 1, 0, -1, 1>') and 'double')
  return boost::math::relative_difference(a, b) <= tolerance;
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^  ~~~~~~~~~
src/mesh/Mesh.cpp:363:27: note: in instantiation of function template specialization
      'precice::math::equals<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >'
      requested here
      assertion(not math::equals(triangle.vertex(0).getCoords(), triangle.vertex(1).getCoords()),
                          ^


I also tried different variants, like the monstrous
Code: Select all
template <class Scalar, int RowsA, int RowsB, int Cols, int Options, int MaxRowsA, int MaxRowsB, int MaxCols>
constexpr bool equals (const Eigen::Matrix<Scalar, RowsA, Cols, Options, MaxRowsA, MaxCols>& A,
                       const Eigen::Matrix<Scalar, RowsB, Cols, Options, MaxRowsB, MaxCols>& B,
                       double tolerance = NUMERICAL_ZERO_DIFFERENCE)
{
  return A.isApprox(B, tolerance);
}


which solved some errors, but failed to match math::equals(coords, Eigen::Vector3d::Constant(1.0))
(coords is Eigen::Vector3d)

Code: Select all
src/math/differences.hpp:53:49: error: invalid operands to binary expression ('typename
      boost::math::tools::promote_args<Matrix<double, 3, 1, 0, 3, 1>, CwiseNullaryOp<scalar_constant_op<double>,
      Matrix<double, 3, 1, 0, 3, 1> > >::type' (aka 'Eigen::Matrix<double, 3, 1, 0, 3, 1>') and 'double')
  return boost::math::relative_difference(a, b) <= tolerance;
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^  ~~~~~~~~~
src/mesh/tests/VertexTest.cpp:34:20: note: in instantiation of function template specialization
      'precice::math::equals<Eigen::Matrix<double, 3, 1, 0, 3, 1>,
      Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<double>, Eigen::Matrix<double, 3, 1, 0, 3, 1> > >'
      requested here
  validate ( math::equals(coords, Eigen::Vector3d::Constant(1.0)) );


How should an appropriate template look like?

Thanks,
Florian
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
I see two approaches. One is to make use of enable_if<> to disable the generic version for non-Eigen types. This will involve some meta-programming kung fu.

The second one is to play with ADL:
1 - Move the generic 'equals(A,B)' to some namespace 'details' and rename it to equals_impl.
2 - Move equals(const MatrixBase<A>&,const MatrixBase<B>&) to namespace Eigen and rename it to equals_impl.
3 - add a new:

template<class A, class B>
constexpr bool equals(const A a, const B b, const double tolerance = NUMERICAL_ZERO_DIFFERENCE)
{
using namespace ADL;
return equals_impl(a, b, tolerance);
}


Bookmarks



Who is online

Registered users: Bing [Bot], Google [Bot], Sogou [Bot]