Re: [eigen] problem with operator() in development branch

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




On Tue, Jun 1, 2010 at 2:55 PM, Benoit Jacob <jacob.benoit.1@xxxxxxxxx> wrote:

oh, right ! Don't know why I didn't remember about that. By the way,
are you planning to allow 1x1 to scalar conversion ? I'm rather
favorable to that. There recently was an unanswered forum post about
doing that.

ok I've a working version of that:

Matrix<float,1,1> mat;

mat = 1;
float x = mat + 1
std::sin(mat);

 but there is a quite big downside:

mat * 2

does not compile anymore because there is an ambiguity which has to be resolved by doing either:

mat * Scalar(2);
mat * 2.f;
Scalar(mat) * 2;

Maybe the worst thing is that such an ambiguity will show up for 1x1 objects only... so think about general template code which compile fine for all objects except 1x1. Since the later ones are likely not be well tested....

I'm tempted to postpone this feature and/or enable this conversion for inner products only which are less likely to trigger such issues. Also for other use cases there is the class Array which is supposed to be explicitly fully compatible with scalars.

gael
diff -r b1513faeb8c8 Eigen/src/Core/DenseBase.h
--- a/Eigen/src/Core/DenseBase.h	Tue Jun 01 09:17:50 2010 -0400
+++ b/Eigen/src/Core/DenseBase.h	Tue Jun 01 16:58:57 2010 +0200
@@ -218,8 +218,8 @@
       */
     void resize(Index rows, Index cols)
     {
-      EIGEN_ONLY_USED_FOR_DEBUG(rows); 
-      EIGEN_ONLY_USED_FOR_DEBUG(cols); 
+      EIGEN_ONLY_USED_FOR_DEBUG(rows);
+      EIGEN_ONLY_USED_FOR_DEBUG(cols);
       ei_assert(rows == this->rows() && cols == this->cols()
                 && "DenseBase::resize() does not actually allow to resize.");
     }
@@ -247,7 +247,7 @@
     /** \internal expression type of a block of whole rows */
     template<int N> struct NRowsBlockXpr { typedef Block<Derived, N, ei_traits<Derived>::ColsAtCompileTime> Type; };
 
-    
+
 #endif // not EIGEN_PARSED_BY_DOXYGEN
 
     /** Copies \a other into *this. \returns a reference to *this. */
@@ -295,6 +295,17 @@
   public:
 #endif
 
+    /** Convertion to scalar for 1x1 objects */
+    operator typename ei_meta_if<SizeAtCompileTime==1,typename Base::CoeffReturnType,ei_dummy_struct>::ret() const {
+      return coeff(0);
+    }
+
+    /** Convertion from scalar to 1x1 objects */
+    Derived& operator=(typename ei_meta_if<SizeAtCompileTime==1,const Scalar&,ei_dummy_struct>::ret s) {
+      coeffRef(0) = s;
+      return derived();
+    }
+
     RowXpr row(Index i);
     const RowXpr row(Index i) const;
 
@@ -440,8 +451,8 @@
       * a const reference, in order to avoid a useless copy.
       */
     EIGEN_STRONG_INLINE const typename ei_eval<Derived>::type eval() const
-    { 
-      // Even though MSVC does not honor strong inlining when the return type 
+    {
+      // Even though MSVC does not honor strong inlining when the return type
       // is a dynamic matrix, we desperately need strong inlining for fixed
       // size types on MSVC.
       return typename ei_eval<Derived>::type(derived());
diff -r b1513faeb8c8 Eigen/src/Core/DenseStorageBase.h
--- a/Eigen/src/Core/DenseStorageBase.h	Tue Jun 01 09:17:50 2010 -0400
+++ b/Eigen/src/Core/DenseStorageBase.h	Tue Jun 01 16:58:57 2010 +0200
@@ -59,6 +59,7 @@
     using Base::MaxSizeAtCompileTime;
     using Base::IsVectorAtCompileTime;
     using Base::Flags;
+    using Base::operator=;
 
     friend  class Eigen::Map<Derived, Unaligned>;
     typedef class Eigen::Map<Derived, Unaligned>  UnalignedMapType;
diff -r b1513faeb8c8 Eigen/src/Core/Matrix.h
--- a/Eigen/src/Core/Matrix.h	Tue Jun 01 09:17:50 2010 -0400
+++ b/Eigen/src/Core/Matrix.h	Tue Jun 01 16:58:57 2010 +0200
@@ -150,6 +150,7 @@
 
     using Base::base;
     using Base::coeffRef;
+    using Base::operator=;
 
     /**
       * \brief Assigns matrices to each other.
diff -r b1513faeb8c8 Eigen/src/Core/util/XprHelper.h
--- a/Eigen/src/Core/util/XprHelper.h	Tue Jun 01 09:17:50 2010 -0400
+++ b/Eigen/src/Core/util/XprHelper.h	Tue Jun 01 16:58:57 2010 +0200
@@ -329,6 +329,10 @@
   typedef ArrayBase<Derived> type;
 };
 
+/** \internal Dummy structure to disable some methods. */
+struct ei_dummy_struct {};
+
+
 /** \internal Helper base class to add a scalar multiple operator
   * overloads for complex types */
 template<typename Derived,typename Scalar,typename OtherScalar,
diff -r b1513faeb8c8 test/CMakeLists.txt
--- a/test/CMakeLists.txt	Tue Jun 01 09:17:50 2010 -0400
+++ b/test/CMakeLists.txt	Tue Jun 01 16:58:57 2010 +0200
@@ -92,6 +92,7 @@
 ei_add_test(unalignedassert)
 ei_add_test(vectorization_logic)
 ei_add_test(basicstuff)
+ei_add_test(matrix1x1)
 ei_add_test(linearstructure)
 ei_add_test(integer_types)
 ei_add_test(cwiseop)
diff -r b1513faeb8c8 test/array.cpp
--- a/test/array.cpp	Tue Jun 01 09:17:50 2010 -0400
+++ b/test/array.cpp	Tue Jun 01 16:58:57 2010 +0200
@@ -126,13 +126,13 @@
   VERIFY_IS_APPROX( (m1.abs()<mid).select(0,m1), m3);
 
   // count
-  VERIFY(((m1.abs()+1)>RealScalar(0.1)).count() == rows*cols);
+  VERIFY(((m1.abs()+Scalar(1))>RealScalar(0.1)).count() == rows*cols);
 
   typedef Array<typename ArrayType::Index, Dynamic, 1> ArrayOfIndices;
-  
+
   // TODO allows colwise/rowwise for array
-  VERIFY_IS_APPROX(((m1.abs()+1)>RealScalar(0.1)).colwise().count(), ArrayOfIndices::Constant(cols,rows).transpose());
-  VERIFY_IS_APPROX(((m1.abs()+1)>RealScalar(0.1)).rowwise().count(), ArrayOfIndices::Constant(rows, cols));
+  VERIFY_IS_APPROX(((m1.abs()+Scalar(1))>RealScalar(0.1)).colwise().count(), ArrayOfIndices::Constant(cols,rows).transpose());
+  VERIFY_IS_APPROX(((m1.abs()+Scalar(1))>RealScalar(0.1)).rowwise().count(), ArrayOfIndices::Constant(rows, cols));
 }
 
 template<typename ArrayType> void array_real(const ArrayType& m)
@@ -151,10 +151,10 @@
   VERIFY_IS_APPROX(m1.sin(), ei_sin(m1));
   VERIFY_IS_APPROX(m1.cos(), std::cos(m1));
   VERIFY_IS_APPROX(m1.cos(), ei_cos(m1));
-  
+
   VERIFY_IS_APPROX(ei_cos(m1+RealScalar(3)*m2), ei_cos((m1+RealScalar(3)*m2).eval()));
   VERIFY_IS_APPROX(std::cos(m1+RealScalar(3)*m2), std::cos((m1+RealScalar(3)*m2).eval()));
-  
+
   VERIFY_IS_APPROX(m1.abs().sqrt(), std::sqrt(std::abs(m1)));
   VERIFY_IS_APPROX(m1.abs().sqrt(), ei_sqrt(ei_abs(m1)));
   VERIFY_IS_APPROX(m1.abs(), ei_sqrt(ei_abs2(m1)));
@@ -163,10 +163,10 @@
   VERIFY_IS_APPROX(ei_abs2(std::real(m1)) + ei_abs2(std::imag(m1)), ei_abs2(m1));
   if(!NumTraits<Scalar>::IsComplex)
     VERIFY_IS_APPROX(ei_real(m1), m1);
-  
+
   VERIFY_IS_APPROX(m1.abs().log(), std::log(std::abs(m1)));
   VERIFY_IS_APPROX(m1.abs().log(), ei_log(ei_abs(m1)));
-  
+
   VERIFY_IS_APPROX(m1.exp(), std::exp(m1));
   VERIFY_IS_APPROX(m1.exp() * m2.exp(), std::exp(m1+m2));
   VERIFY_IS_APPROX(m1.exp(), ei_exp(m1));
diff -r b1513faeb8c8 test/array_for_matrix.cpp
--- a/test/array_for_matrix.cpp	Tue Jun 01 09:17:50 2010 -0400
+++ b/test/array_for_matrix.cpp	Tue Jun 01 16:58:57 2010 +0200
@@ -37,10 +37,10 @@
   MatrixType m1 = MatrixType::Random(rows, cols),
              m2 = MatrixType::Random(rows, cols),
              m3(rows, cols);
-             
+
   ColVectorType cv1 = ColVectorType::Random(rows);
   RowVectorType rv1 = RowVectorType::Random(cols);
-             
+
   Scalar  s1 = ei_random<Scalar>(),
           s2 = ei_random<Scalar>();
 
@@ -123,13 +123,13 @@
   VERIFY_IS_APPROX( (m1.array().abs()<mid).select(0,m1), m3);
 
   // count
-  VERIFY(((m1.array().abs()+1)>RealScalar(0.1)).count() == rows*cols);
+  VERIFY(((m1.array().abs()+Scalar(1))>RealScalar(0.1)).count() == rows*cols);
 
   typedef Matrix<typename MatrixType::Index, Dynamic, 1> VectorOfIndices;
 
   // TODO allows colwise/rowwise for array
-  VERIFY_IS_APPROX(((m1.array().abs()+1)>RealScalar(0.1)).matrix().colwise().count(), VectorOfIndices::Constant(cols,rows).transpose());
-  VERIFY_IS_APPROX(((m1.array().abs()+1)>RealScalar(0.1)).matrix().rowwise().count(), VectorOfIndices::Constant(rows, cols));
+  VERIFY_IS_APPROX(((m1.array().abs()+Scalar(1))>RealScalar(0.1)).matrix().colwise().count(), VectorOfIndices::Constant(cols,rows).transpose());
+  VERIFY_IS_APPROX(((m1.array().abs()+Scalar(1))>RealScalar(0.1)).matrix().rowwise().count(), VectorOfIndices::Constant(rows, cols));
 }
 
 template<typename VectorType> void lpNorm(const VectorType& v)
diff -r b1513faeb8c8 test/matrix1x1.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/matrix1x1.cpp	Tue Jun 01 16:58:57 2010 +0200
@@ -0,0 +1,72 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2010 Gael Guennebaud <g.gael@xxxxxxx>
+//
+// Eigen is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 3 of the License, or (at your option) any later version.
+//
+// Alternatively, you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of
+// the License, or (at your option) any later version.
+//
+// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License and a copy of the GNU General Public License along with
+// Eigen. If not, see <http://www.gnu.org/licenses/>.
+
+#include "main.h"
+
+
+template<typename Scalar> void matrix1x1()
+{
+  typedef typename NumTraits<Scalar>::Real RealScalar;
+  typedef Matrix<Scalar, 1, 1> Matrix11;
+  typedef Matrix<Scalar, Dynamic, Dynamic> MatrixX;
+
+  Matrix11 m1, m2;
+  Scalar x1;
+  RealScalar y1;
+
+  // assign from scalar
+  x1 = ei_random<Scalar>();
+  m1 = x1;
+  VERIFY_IS_APPROX(x1,m1(0,0));
+  y1 = ei_random<RealScalar>();
+  m2 = y1;
+  VERIFY_IS_APPROX(Scalar(y1),m2(0,0));
+  x1 = y1 = 0;
+
+  // convert to scalar
+  x1 = m1;
+  VERIFY_IS_APPROX(x1,m1(0,0));
+  x1 = m1 + m2;
+  VERIFY_IS_APPROX(x1,(m1+m2)(0,0));
+
+  // inner product
+  int s = ei_random<int>(1,30);
+  int i = ei_random<int>(0,s-1);
+  int j = ei_random<int>(0,s-1);
+  MatrixX m3(s,s);
+  m3.setRandom();
+  x1 = m3.row(i) * m3.col(j);
+  VERIFY_IS_APPROX(x1,(m3.row(i) * m3.col(j))(0,0));
+
+  y1 = std::sin(m1.real());
+  VERIFY_IS_APPROX(y1,std::sin(m1.real()(0,0)));
+}
+
+void test_matrix1x1()
+{
+  for(int i = 0; i < g_repeat ; i++) {
+    CALL_SUBTEST_1( matrix1x1<float>() );
+    CALL_SUBTEST_2( matrix1x1<std::complex<double> >() );
+  }
+}


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