[eigen] [PATCH] Reverse expression (trying again)

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


Hi again,

This time I think I've got it right.  Or at least righter.

I have added tests and as Gael suggested I have added a template parameter to Reverse so that PartialRedux returns an _expression_ (however I still don't know if I've got that part right).

In the tests there is one commented part, which I would like to pass in the future but I think it is a bit more complicated.

The patch as been generated using git:
git format-patch git-svn

So to apply to svn it you will need to do (I think):
patch -p1 -i 0001-adding-Reverse.patch

The coeff(int index) and coeffRef(int index) are still not handled (reversed).  That will come in the next patch.

Ricard

--
ricard
http://www.ricardmarxer.com
http://www.caligraft.com
From 25a9086ad78938454f0776c9698a80b00b7b1114 Mon Sep 17 00:00:00 2001
From: Ricard Marxer <email@xxxxxxxxxxxxxxxx>
Date: Thu, 5 Feb 2009 15:26:48 +0100
Subject: [PATCH] adding Reverse

---
 Eigen/Core                                |    1 +
 Eigen/src/Array/PartialRedux.h            |   16 +++-
 Eigen/src/Core/MatrixBase.h               |    5 +-
 Eigen/src/Core/Reverse.h                  |  172 +++++++++++++++++++++++++++++
 Eigen/src/Core/util/Constants.h           |    2 +-
 Eigen/src/Core/util/ForwardDeclarations.h |    1 +
 doc/snippets/MatrixBase_reverse.cpp       |    8 ++
 doc/snippets/PartialRedux_reverse.cpp     |   10 ++
 test/CMakeLists.txt                       |    1 +
 test/reverse.cpp                          |  131 ++++++++++++++++++++++
 10 files changed, 344 insertions(+), 3 deletions(-)
 create mode 100644 Eigen/src/Core/Reverse.h
 create mode 100644 doc/snippets/MatrixBase_reverse.cpp
 create mode 100644 doc/snippets/PartialRedux_reverse.cpp
 create mode 100644 test/reverse.cpp

diff --git a/Eigen/Core b/Eigen/Core
index 211e0f9..88f5228 100644
--- a/Eigen/Core
+++ b/Eigen/Core
@@ -136,6 +136,7 @@ namespace Eigen {
 #include "src/Core/Block.h"
 #include "src/Core/Minor.h"
 #include "src/Core/Transpose.h"
+#include "src/Core/Reverse.h"
 #include "src/Core/DiagonalMatrix.h"
 #include "src/Core/DiagonalCoeffs.h"
 #include "src/Core/Sum.h"
diff --git a/Eigen/src/Array/PartialRedux.h b/Eigen/src/Array/PartialRedux.h
index 96c13ca..d2813cf 100644
--- a/Eigen/src/Array/PartialRedux.h
+++ b/Eigen/src/Array/PartialRedux.h
@@ -257,7 +257,21 @@ template<typename ExpressionType, int Direction> class PartialRedux
       * \sa MatrixBase::count() */
     const PartialReduxExpr<ExpressionType, ei_member_count<int>, Direction> count() const
     { return _expression(); }
-
+    
+    
+    /** \returns a matrix expression
+      * where each column (or row) are reversed.
+      *
+      * Example: \include PartialRedux_reverse.cpp
+      * Output: \verbinclude PartialRedux_reverse.out
+      *
+      * \sa MatrixBase::reverse() */
+    const Reverse<ExpressionType, Direction> reverse() const
+    {
+      return Reverse<ExpressionType, Direction>( _expression() );
+    }
+  
+    
     /** \returns a 3x3 matrix expression of the cross product
       * of each column or row of the referenced expression with the \a other vector.
       *
diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h
index 6b7b002..c558881 100644
--- a/Eigen/src/Core/MatrixBase.h
+++ b/Eigen/src/Core/MatrixBase.h
@@ -359,7 +359,10 @@ template<typename Derived> class MatrixBase
     const Eigen::Transpose<Derived> transpose() const;
     void transposeInPlace();
     const AdjointReturnType adjoint() const;
-
+  
+    Eigen::Reverse<Derived, BothDirections> reverse();
+    const Eigen::Reverse<Derived, BothDirections> reverse() const;
+    void reverseInPlace();
 
     RowXpr row(int i);
     const RowXpr row(int i) const;
diff --git a/Eigen/src/Core/Reverse.h b/Eigen/src/Core/Reverse.h
new file mode 100644
index 0000000..a53eaed
--- /dev/null
+++ b/Eigen/src/Core/Reverse.h
@@ -0,0 +1,172 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@xxxxxxxxx>
+// Copyright (C) 2009 Ricard Marxer <email@xxxxxxxxxxxxxxxx>
+//
+// 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/>.
+
+#ifndef EIGEN_REVERSE_H
+#define EIGEN_REVERSE_H
+
+/** \class Reverse
+  *
+  * \brief Expression of the reverse of a vector
+  *
+  * \param MatrixType the type of the object of which we are taking the reverse
+  *
+  * This class represents an expression of the reverse of a vector.
+  * It is the return type of MatrixBase::reverse()
+  * and most of the time this is the only way it is used.
+  *
+  * \sa MatrixBase::reverse()
+  */
+template<typename MatrixType, int Direction>
+struct ei_traits<Reverse<MatrixType, Direction> >
+{
+  typedef typename MatrixType::Scalar Scalar;
+  typedef typename ei_nested<MatrixType>::type MatrixTypeNested;
+  typedef typename ei_unref<MatrixTypeNested>::type _MatrixTypeNested;
+  enum {
+    RowsAtCompileTime = MatrixType::RowsAtCompileTime,
+    ColsAtCompileTime = MatrixType::ColsAtCompileTime,
+    MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
+    MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
+    
+    // TODO: check how to correctly set the new flags
+    Flags = ((int(_MatrixTypeNested::Flags) ^ RowMajorBit)
+          & ~(LowerTriangularBit | UpperTriangularBit))
+          | (int(_MatrixTypeNested::Flags)&UpperTriangularBit ? LowerTriangularBit : 0)
+          | (int(_MatrixTypeNested::Flags)&LowerTriangularBit ? UpperTriangularBit : 0),
+    
+    // TODO: should add two add costs (due to the -1) or only one, and add the cost of calling .rows() and .cols()
+    CoeffReadCost = _MatrixTypeNested::CoeffReadCost
+  };
+};
+
+template<typename MatrixType, int Direction> class Reverse
+  : public MatrixBase<Reverse<MatrixType, Direction> >
+{
+  public:
+
+    EIGEN_GENERIC_PUBLIC_INTERFACE(Reverse)
+
+    inline Reverse(const MatrixType& matrix) : m_matrix(matrix) { }
+
+    EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Reverse)
+
+    inline int rows() const { return m_matrix.rows(); }
+    inline int cols() const { return m_matrix.cols(); }
+
+    inline Scalar& coeffRef(int row, int col)
+    {
+      return m_matrix.const_cast_derived().coeffRef(((Direction == Vertical) || (Direction == BothDirections)) ? m_matrix.rows() - row - 1 : row,
+                                                    ((Direction == Horizontal) || (Direction == BothDirections)) ? m_matrix.cols() - col - 1 : col);
+    }
+
+    inline const Scalar coeff(int row, int col) const
+    {
+      return m_matrix.coeff(((Direction == Vertical) || (Direction == BothDirections)) ? m_matrix.rows() - row - 1 : row,
+                            ((Direction == Horizontal) || (Direction == BothDirections)) ? m_matrix.cols() - col - 1 : col);
+    }
+
+    inline const Scalar coeff(int index) const
+    {
+      return m_matrix.coeff(m_matrix.rows() * m_matrix.cols() - index - 1);
+    }
+
+    inline Scalar& coeffRef(int index)
+    {
+      return m_matrix.const_cast_derived().coeffRef(m_matrix.rows() * m_matrix.cols() - index - 1);
+    }
+
+    // TODO: We must reverse the packet reading and writing, which is currently not done here, I think
+    template<int LoadMode>
+    inline const PacketScalar packet(int row, int col) const
+    {
+      return m_matrix.template packet<LoadMode>(((Direction == Vertical) || (Direction == BothDirections)) ? m_matrix.rows() - row - 1 : row,
+                                                ((Direction == Horizontal) || (Direction == BothDirections)) ? m_matrix.cols() - col - 1 : col);
+    }
+  
+    template<int LoadMode>
+    inline void writePacket(int row, int col, const PacketScalar& x)
+    {
+      m_matrix.const_cast_derived().template writePacket<LoadMode>(((Direction == Vertical) || (Direction == BothDirections)) ? m_matrix.rows() - row - 1 : row,
+                                                                   ((Direction == Horizontal) || (Direction == BothDirections)) ? m_matrix.cols() - col - 1 : col,
+                                                                   x);
+    }
+
+    template<int LoadMode>
+    inline const PacketScalar packet(int index) const
+    {
+      return m_matrix.template packet<LoadMode>(m_matrix.rows() * m_matrix.cols() - index - 1);
+    }
+
+    template<int LoadMode>
+    inline void writePacket(int index, const PacketScalar& x)
+    {
+      m_matrix.const_cast_derived().template writePacket<LoadMode>(m_matrix.rows() * m_matrix.cols() - index - 1, x);
+    }
+
+  protected:
+    const typename MatrixType::Nested m_matrix;
+};
+
+/** \returns an expression of the reverse of *this.
+  *
+  * Example: \include MatrixBase_reverse.cpp
+  * Output: \verbinclude MatrixBase_reverse.out
+  *
+  */
+template<typename Derived>
+inline Reverse<Derived, BothDirections>
+MatrixBase<Derived>::reverse()
+{
+  return derived();
+}
+
+/** This is the const version of reverse(). */
+template<typename Derived>
+inline const Reverse<Derived, BothDirections>
+MatrixBase<Derived>::reverse() const
+{
+  return derived();
+}
+
+/** This is the "in place" version of reverse: it reverses \c *this.
+  *
+  * In most cases it is probably better to simply use the reversed expression
+  * of a matrix. However, when reversing the matrix data itself is really needed,
+  * then this "in-place" version is probably the right choice because it provides
+  * the following additional features:
+  *  - less error prone: doing the same operation with .reverse() requires special care:
+  *    \code m = m.reverse().eval(); \endcode
+  *  - no temporary object is created (currently there is one created but could be avoided using swap)
+  *  - it allows future optimizations (cache friendliness, etc.)
+  *
+  * \sa reverse() */
+template<typename Derived>
+inline void MatrixBase<Derived>::reverseInPlace()
+{
+  this = this.reverse().eval();
+}
+
+
+#endif // EIGEN_REVERSE_H
diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h
index 1cbf501..603e595 100644
--- a/Eigen/src/Core/util/Constants.h
+++ b/Eigen/src/Core/util/Constants.h
@@ -200,7 +200,7 @@ enum { Aligned, Unaligned };
 enum { ForceAligned, AsRequested };
 enum { ConditionalJumpCost = 5 };
 enum CornerType { TopLeft, TopRight, BottomLeft, BottomRight };
-enum DirectionType { Vertical, Horizontal };
+enum DirectionType { Vertical, Horizontal, BothDirections };
 enum ProductEvaluationMode { NormalProduct, CacheFriendlyProduct, DiagonalProduct, SparseTimeSparseProduct, SparseTimeDenseProduct, DenseTimeSparseProduct };
 
 enum {
diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h
index 83c4244..759efda 100644
--- a/Eigen/src/Core/util/ForwardDeclarations.h
+++ b/Eigen/src/Core/util/ForwardDeclarations.h
@@ -40,6 +40,7 @@ template<typename MatrixType, int BlockRows=Dynamic, int BlockCols=Dynamic, int
          int _DirectAccessStatus = ei_traits<MatrixType>::Flags&DirectAccessBit ? DirectAccessBit
                                  : ei_traits<MatrixType>::Flags&SparseBit> class Block;
 template<typename MatrixType> class Transpose;
+template<typename MatrixType, int Direction = BothDirections> class Reverse;
 template<typename MatrixType> class Conjugate;
 template<typename NullaryOp, typename MatrixType>         class CwiseNullaryOp;
 template<typename UnaryOp,   typename MatrixType>         class CwiseUnaryOp;
diff --git a/doc/snippets/MatrixBase_reverse.cpp b/doc/snippets/MatrixBase_reverse.cpp
new file mode 100644
index 0000000..f545a28
--- /dev/null
+++ b/doc/snippets/MatrixBase_reverse.cpp
@@ -0,0 +1,8 @@
+MatrixXi m = MatrixXi::Random(3,4);
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the reverse of m:" << endl << m.reverse() << endl;
+cout << "Here is the coefficient (1,0) in the reverse of m:" << endl
+     << m.reverse()(1,0) << endl;
+cout << "Let us overwrite this coefficient with the value 4." << endl;
+m.reverse()(1,0) = 4;
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/doc/snippets/PartialRedux_reverse.cpp b/doc/snippets/PartialRedux_reverse.cpp
new file mode 100644
index 0000000..57a0d6f
--- /dev/null
+++ b/doc/snippets/PartialRedux_reverse.cpp
@@ -0,0 +1,10 @@
+MatrixXi m = MatrixXi::Random(3,4);
+cout << "Here is the matrix m:" << endl << m << endl;
+cout << "Here is the rowwise reverse of m:" << endl << m.rowwise().reverse() << endl;
+cout << "Here is the colwise reverse of m:" << endl << m.colwise().reverse() << endl;
+
+cout << "Here is the coefficient (1,0) in the colwise reverse of m:" << endl
+<< m.colwise().reverse()(1,0) << endl;
+cout << "Let us overwrite this coefficient with the value 4." << endl;
+//m.colwise().reverse()(1,0) = 4;
+cout << "Now the matrix m is:" << endl << m << endl;
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 01bb721..bd766ff 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -137,6 +137,7 @@ endif(QT4_FOUND)
 ei_add_test(sparse_vector)
 ei_add_test(sparse_basic)
 ei_add_test(sparse_solvers " " "${SPARSE_LIBS}")
+ei_add_test(reverse)
 
 # print a summary of the different options
 message("************************************************************")
diff --git a/test/reverse.cpp b/test/reverse.cpp
new file mode 100644
index 0000000..104768a
--- /dev/null
+++ b/test/reverse.cpp
@@ -0,0 +1,131 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra. Eigen itself is part of the KDE project.
+//
+// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@xxxxxxxxx>
+// Copyright (C) 2009 Ricard Marxer <email@xxxxxxxxxxxxxxxx>
+//
+// 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 MatrixType> void reverse(const MatrixType& m)
+{
+  typedef typename MatrixType::Scalar Scalar;
+  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;
+
+  int rows = m.rows();
+  int cols = m.cols();
+
+  // this test relies a lot on Random.h, and there's not much more that we can do
+  // to test it, hence I consider that we will have tested Random.h
+  MatrixType m1 = MatrixType::Random(rows, cols);  
+  VectorType v1 = VectorType::Random(rows);
+
+  MatrixType m1_r = m1.reverse();
+  // Verify that MatrixBase::reverse() works
+  for ( int i = 0; i < rows; i++ ) {
+    for ( int j = 0; j < cols; j++ ) {
+      VERIFY_IS_APPROX(m1_r(i, j), m1(rows - 1 - i, cols - 1 - j));
+    }
+  }
+  
+  Reverse<MatrixType> m1_rd(m1);
+  // Verify that a Reverse default (in both directions) of an expression works
+  for ( int i = 0; i < rows; i++ ) {
+    for ( int j = 0; j < cols; j++ ) {
+      VERIFY_IS_APPROX(m1_rd(i, j), m1(rows - 1 - i, cols - 1 - j));
+    }
+  }
+  
+  Reverse<MatrixType, BothDirections> m1_rb(m1);
+  // Verify that a Reverse in both directions of an expression works
+  for ( int i = 0; i < rows; i++ ) {
+    for ( int j = 0; j < cols; j++ ) {
+      VERIFY_IS_APPROX(m1_rb(i, j), m1(rows - 1 - i, cols - 1 - j));
+    }
+  }
+
+  Reverse<MatrixType, Vertical> m1_rv(m1);
+  // Verify that a Reverse in the vertical directions of an expression works
+  for ( int i = 0; i < rows; i++ ) {
+    for ( int j = 0; j < cols; j++ ) {
+      VERIFY_IS_APPROX(m1_rv(i, j), m1(rows - 1 - i, j));
+    }
+  }
+
+  Reverse<MatrixType, Horizontal> m1_rh(m1);
+  // Verify that a Reverse in the horizontal directions of an expression works
+  for ( int i = 0; i < rows; i++ ) {
+    for ( int j = 0; j < cols; j++ ) {
+      VERIFY_IS_APPROX(m1_rh(i, j), m1(i, cols - 1 - j));
+    }
+  }
+
+  VectorType v1_r = v1.reverse();
+  // Verify that a VectorType::reverse() of an expression works
+  for ( int i = 0; i < rows; i++ ) {
+    VERIFY_IS_APPROX(v1_r(i), v1(rows - 1 - i));
+  }  
+
+  MatrixType m1_cr = m1.colwise().reverse();
+  // Verify that PartialRedux::reverse() works (for colwise())
+  for ( int i = 0; i < rows; i++ ) {
+    for ( int j = 0; j < cols; j++ ) {
+      VERIFY_IS_APPROX(m1_cr(i, j), m1(rows - 1 - i, j));
+    }
+  }
+
+  MatrixType m1_rr = m1.rowwise().reverse();
+  // Verify that PartialRedux::reverse() works (for rowwise())
+  for ( int i = 0; i < rows; i++ ) {
+    for ( int j = 0; j < cols; j++ ) {
+      VERIFY_IS_APPROX(m1_rr(i, j), m1(i, cols - 1 - j));
+    }
+  }
+    
+  /* 
+  Scalar x = ei_random<Scalar>();
+
+  int r = ei_random<int>(0, rows-1),
+      c = ei_random<int>(0, cols-1);
+
+  m1.reverse()(r, c) = x;
+  VERIFY_IS_APPROX(x, m1(rows - 1 - r, cols - 1 - c));
+  
+  m1.colwise().reverse()(r, c) = x;
+  VERIFY_IS_APPROX(x, m1(rows - 1 - r, c));
+
+  m1.rowwise().reverse()(r, c) = x;
+  VERIFY_IS_APPROX(x, m1(r, cols - 1 - c));
+  */
+}
+
+void test_reverse()
+{
+  for(int i = 0; i < g_repeat; i++) {
+    CALL_SUBTEST( reverse(Matrix<float, 1, 1>()) );
+    CALL_SUBTEST( reverse(Matrix4d()) );
+    CALL_SUBTEST( reverse(MatrixXcf(3, 3)) );
+    CALL_SUBTEST( reverse(MatrixXi(8, 12)) );
+    CALL_SUBTEST( reverse(MatrixXcd(20, 20)) );
+    CALL_SUBTEST( reverse(Matrix<float, 100, 100>()) );
+    CALL_SUBTEST( reverse(Matrix<long double,Dynamic,Dynamic>(10,10)) );
+  }
+}
-- 
1.5.6.3



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