Posts Tagged ‘template’

Eigen performance gotcha calling non-templated function from templated one

Tuesday, July 25th, 2017

I just spent a while tracking down a rather surprising performance bug in my code.

Here’s a minimal example:

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

int simple_size(const Eigen::MatrixXi & Z)
{
  return Z.size();
}

template <typename T> int templated_size(const Eigen::MatrixBase<T> & Y)
{
  return simple_size(Y);
}

int main(int argc, const char * argv[])
{
  const int s = 40000;
  Eigen::MatrixXi X = Eigen::MatrixXi::Zero(40000,40000);
  std::cout<<"Compare:"<<std::endl;
  std::cout<<(X.size()         ?"done":"")<<std::endl;
  std::cout<<(simple_size(X)          ?"done":"")<<std::endl;
  std::cout<<(templated_size(X)?"done":"")<<std::endl;

}

Running this, it will show that the last call to templated_size is taking way too long. Inspection will show that a copy of Y is being created to create a Eigen::MatrixXi & reference.

Now, clearly it’s poor design to call a function expecting a Eigen::MatrixXi & reference with a generic templated type Eigen::MatrixBase<T> &, but unfortunately this happens quite often with legacy libigl functions. My expectation was that since T is Eigen::MatrixXi in this case a simple reference would be passed.

It’s worth noting that const is actually creating/hiding the problem. Because simple_size takes a const reference, the compiler is happy to construct a Eigen::MatrixXi on the fly to create a valid reference. Without the consts the compiler stops at an error.

Memory gotcha in eigen

Wednesday, August 26th, 2015

I recently ran into a frustrating memory leak “gotcha” involving Eigen. The following code compiles

template <typename Derived>
Eigen::PlainObjectBase<Derived> leaky(
  const Eigen::PlainObjectBase<Derived> & A)
{
  Derived B = A;
  return B;
}

int main(int argc, char * argv[])
{
  Eigen::MatrixXd A(10000,1);
  Eigen::MatrixXd B = leaky(A);
}

but causes a memory leak (without any warnings/asserts from Eigen):

.main(33789,0x7fff7bb2d300) malloc: *** error for object 0x7f9ed188da00: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

The problem seems to be the cast happening in the return. Changing the return type of leaky to Derived:

template <typename Derived>
Derived leaky(
  const Eigen::PlainObjectBase<Derived> & A)

fixes the issue. Or it could be fixed by changing the type of B inside leaky to Eigen::PlainObjectBase<Derived>.

  Eigen::PlainObjectBase<Derived> B = A;

Update:

The preferred answer from the Eigen developers is that leaky() should return Derived. This is a little disappointing if I want to have A and the return value be different types and I don’t want to expose all possible types for the return (i.e. I only want to template on top of Eigen matrices).

Mysterious gcc compile error near Eigen `cast`

Saturday, December 14th, 2013

I run into this error often and it always takes me a bit to remember the problem. The line usually looks like:

MatrixXd B = A.cast<float>();

and the error gcc spits out is:

XXX.cpp:719:34: error: expected primary-expression before 'float'
XXX.cpp:719:34: error: expected ',' or ';' before 'float'

The problem happens when A is some templated Eigen object. The solution is to add the word template in front of cast:

MatrixXd B = A.template cast<float>();

Thanks for nothing gcc error messages.

Templated Eigen SparseMatrix with triangularView

Saturday, September 14th, 2013

I was trying to use Eigen’s triangularView for a templated SparseMatrix like this:

template <typename T> void foo()
{
  Eigen::SparseMatrix<T> A;
  A.triangularView<Upper>();
}

But I kept getting errors like:

 In function 'void foo()':
22:34: error: expected primary-expression before ')' token
 In instantiation of 'void foo() [with T = double]':
81:15:   required from here
22:3: error: no match for 'operator<' in 'A.Eigen::SparseMatrixBase<Derived>::triangularView<Mode> < (Eigen::._64)2u'

Turns out this can be fixed by appending the word template before triangularView:

template <typename T> void foo()
{
  Eigen::SparseMatrix<T> A;
  A.template triangularView<Eigen::Upper>();
}

Gcc on cygwin doesn’t like leading underscores in variable names

Monday, May 6th, 2013

I recently tried to compile libigl on windows using cygwin, and got a myriad of errors of the form:


include/igl/draw_beach_ball.cpp:37:63: error: expected ‘,’ or ‘...’ before numeric constant
include/igl/draw_beach_ball.cpp: In function ‘const _T& TClamp(const _T&)’:
include/igl/draw_beach_ball.cpp:39:9: error: ‘_Limit1’ was not declared in this scope
include/igl/draw_beach_ball.cpp:39:17: error: ‘_Limit2’ was not declared in this scope
include/igl/draw_beach_ball.cpp: At global scope:
include/igl/draw_beach_ball.cpp:46:73: error: expected ‘,’ or ‘...’ before numeric constant
include/igl/draw_beach_ball.cpp: In function ‘color32 Color32FromARGBi(int, int, int, int)’:
include/igl/draw_beach_ball.cpp:48:40: error: no matching function for call to ‘TClamp(int&, int, int)’
include/igl/draw_beach_ball.cpp:48:78: error: no matching function for call to ‘TClamp(int&, int, int)’
include/igl/draw_beach_ball.cpp:48:116: error: no matching function for call to ‘TClamp(int&, int, int)’
include/igl/draw_beach_ball.cpp:48:152: error: no matching function for call to ‘TClamp(int, int, int)’
include/igl/draw_beach_ball.cpp: At global scope:
include/igl/draw_beach_ball.cpp:51:81: error: expected ‘,’ or ‘...’ before numeric constant

Turns out these were all due to the code we copied from AntTweakBar which used leading underscores before variable and template names. To fix it we just needed to change any variables like:


_FOO

to


FOO

CGAL intersections.h conflicts with Boolean_set_operations_2.h

Thursday, November 15th, 2012

I was trying to transform the cgal 2d polygon intersection example into an example that computes 3d triangle intersections.

This gave some typical pages of CGAL compiler errors:


In file included from /opt/local/include/CGAL/intersection_3.h:49:0,
                 from /opt/local/include/CGAL/Kernel/function_objects.h:34,
                 from /opt/local/include/CGAL/Cartesian/function_objects.h:28,
                 from /opt/local/include/CGAL/Cartesian/Cartesian_base.h:68,
                 from /opt/local/include/CGAL/Simple_cartesian.h:28,
                 from /opt/local/include/CGAL/Exact_predicates_exact_constructions_kernel.h:28,
                 from CGAL_includes.hpp:4:
/opt/local/include/CGAL/Triangle_3_Triangle_3_intersection.h: In instantiation of 'void CGAL::internal::intersection_coplanar_triangles_cutoff(const typename Kernel::Point_3&, const typename Kernel::Point_3&, const typename Kernel::Point_3&, const Kernel&, std::list<typename Kernel::Point_3>&) [with Kernel = CGAL::Simple_cartesian<CGAL::Gmpq>; typename Kernel::Point_3 = CGAL::Point_3<CGAL::Simple_cartesian<CGAL::Gmpq> >; typename R_::Point_3 = CGAL::Point_3<CGAL::Simple_cartesian<CGAL::Gmpq> >]':
/opt/local/include/CGAL/Triangle_3_Triangle_3_intersection.h:98:3:   Error: required from 'CGAL::Object CGAL::internal::intersection_coplanar_triangles(const typename Kernel::Triangle_3&, const typename Kernel::Triangle_3&, const Kernel&) [with Kernel = CGAL::Simple_cartesian<CGAL::Gmpq>; typename Kernel::Triangle_3 = CGAL::Triangle_3<CGAL::Simple_cartesian<CGAL::Gmpq> >]'
/opt/local/include/CGAL/Triangle_3_Triangle_3_intersection.h:136:53:   Error: required from 'CGAL::Object CGAL::internal::intersection(const typename Kernel::Triangle_3&, const typename Kernel::Triangle_3&, const Kernel&) [with Kernel = CGAL::Simple_cartesian<CGAL::Gmpq>; typename Kernel::Triangle_3 = CGAL::Triangle_3<CGAL::Simple_cartesian<CGAL::Gmpq> >]'
/opt/local/include/CGAL/Kernel/function_objects.h:2535:49:   Error: required from 'CGAL::CommonKernelFunctors::Intersect_3<K>::Object_3 CGAL::CommonKernelFunctors::Intersect_3<K>::operator()(const T1&, const T2&) const [with T1 = CGAL::Triangle_3<CGAL::Simple_cartesian<CGAL::Gmpq> >; T2 = CGAL::Triangle_3<CGAL::Simple_cartesian<CGAL::Gmpq> >; K = CGAL::Simple_cartesian<CGAL::Gmpq>; CGAL::CommonKernelFunctors::Intersect_3<K>::Object_3 = CGAL::Object]'
/opt/local/include/CGAL/Lazy.h:1756:51:   Error: required from 'CGAL::Lazy_construction_object<LK, AC, EC>::result_type CGAL::Lazy_construction_object<LK, AC, EC>::operator()(const L1&, const L2&) const [with L1 = CGAL::Triangle_3<CGAL::Epeck>; L2 = CGAL::Triangle_3<CGAL::Epeck>; LK = CGAL::Epeck; AC = CGAL::CommonKernelFunctors::Intersect_3<CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >; EC = CGAL::CommonKernelFunctors::Intersect_3<CGAL::Simple_cartesian<CGAL::Gmpq> >; CGAL::Lazy_construction_object<LK, AC, EC>::result_type = CGAL::Object]'
/opt/local/include/CGAL/Triangle_3_Triangle_3_intersection.h:180:42:   Error: required from 'CGAL::Object CGAL::intersection(const CGAL::Triangle_3<R>&, const CGAL::Triangle_3<R>&) [with K = CGAL::Epeck]'
main.cpp:41:49:   Error: required from here
/opt/local/include/CGAL/Triangle_3_Triangle_3_intersection.h:62:64: Error: error: call of overloaded 'intersection(CGAL::CartesianKernelFunctors::Construct_line_3<CGAL::Simple_cartesian<CGAL::Gmpq> >::Line_3, CGAL::CartesianKernelFunctors::Construct_line_3<CGAL::Simple_cartesian<CGAL::Gmpq> >::Line_3, const CGAL::Simple_cartesian<CGAL::Gmpq>&)' is ambiguous
/opt/local/include/CGAL/Triangle_3_Triangle_3_intersection.h:62:64: note: candidates are:
In file included from /opt/local/include/CGAL/intersection_3_1.h:427:0,
                 from /opt/local/include/CGAL/intersection_3.h:29,
                 from /opt/local/include/CGAL/Kernel/function_objects.h:34,
                 from /opt/local/include/CGAL/Cartesian/function_objects.h:28,
                 from /opt/local/include/CGAL/Cartesian/Cartesian_base.h:68,
                 from /opt/local/include/CGAL/Simple_cartesian.h:28,
                 from /opt/local/include/CGAL/Exact_predicates_exact_constructions_kernel.h:28,
                 from CGAL_includes.hpp:4:
/opt/local/include/CGAL/Intersections_3/intersection_3_1_impl.h:200:1: Error: note: CGAL::Object CGAL::internal::intersection(const typename K::Line_3&, const typename K::Line_3&, const K&) [with K = CGAL::Simple_cartesian<CGAL::Gmpq>; typename K::Line_3 = CGAL::Line_3<CGAL::Simple_cartesian<CGAL::Gmpq> >]
In file included from CGAL_includes.hpp:11:0:
/opt/local/include/CGAL/Boolean_set_operations_2.h:904:23: Error: note: OutputIterator CGAL::intersection(InputIterator, InputIterator, OutputIterator, unsigned int) [with InputIterator = CGAL::Line_3<CGAL::Simple_cartesian<CGAL::Gmpq> >; OutputIterator = CGAL::Simple_cartesian<CGAL::Gmpq>]
In file included from /opt/local/include/CGAL/intersection_3.h:49:0,
                 from /opt/local/include/CGAL/Kernel/function_objects.h:34,
                 from /opt/local/include/CGAL/Cartesian/function_objects.h:28,
                 from /opt/local/include/CGAL/Cartesian/Cartesian_base.h:68,
                 from /opt/local/include/CGAL/Simple_cartesian.h:28,
                 from /opt/local/include/CGAL/Exact_predicates_exact_constructions_kernel.h:28,
                 from CGAL_includes.hpp:4:
/opt/local/include/CGAL/Triangle_3_Triangle_3_intersection.h: In instantiation of 'void CGAL::internal::intersection_coplanar_triangles_cutoff(const typename Kernel::Point_3&, const typename Kernel::Point_3&, const typename Kernel::Point_3&, const Kernel&, std::list<typename Kernel::Point_3>&) [with Kernel = CGAL::Simple_cartesian<CGAL::Interval_nt<false> >; typename Kernel::Point_3 = CGAL::Point_3<CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >; typename R_::Point_3 = CGAL::Point_3<CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >]':
/opt/local/include/CGAL/Triangle_3_Triangle_3_intersection.h:98:3:   Error: required from 'CGAL::Object CGAL::internal::intersection_coplanar_triangles(const typename Kernel::Triangle_3&, const typename Kernel::Triangle_3&, const Kernel&) [with Kernel = CGAL::Simple_cartesian<CGAL::Interval_nt<false> >; typename Kernel::Triangle_3 = CGAL::Triangle_3<CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >]'
/opt/local/include/CGAL/Triangle_3_Triangle_3_intersection.h:136:53:   Error: required from 'CGAL::Object CGAL::internal::intersection(const typename Kernel::Triangle_3&, const typename Kernel::Triangle_3&, const Kernel&) [with Kernel = CGAL::Simple_cartesian<CGAL::Interval_nt<false> >; typename Kernel::Triangle_3 = CGAL::Triangle_3<CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >]'
/opt/local/include/CGAL/Kernel/function_objects.h:2535:49:   Error: required from 'CGAL::CommonKernelFunctors::Intersect_3<K>::Object_3 CGAL::CommonKernelFunctors::Intersect_3<K>::operator()(const T1&, const T2&) const [with T1 = CGAL::Triangle_3<CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >; T2 = CGAL::Triangle_3<CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >; K = CGAL::Simple_cartesian<CGAL::Interval_nt<false> >; CGAL::CommonKernelFunctors::Intersect_3<K>::Object_3 = CGAL::Object]'
/opt/local/include/CGAL/Lazy.h:385:22:   Error: required from 'CGAL::Lazy_rep_2<AC, EC, E2A, L1, L2>::Lazy_rep_2(const AC&, const EC&, const L1&, const L2&) [with AC = CGAL::CommonKernelFunctors::Intersect_3<CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >; EC = CGAL::CommonKernelFunctors::Intersect_3<CGAL::Simple_cartesian<CGAL::Gmpq> >; E2A = CGAL::Cartesian_converter<CGAL::Simple_cartesian<CGAL::Gmpq>, CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >; L1 = CGAL::Triangle_3<CGAL::Epeck>; L2 = CGAL::Triangle_3<CGAL::Epeck>]'
/opt/local/include/CGAL/Lazy.h:1715:73:   Error: required from 'CGAL::Lazy_construction_object<LK, AC, EC>::result_type CGAL::Lazy_construction_object<LK, AC, EC>::operator()(const L1&, const L2&) const [with L1 = CGAL::Triangle_3<CGAL::Epeck>; L2 = CGAL::Triangle_3<CGAL::Epeck>; LK = CGAL::Epeck; AC = CGAL::CommonKernelFunctors::Intersect_3<CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >; EC = CGAL::CommonKernelFunctors::Intersect_3<CGAL::Simple_cartesian<CGAL::Gmpq> >; CGAL::Lazy_construction_object<LK, AC, EC>::result_type = CGAL::Object]'
/opt/local/include/CGAL/Triangle_3_Triangle_3_intersection.h:180:42:   Error: required from 'CGAL::Object CGAL::intersection(const CGAL::Triangle_3<R>&, const CGAL::Triangle_3<R>&) [with K = CGAL::Epeck]'
main.cpp:41:49:   Error: required from here
/opt/local/include/CGAL/Triangle_3_Triangle_3_intersection.h:62:64: Error: error: call of overloaded 'intersection(CGAL::CartesianKernelFunctors::Construct_line_3<CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >::Line_3, CGAL::CartesianKernelFunctors::Construct_line_3<CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >::Line_3, const CGAL::Simple_cartesian<CGAL::Interval_nt<false> >&)' is ambiguous
/opt/local/include/CGAL/Triangle_3_Triangle_3_intersection.h:62:64: note: candidates are:
In file included from /opt/local/include/CGAL/intersection_3_1.h:427:0,
                 from /opt/local/include/CGAL/intersection_3.h:29,
                 from /opt/local/include/CGAL/Kernel/function_objects.h:34,
                 from /opt/local/include/CGAL/Cartesian/function_objects.h:28,
                 from /opt/local/include/CGAL/Cartesian/Cartesian_base.h:68,
                 from /opt/local/include/CGAL/Simple_cartesian.h:28,
                 from /opt/local/include/CGAL/Exact_predicates_exact_constructions_kernel.h:28,
                 from CGAL_includes.hpp:4:
/opt/local/include/CGAL/Intersections_3/intersection_3_1_impl.h:200:1: Error: note: CGAL::Object CGAL::internal::intersection(const typename K::Line_3&, const typename K::Line_3&, const K&) [with K = CGAL::Simple_cartesian<CGAL::Interval_nt<false> >; typename K::Line_3 = CGAL::Line_3<CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >]
In file included from CGAL_includes.hpp:11:0:
/opt/local/include/CGAL/Boolean_set_operations_2.h:904:23: Error: note: OutputIterator CGAL::intersection(InputIterator, InputIterator, OutputIterator, unsigned int) [with InputIterator = CGAL::Line_3<CGAL::Simple_cartesian<CGAL::Interval_nt<false> > >; OutputIterator = CGAL::Simple_cartesian<CGAL::Interval_nt<false> >]
make: *** [obj/main.o] Error 1

I fixed this by making sure in the files where I include:


#include <CGAL/intersections.h>

I don’t include:


#include <CGAL/Boolean_set_operations_2.h>

Eigen gotcha, sparse matrix inneriterator type

Sunday, October 9th, 2011

I just experienced a really annoying Eigen gotcha. If I have a sparsematrix A, defined as:


SparseMatrix<double> A;
// ... filled in somehow

then I can loop over the values with:


for(int k=0; k<A.outerSize(); ++k)
{
  // Iterate over inside
  for(SparseMatrix<double>::InnerIterator it (A,k); it; ++it)
  {
      // it.row(),  it.col(), it.value()
  }
}

This works fine. But if instead I use the wrong type for the InnerIterator, say int, I get no complaint from the compiler, just occasional garbage when I use it.col(), it.row(), or it.value():


for(int k=0; k<A.outerSize(); ++k)
{
  // Iterate over inside
  for(SparseMatrix<int>::InnerIterator it (A,k); it; ++it)
  {
      // it.row(),  it.col(), it.value() produce occasional garbage
  }
}