[eigen] [PATCH] Reverse expression (trying again) |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/eigen Archives
]
- To: eigen@xxxxxxxxxxxxxxxxxxx
- Subject: [eigen] [PATCH] Reverse expression (trying again)
- From: Ricard Marxer Piñón <email@xxxxxxxxxxxxxxxx>
- Date: Thu, 5 Feb 2009 15:35:01 +0100
- Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:sender:received:date :x-google-sender-auth:message-id:subject:from:to:content-type; bh=6pigzrrAU0MzH1+tAMWeOcZuHVWY7hXZMnC3meRnUUk=; b=bmvhu52Ytu6uxiF3UQnNObE7ErrV0vJ3WzYJIh+mRZ6Whah+25RkQsCUIxxvJKJg0o HnnG6OIS92cFHqIQXsyQBNdiRN/fftusVf+ntF61+8sZ7ZsFgED+C5Bbn2rcISeHh8Kx 9bgDUZ9ZsYKAocyspWowNVSilM5qe1zdhUcvA=
- Domainkey-signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:sender:date:x-google-sender-auth:message-id:subject :from:to:content-type; b=aHMgsaz0bBzll7LH/IwvAAJs2PopmQkZaiXULMZcfjMinQN0XXz/eP0X1uSB4lmbc6 5Bwa3O1dYwBjr2Tud90qZEjooBwMe2X8P1PCgLxf8SgjxPce4u0wTFnS2le09Zp3TNUo eeCSAH/UkC5j/0YzO4WtYwMAnlnuuLF1JEec8=
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