浏览代码

optimize performance on sorting and unique routines

Former-commit-id: 03944b06cf373adf7adfc3a08ae206b049d99dd7
Alec Jacobson (jalec 11 年之前
父节点
当前提交
1a5dd79889

+ 80 - 0
include/igl/IndexComparison.h

@@ -1,5 +1,6 @@
 #ifndef IGL_INDEXCOMPARISON_H
 #define IGL_INDEXCOMPARISON_H
+#include <iostream>
 // Comparison struct used by sort
 // http://bytes.com/topic/c/answers/132045-sort-get-index
 namespace igl{
@@ -25,6 +26,85 @@ namespace igl{
     }
     const T arr;
   };
+
+  // For use with functions like std::sort
+  template<class T> struct IndexVectorLessThan
+  {
+    IndexVectorLessThan(const T & vec) : vec ( vec) {}
+    bool operator()(const size_t a, const size_t b) const
+    {
+      return vec(a) < vec(b);
+    }
+    const T & vec;
+  };
+
+  // For use with functions like std::sort
+  template<class T> struct IndexDimLessThan
+  {
+    IndexDimLessThan(const T & mat,const int & dim, const int & j) : 
+      mat(mat),
+      dim(dim),
+      j(j)
+    {}
+    bool operator()(const size_t a, const size_t b) const
+    {
+      if(dim == 1)
+      {
+        return mat(a,j) < mat(b,j);
+      }else
+      {
+        return mat(j,a) < mat(j,b);
+      }
+    }
+    const T & mat;
+    const int & dim;
+    const int & j;
+  };
+
+  // For use with functions like std::sort
+  template<class T> struct IndexRowLessThan
+  {
+    IndexRowLessThan(const T & mat) : mat ( mat) {}
+    bool operator()(const size_t a, const size_t b) const
+    {
+      const int cols = mat.cols();
+      // Lexicographical order
+      for(int j = 0;j<cols;j++)
+      {
+        if(mat(a,j) > mat(b,j))
+        {
+          return false;
+        } else if(mat(a,j) < mat(b,j))
+        {
+          return true;
+        }
+      }
+      // equality is false
+      return false;
+    }
+    const T & mat;
+  };
+
+  // For use with functions like std::sort
+  template<class T> struct IndexRowEquals
+  {
+    IndexRowEquals(const T & mat) : mat ( mat) {}
+    bool operator()(const size_t a, const size_t b) const
+    {
+      const int cols = mat.cols();
+      // Lexicographical order
+      for(int j = 0;j<cols;j++)
+      {
+        if(mat(a,j) !=  mat(b,j))
+        {
+          return false;
+        }
+      }
+      return true;
+    }
+    const T & mat;
+  };
+
 }
 
 #endif

+ 1 - 0
include/igl/colon.cpp

@@ -75,4 +75,5 @@ template Eigen::Matrix<int, -1, 1, 0, -1, 1> igl::colon<int, int, long>(int, lon
 template void igl::colon<int, long, int, int>(int, long, int, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
 template void igl::colon<int, int, long, int>(int, int, long, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
 template void igl::colon<int, long, int>(int, long, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+template void igl::colon<int, int, int>(int, int, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
 #endif

+ 1 - 0
include/igl/matlab_format.cpp

@@ -92,4 +92,5 @@ template std::basic_string<char, std::char_traits<char>, std::allocator<char> >
 template Eigen::WithFormat<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const igl::matlab_format<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::string);
 template Eigen::WithFormat<Eigen::Array<int, -1, -1, 0, -1, -1> > const igl::matlab_format<Eigen::Array<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Array<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
 template Eigen::WithFormat<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const igl::matlab_format<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const igl::matlab_format<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
 #endif

+ 65 - 0
include/igl/sort.cpp

@@ -3,6 +3,7 @@
 #include "SortableRow.h"
 #include "reorder.h"
 #include "IndexComparison.h"
+#include "colon.h"
 
 #include <cassert>
 #include <algorithm>
@@ -66,6 +67,69 @@ IGL_INLINE void igl::sort(
   }
 }
 
+template <typename DerivedX, typename DerivedIX>
+IGL_INLINE void igl::sort_new(
+  const Eigen::PlainObjectBase<DerivedX>& X,
+  const int dim,
+  const bool ascending,
+  Eigen::PlainObjectBase<DerivedX>& Y,
+  Eigen::PlainObjectBase<DerivedIX>& IX)
+{
+  // get number of rows (or columns)
+  int num_inner = (dim == 1 ? X.rows() : X.cols() );
+  // Special case for swapping
+  if(num_inner == 2)
+  {
+    return igl::sort2(X,dim,ascending,Y,IX);
+  }
+  using namespace Eigen;
+  // get number of columns (or rows)
+  int num_outer = (dim == 1 ? X.cols() : X.rows() );
+  // dim must be 2 or 1
+  assert(dim == 1 || dim == 2);
+  // Resize output
+  Y.resize(X.rows(),X.cols());
+  IX.resize(X.rows(),X.cols());
+  // idea is to process each column (or row) as a std vector
+  // loop over columns (or rows)
+  for(int i = 0; i<num_outer;i++)
+  {
+    VectorXi ix;
+    colon(0,num_inner-1,ix);
+    // Sort the index map, using unsorted for comparison
+    if(dim == 1)
+    {
+      std::sort(
+        ix.data(),
+        ix.data()+ix.size(),
+        igl::IndexVectorLessThan<const typename DerivedX::ConstColXpr >(X.col(i)));
+    }else
+    {
+      std::sort(
+        ix.data(),
+        ix.data()+ix.size(),
+        igl::IndexVectorLessThan<const typename DerivedX::ConstRowXpr >(X.row(i)));
+    }
+    // if not ascending then reverse
+    if(!ascending)
+    {
+      std::reverse(ix.data(),ix.data()+ix.size());
+    }
+    for(int j = 0;j<num_inner;j++)
+    {
+      if(dim == 1)
+      {
+        Y(j,i) = X(ix[j],i);
+        IX(j,i) = ix[j];
+      }else
+      {
+        Y(i,j) = X(i,ix[j]);
+        IX(i,j) = ix[j];
+      }
+    }
+  }
+}
+
 template <typename DerivedX, typename DerivedIX>
 IGL_INLINE void igl::sort2(
   const Eigen::PlainObjectBase<DerivedX>& X,
@@ -149,4 +213,5 @@ template void igl::sort<int>(std::vector<int, std::allocator<int> > const&, bool
 template void igl::sort<SortableRow<Eigen::Matrix<double, -1, 1, 0, -1, 1> > >(std::vector<SortableRow<Eigen::Matrix<double, -1, 1, 0, -1, 1> >, std::allocator<SortableRow<Eigen::Matrix<double, -1, 1, 0, -1, 1> > > > const&, bool, std::vector<SortableRow<Eigen::Matrix<double, -1, 1, 0, -1, 1> >, std::allocator<SortableRow<Eigen::Matrix<double, -1, 1, 0, -1, 1> > > >&, std::vector<unsigned long, std::allocator<unsigned long> >&);
 template void igl::sort2<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::sort2<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort_new<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #endif

+ 8 - 0
include/igl/sort.h

@@ -30,6 +30,14 @@ namespace igl
     const bool ascending,
     Eigen::PlainObjectBase<DerivedX>& Y,
     Eigen::PlainObjectBase<DerivedIX>& IX);
+  template <typename DerivedX, typename DerivedIX>
+  // Only better if size(X,dim) is small
+  IGL_INLINE void sort_new(
+    const Eigen::PlainObjectBase<DerivedX>& X,
+    const int dim,
+    const bool ascending,
+    Eigen::PlainObjectBase<DerivedX>& Y,
+    Eigen::PlainObjectBase<DerivedIX>& IX);
   // Special case if size(X,dim) == 2
   template <typename DerivedX, typename DerivedIX>
   IGL_INLINE void sort2(

+ 52 - 16
include/igl/sortrows.cpp

@@ -2,9 +2,45 @@
 
 #include "SortableRow.h"
 #include "sort.h"
+#include "colon.h"
+#include "IndexComparison.h"
 
 #include <vector>
 
+// Obsolete slower version converst to vector
+//template <typename DerivedX, typename DerivedIX>
+//IGL_INLINE void igl::sortrows(
+//  const Eigen::PlainObjectBase<DerivedX>& X,
+//  const bool ascending,
+//  Eigen::PlainObjectBase<DerivedX>& Y,
+//  Eigen::PlainObjectBase<DerivedIX>& IX)
+//{
+//  using namespace std;
+//  using namespace Eigen;
+//  typedef Eigen::Matrix<typename DerivedX::Scalar, Eigen::Dynamic, 1> RowVector;
+//  vector<SortableRow<RowVector> > rows;
+//  rows.resize(X.rows());
+//  // Loop over rows
+//  for(int i = 0;i<X.rows();i++)
+//  {
+//    RowVector ri = X.row(i);
+//    rows[i] = SortableRow<RowVector>(ri);
+//  }
+//  vector<SortableRow<RowVector> > sorted;
+//  std::vector<size_t> index_map;
+//  // Perform sort on rows
+//  igl::sort(rows,ascending,sorted,index_map);
+//  // Resize output
+//  Y.resize(X.rows(),X.cols());
+//  IX.resize(X.rows(),1);
+//  // Convert to eigen
+//  for(int i = 0;i<X.rows();i++)
+//  {
+//    Y.row(i) = sorted[i].data;
+//    IX(i,0) = index_map[i];
+//  }
+//}
+
 template <typename DerivedX, typename DerivedIX>
 IGL_INLINE void igl::sortrows(
   const Eigen::PlainObjectBase<DerivedX>& X,
@@ -14,31 +50,31 @@ IGL_INLINE void igl::sortrows(
 {
   using namespace std;
   using namespace Eigen;
-  typedef Eigen::Matrix<typename DerivedX::Scalar, Eigen::Dynamic, 1> RowVector;
-  vector<SortableRow<RowVector> > rows;
-  rows.resize(X.rows());
-  // Loop over rows
-  for(int i = 0;i<X.rows();i++)
-  {
-    RowVector ri = X.row(i);
-    rows[i] = SortableRow<RowVector>(ri);
-  }
-  vector<SortableRow<RowVector> > sorted;
-  std::vector<size_t> index_map;
-  // Perform sort on rows
-  igl::sort(rows,ascending,sorted,index_map);
+  using namespace igl;
   // Resize output
   Y.resize(X.rows(),X.cols());
   IX.resize(X.rows(),1);
-  // Convert to eigen
   for(int i = 0;i<X.rows();i++)
   {
-    Y.row(i) = sorted[i].data;
-    IX(i) = index_map[i];
+    IX(i) = i;
+  }
+  std::sort(
+    IX.data(),
+    IX.data()+IX.size(),
+    igl::IndexRowLessThan<const Eigen::PlainObjectBase<DerivedX> & >(X));
+  // if not ascending then reverse
+  if(!ascending)
+  {
+    std::reverse(IX.data(),IX.data()+IX.size());
+  }
+  for(int i = 0;i<X.rows();i++)
+  {
+    Y.row(i) = X.row(IX(i));
   }
 }
 
 #ifndef IGL_HEADER_ONLY
 template void igl::sortrows<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::sortrows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 #endif

+ 0 - 1
include/igl/sortrows.h

@@ -24,7 +24,6 @@ namespace igl
     const bool ascending,
     Eigen::PlainObjectBase<DerivedX>& Y,
     Eigen::PlainObjectBase<DerivedIX>& IX);
-
 }
 
 #ifdef IGL_HEADER_ONLY

+ 114 - 65
include/igl/unique.cpp

@@ -2,6 +2,7 @@
 #include "sort.h"
 #include "IndexComparison.h"
 #include "SortableRow.h"
+#include "sortrows.h"
 #include "list_to_matrix.h"
 
 #include <algorithm>
@@ -43,7 +44,6 @@ IGL_INLINE void igl::unique(
       IC[IM[i]] = j;
     }
   }
-
   C.resize(IA.size());
   // Reindex IA according to IM
   for(int i = 0;i<(int)IA.size();i++)
@@ -51,8 +51,95 @@ IGL_INLINE void igl::unique(
     IA[i] = IM[IA[i]];
     C[i] = A[IA[i]];
   }
+
 }
 
+// Obsolete slow version converting to vectors
+// template <typename DerivedA, typename DerivedIA, typename DerivedIC>
+// IGL_INLINE void igl::unique_rows(
+//   const Eigen::PlainObjectBase<DerivedA>& A,
+//   Eigen::PlainObjectBase<DerivedA>& C,
+//   Eigen::PlainObjectBase<DerivedIA>& IA,
+//   Eigen::PlainObjectBase<DerivedIC>& IC)
+// {
+//   using namespace std;
+// 
+//   typedef Eigen::Matrix<typename DerivedA::Scalar, Eigen::Dynamic, 1> RowVector;
+//   vector<SortableRow<RowVector> > rows;
+//   rows.resize(A.rows());
+//   // Loop over rows
+//   for(int i = 0;i<A.rows();i++)
+//   {
+//     RowVector ri = A.row(i);
+//     rows[i] = SortableRow<RowVector>(ri);
+//   }
+//   vector<SortableRow<RowVector> > vC;
+// 
+//   // unique on rows
+//   vector<size_t> vIA;
+//   vector<size_t> vIC;
+//   unique(rows,vC,vIA,vIC);
+// 
+//   // Convert to eigen
+//   C.resize(vC.size(),A.cols());
+//   IA.resize(vIA.size(),1);
+//   IC.resize(vIC.size(),1);
+//   for(int i = 0;i<C.rows();i++)
+//   {
+//     C.row(i) = vC[i].data;
+//     IA(i) = vIA[i];
+//   }
+//   for(int i = 0;i<A.rows();i++)
+//   {
+//     IC(i) = vIC[i];
+//   }
+// }
+
+// Obsolete
+// template <typename DerivedA, typename DerivedIA, typename DerivedIC>
+// IGL_INLINE void igl::unique_rows_many(
+//   const Eigen::PlainObjectBase<DerivedA>& A,
+//   Eigen::PlainObjectBase<DerivedA>& C,
+//   Eigen::PlainObjectBase<DerivedIA>& IA,
+//   Eigen::PlainObjectBase<DerivedIC>& IC)
+// {
+//   using namespace std;
+//   // frequency map
+//   typedef Eigen::Matrix<typename DerivedA::Scalar, Eigen::Dynamic, 1> RowVector;
+//   IC.resize(A.rows(),1);
+//   map<SortableRow<RowVector>, int> fm;
+//   const int m = A.rows();
+//   for(int i = 0;i<m;i++)
+//   {
+//     RowVector ri = A.row(i);
+//     if(fm.count(SortableRow<RowVector>(ri)) == 0)
+//     {
+//       fm[SortableRow<RowVector>(ri)] = i;
+//     }
+//     IC(i) = fm[SortableRow<RowVector>(ri)];
+//   }
+//   IA.resize(fm.size(),1);
+//   Eigen::VectorXi RIA(m);
+//   C.resize(fm.size(),A.cols());
+//   {
+//     int i = 0;
+//     for(typename map<SortableRow<RowVector > , int >::const_iterator fit = fm.begin();
+//         fit != fm.end();
+//         fit++)
+//     {
+//       IA(i) = fit->second;
+//       RIA(fit->second) = i;
+//       C.row(i) = fit->first.data;
+//       i++;
+//     }
+//   }
+//   // IC should index C
+//   for(int i = 0;i<m;i++)
+//   {
+//     IC(i) = RIA(IC(i));
+//   }
+// }
+
 template <typename DerivedA, typename DerivedIA, typename DerivedIC>
 IGL_INLINE void igl::unique_rows(
   const Eigen::PlainObjectBase<DerivedA>& A,
@@ -61,79 +148,43 @@ IGL_INLINE void igl::unique_rows(
   Eigen::PlainObjectBase<DerivedIC>& IC)
 {
   using namespace std;
+  using namespace igl;
+  using namespace Eigen;
+  VectorXi IM;
+  Eigen::PlainObjectBase<DerivedA> sortA;
+  sortrows(A,true,sortA,IM);
 
-  typedef Eigen::Matrix<typename DerivedA::Scalar, Eigen::Dynamic, 1> RowVector;
-  vector<SortableRow<RowVector> > rows;
-  rows.resize(A.rows());
-  // Loop over rows
-  for(int i = 0;i<A.rows();i++)
-  {
-    RowVector ri = A.row(i);
-    rows[i] = SortableRow<RowVector>(ri);
-  }
-  vector<SortableRow<RowVector> > vC;
 
-  // unique on rows
-  vector<size_t> vIA;
-  vector<size_t> vIC;
-  unique(rows,vC,vIA,vIC);
-
-  // Convert to eigen
-  C.resize(vC.size(),A.cols());
-  IA.resize(vIA.size(),1);
-  IC.resize(vIC.size(),1);
-  for(int i = 0;i<C.rows();i++)
+  vector<int> vIA(sortA.rows());
+  for(int i=0;i<(int)sortA.rows();i++)
   {
-    C.row(i) = vC[i].data;
-    IA(i) = vIA[i];
+    vIA[i] = i;
   }
-  for(int i = 0;i<A.rows();i++)
-  {
-    IC(i) = vIC[i];
-  }
-}
+  vIA.erase(
+    std::unique(
+    vIA.begin(),
+    vIA.end(),
+    igl::IndexRowEquals<const Eigen::PlainObjectBase<DerivedA> &>(sortA)),vIA.end());
 
-template <typename DerivedA, typename DerivedIA, typename DerivedIC>
-IGL_INLINE void igl::unique_rows_many(
-  const Eigen::PlainObjectBase<DerivedA>& A,
-  Eigen::PlainObjectBase<DerivedA>& C,
-  Eigen::PlainObjectBase<DerivedIA>& IA,
-  Eigen::PlainObjectBase<DerivedIC>& IC)
-{
-  using namespace std;
-  // frequency map
-  typedef Eigen::Matrix<typename DerivedA::Scalar, Eigen::Dynamic, 1> RowVector;
   IC.resize(A.rows(),1);
-  map<SortableRow<RowVector>, int> fm;
-  const int m = A.rows();
-  for(int i = 0;i<m;i++)
-  {
-    RowVector ri = A.row(i);
-    if(fm.count(SortableRow<RowVector>(ri)) == 0)
-    {
-      fm[SortableRow<RowVector>(ri)] = i;
-    }
-    IC(i) = fm[SortableRow<RowVector>(ri)];
-  }
-  IA.resize(fm.size(),1);
-  Eigen::VectorXi RIA(m);
-  C.resize(fm.size(),A.cols());
   {
-    int i = 0;
-    for(typename map<SortableRow<RowVector > , int >::const_iterator fit = fm.begin();
-        fit != fm.end();
-        fit++)
+    int j = 0;
+    for(int i = 0;i<(int)sortA.rows();i++)
     {
-      IA(i) = fit->second;
-      RIA(fit->second) = i;
-      C.row(i) = fit->first.data;
-      i++;
+      if(sortA.row(vIA[j]) != sortA.row(i))
+      {
+        j++;
+      }
+      IC(IM(i,0),0) = j;
     }
   }
-  // IC should index C
-  for(int i = 0;i<m;i++)
+  C.resize(vIA.size(),A.cols());
+  IA.resize(vIA.size(),1);
+  // Reindex IA according to IM
+  for(int i = 0;i<(int)vIA.size();i++)
   {
-    IC(i) = RIA(IC(i));
+    IA(i,0) = IM(vIA[i],0);
+    C.row(i) = A.row(IA(i,0));
   }
 }
 
@@ -143,6 +194,4 @@ template void igl::unique_rows<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Mat
 template void igl::unique_rows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
 template void igl::unique_rows<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 template void igl::unique_rows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
-template void igl::unique_rows_many<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
-template void igl::unique_rows_many<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 #endif

+ 0 - 8
include/igl/unique.h

@@ -41,14 +41,6 @@ namespace igl
     Eigen::PlainObjectBase<DerivedA>& C,
     Eigen::PlainObjectBase<DerivedIA>& IA,
     Eigen::PlainObjectBase<DerivedIC>& IC);
-  // Faster if there are expected to be many matches
-  template <typename DerivedA, typename DerivedIA, typename DerivedIC>
-  IGL_INLINE void unique_rows_many(
-    const Eigen::PlainObjectBase<DerivedA>& A,
-    Eigen::PlainObjectBase<DerivedA>& C,
-    Eigen::PlainObjectBase<DerivedIA>& IA,
-    Eigen::PlainObjectBase<DerivedIC>& IC);
-
 }
 
 #ifdef IGL_HEADER_ONLY