* implement the corner() API change: new methods topLeftCorner() etc

* get rid of BlockReturnType: it was not needed, and code was not always using it consistently anyway
* add topRows(), leftCols(), bottomRows(), rightCols()
* add corners unit-test covering all of that
* adapt docs, expand "porting from eigen 2 to 3"
* adapt Eigen2Support
This commit is contained in:
Benoit Jacob
2010-04-22 14:11:18 -04:00
parent 28dde19e40
commit 9962c59b56
37 changed files with 820 additions and 350 deletions

View File

@@ -9,6 +9,7 @@ and to help porting an application from Eigen2 to Eigen3.
- \ref CompatibilitySupport
- \ref ChangeList
- \ref CoefficientWiseOperations
- \ref Corners
- \ref LazyVsNoalias
\section CompatibilitySupport Eigen2 compatibility support
@@ -81,6 +82,34 @@ With Eigen2 you would have written:
c = (a.cwise().abs().cwise().pow(3)).cwise() * (b.cwise().abs().cwise().sin());
\endcode
\section Corners Corners
<table>
<tr><td>Eigen 2</td><td>Eigen 3</td></tr>
<tr><td>\code
matrix.corner(TopLeft,r,c)
matrix.corner(TopRight,r,c)
matrix.corner(BottomLeft,r,c)
matrix.corner(BottomRight,r,c)
matrix.corner<r,c>(TopLeft)
matrix.corner<r,c>(TopRight)
matrix.corner<r,c>(BottomLeft)
matrix.corner<r,c>(BottomRight)
\endcode</td><td>\code
matrix.topLeftCorner(r,c)
matrix.topRightCorner(r,c)
matrix.bottomLeftCorner(r,c)
matrix.bottomRightCorner(r,c)
matrix.topLeftCorner<r,c>()
matrix.topRightCorner<r,c>()
matrix.bottomLeftCorner<r,c>()
matrix.bottomRightCorner<r,c>()
\endcode</td>
</tr>
</table>
Notice that Eigen3 also provides these new convenience methods: topRows(), bottomRows(), leftCols(), rightCols(). See in class DenseBase.
\section LazyVsNoalias Lazy evaluation and noalias
In Eigen all operations are performed in a lazy fashion except the matrix products which are always evaluated into a temporary by default.

View File

@@ -47,15 +47,14 @@ x.segment(i, n) // x(i+1 : i+n)
x.segment<n>(i) // x(i+1 : i+n)
P.block(i, j, rows, cols) // P(i+1 : i+rows, j+1 : j+cols)
P.block<rows, cols>(i, j) // P(i+1 : i+rows, j+1 : j+cols)
P.corner(TopLeft, rows, cols) // P(1:rows, 1:cols)
P.corner(TopRight, rows, cols) // [m n]=size(P); P(1:rows, n-cols+1:n)
P.corner(BottomLeft, rows, cols) // [m n]=size(P); P(m-rows+1:m, 1:cols)
P.corner(BottomRight, rows, cols) // [m n]=size(P); P(m-rows+1:m, n-cols+1:n)
P.corner<rows,cols>(TopLeft) // P(1:rows, 1:cols)
P.corner<rows,cols>(TopRight) // [m n]=size(P); P(1:rows, n-cols+1:n)
P.corner<rows,cols>(BottomLeft) // [m n]=size(P); P(m-rows+1:m, 1:cols)
P.corner<rows,cols>(BottomRight) // [m n]=size(P); P(m-rows+1:m, n-cols+1:n)
P.minor(i, j) // Something nasty.
P.topLeftCorner(rows, cols) // P(1:rows, 1:cols)
P.topRightCorner(rows, cols) // [m n]=size(P); P(1:rows, n-cols+1:n)
P.bottomLeftCorner(rows, cols) // [m n]=size(P); P(m-rows+1:m, 1:cols)
P.bottomRightCorner(rows, cols) // [m n]=size(P); P(m-rows+1:m, n-cols+1:n)
P.topLeftCorner<rows,cols>() // P(1:rows, 1:cols)
P.topRightCorner<rows,cols>() // [m n]=size(P); P(1:rows, n-cols+1:n)
P.bottomLeftCorner<rows,cols>() // [m n]=size(P); P(m-rows+1:m, 1:cols)
P.bottomRightCorner<rows,cols>() // [m n]=size(P); P(m-rows+1:m, n-cols+1:n)
// Of particular note is Eigen's swap function which is highly optimized.
// Eigen // Matlab

View File

@@ -577,29 +577,22 @@ Read-write access to sub-matrices:</td><td></td><td></td></tr>
\link DenseBase::block(int,int) (more) \endlink</td>
<td>the \c rows x \c cols sub-matrix \n starting from position (\c i,\c j)</td></tr><tr>
<td>\code
mat1.corner(TopLeft,rows,cols)
mat1.corner(TopRight,rows,cols)
mat1.corner(BottomLeft,rows,cols)
mat1.corner(BottomRight,rows,cols)\endcode
\link DenseBase::corner(CornerType,int,int) (more) \endlink</td>
mat1.topLeftCorner(rows,cols)
mat1.topRightCorner(rows,cols)
mat1.bottomLeftCorner(rows,cols)
mat1.bottomRightCorner(rows,cols)\endcode
<td>\code
mat1.corner<rows,cols>(TopLeft)
mat1.corner<rows,cols>(TopRight)
mat1.corner<rows,cols>(BottomLeft)
mat1.corner<rows,cols>(BottomRight)\endcode
\link DenseBase::corner(CornerType) (more) \endlink</td>
mat1.topLeftCorner<rows,cols>()
mat1.topRightCorner<rows,cols>()
mat1.bottomLeftCorner<rows,cols>()
mat1.bottomRightCorner<rows,cols>()\endcode
<td>the \c rows x \c cols sub-matrix \n taken in one of the four corners</td></tr>
<tr><td>\code
mat4x4.minor(i,j) = mat3x3;
mat3x3 = mat4x4.minor(i,j);\endcode
</td><td></td><td>
\link DenseBase::minor() minor \endlink (read-write)</td>
</tr>
</table>
<a href="#" class="top">top</a>\section TutorialCoreDiagonalMatrices Diagonal matrices \matrixworld
<a href="#" class="top">top</a>\section TutorialCoreDiagonalMatrices Diagonal matrices
\matrixworld
<table class="tutorial_code">
<tr><td>

View File

@@ -153,7 +153,7 @@ glLoadMatrixf(t.data());\endcode</td></tr>
<tr><td>
OpenGL compatibility \b 2D </td><td>\code
Transform3f aux(Transform3f::Identity);
aux.linear().corner<2,2>(TopLeft) = t.linear();
aux.linear().topLeftCorner<2,2>() = t.linear();
aux.translation().start<2>() = t.translation();
glLoadMatrixf(aux.data());\endcode</td></tr>
</table>

View File

@@ -11,7 +11,7 @@ o /** \mainpage Eigen
This is the API documentation for Eigen3.
You come from Eigen2? Here is a \ref Eigen2ToEigen3 guide for porting your application from Eigen2 to Eigen3.
Eigen2 users: here is a \ref Eigen2ToEigen3 guide to help porting your application.
For a first contact with Eigen, the best place is to have a look at the \ref TutorialCore "tutorial". For an even shorter overview, we have an <a href="AsciiQuickReference.txt">ASCII quick reference</a> with Matlab translations.

View File

@@ -1,121 +0,0 @@
#include <Eigen/Core>
USING_PART_OF_NAMESPACE_EIGEN
namespace Eigen {
/* Echelon a matrix in-place:
*
* Meta-Unrolled version, for small fixed-size matrices
*/
template<typename Derived, int Step>
struct unroll_echelon
{
enum { k = Step - 1,
Rows = Derived::RowsAtCompileTime,
Cols = Derived::ColsAtCompileTime,
CornerRows = Rows - k,
CornerCols = Cols - k
};
static void run(MatrixBase<Derived>& m)
{
unroll_echelon<Derived, Step-1>::run(m);
int rowOfBiggest, colOfBiggest;
m.template corner<CornerRows, CornerCols>(BottomRight)
.cwise().abs()
.maxCoeff(&rowOfBiggest, &colOfBiggest);
m.row(k).swap(m.row(k+rowOfBiggest));
m.col(k).swap(m.col(k+colOfBiggest));
m.template corner<CornerRows-1, CornerCols>(BottomRight)
-= m.col(k).template tail<CornerRows-1>()
* (m.row(k).template tail<CornerCols>() / m(k,k));
}
};
template<typename Derived>
struct unroll_echelon<Derived, 0>
{
static void run(MatrixBase<Derived>& m) {}
};
/* Echelon a matrix in-place:
*
* Non-unrolled version, for dynamic-size matrices.
* (this version works for all matrices, but in the fixed-size case the other
* version is faster).
*/
template<typename Derived>
struct unroll_echelon<Derived, Dynamic>
{
static void run(MatrixBase<Derived>& m)
{
for(int k = 0; k < m.diagonal().size() - 1; k++)
{
int rowOfBiggest, colOfBiggest;
int cornerRows = m.rows()-k, cornerCols = m.cols()-k;
m.corner(BottomRight, cornerRows, cornerCols)
.cwise().abs()
.maxCoeff(&rowOfBiggest, &colOfBiggest);
m.row(k).swap(m.row(k+rowOfBiggest));
m.col(k).swap(m.col(k+colOfBiggest));
m.corner(BottomRight, cornerRows-1, cornerCols)
-= m.col(k).tail(cornerRows-1) * (m.row(k).tail(cornerCols) / m(k,k));
}
}
};
using namespace std;
template<typename Derived>
void echelon(MatrixBase<Derived>& m)
{
const int size = DiagonalCoeffs<Derived>::SizeAtCompileTime;
const bool unroll = size <= 4;
unroll_echelon<Derived, unroll ? size-1 : Dynamic>::run(m);
}
template<typename Derived>
void doSomeRankPreservingOperations(MatrixBase<Derived>& m)
{
for(int a = 0; a < 3*(m.rows()+m.cols()); a++)
{
double d = ei_random<double>(-1,1);
int i = ei_random<int>(0,m.rows()-1); // i is a random row number
int j;
do {
j = ei_random<int>(0,m.rows()-1);
} while (i==j); // j is another one (must be different)
m.row(i) += d * m.row(j);
i = ei_random<int>(0,m.cols()-1); // i is a random column number
do {
j = ei_random<int>(0,m.cols()-1);
} while (i==j); // j is another one (must be different)
m.col(i) += d * m.col(j);
}
}
} // namespace Eigen
using namespace std;
int main(int, char **)
{
srand((unsigned int)time(0));
const int Rows = 6, Cols = 4;
typedef Matrix<double, Rows, Cols> Mat;
const int N = Rows < Cols ? Rows : Cols;
// start with a matrix m that's obviously of rank N-1
Mat m = Mat::identity(Rows, Cols); // args just in case of dyn. size
m.row(0) = m.row(1) = m.row(0) + m.row(1);
doSomeRankPreservingOperations(m);
// now m is still a matrix of rank N-1
cout << "Here's the matrix m:" << endl << m << endl;
cout << "Now let's echelon m (repeating many times for benchmarking purposes):" << endl;
for(int i = 0; i < 1000000; i++) echelon(m);
cout << "Now m is:" << endl << m << endl;
}

View File

@@ -1,6 +0,0 @@
Matrix4i m = Matrix4i::Random();
cout << "Here is the matrix m:" << endl << m << endl;
cout << "Here is the bottom-right 2x3 corner in m:" << endl
<< m.corner(Eigen::BottomRight, 2, 3) << endl;
m.corner(Eigen::BottomRight, 2, 3).setZero();
cout << "Now the matrix m is:" << endl << m << endl;

View File

@@ -1,6 +0,0 @@
Matrix4i m = Matrix4i::Random();
cout << "Here is the matrix m:" << endl << m << endl;
cout << "Here is the bottom-right 2x3 corner in m:" << endl
<< m.corner<2,3>(Eigen::BottomRight) << endl;
m.corner<2,3>(Eigen::BottomRight).setZero();
cout << "Now the matrix m is:" << endl << m << endl;