mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
* 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:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
121
doc/echelon.cpp
121
doc/echelon.cpp
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user