mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-04-23 01:59:38 +08:00
Docs: add section on resolving the aliasing issue.
This commit is contained in:
parent
d1111d625c
commit
474c2996bd
@ -31,19 +31,19 @@ The output is not what one would expect. The problem is the assignment
|
|||||||
\code
|
\code
|
||||||
mat.bottomRightCorner(2,2) = mat.topLeftCorner(2,2);
|
mat.bottomRightCorner(2,2) = mat.topLeftCorner(2,2);
|
||||||
\endcode
|
\endcode
|
||||||
After the assignment, the (2,2) entry in the bottom right corner should have the value of \c mat(1,1) before
|
This assignment exhibits aliasing: the coefficient \c mat(1,1) appears both in the block
|
||||||
the assignment, which is 5. However, the output shows that \c mat(2,2) is actually 1. The problem is that
|
<tt>mat.bottomRightCorner(2,2)</tt> on the left-hand side of the assignment and the block
|
||||||
Eigen uses lazy evaluation (see \ref TopicEigenExpressionTemplates) for <tt>mat.topLeftCorner(2,2)</tt>. The
|
<tt>mat.topLeftCorner(2,2)</tt> on the right-hand side. After the assignment, the (2,2) entry in the bottom
|
||||||
result is similar to
|
right corner should have the value of \c mat(1,1) before the assignment, which is 5. However, the output shows
|
||||||
|
that \c mat(2,2) is actually 1. The problem is that Eigen uses lazy evaluation (see
|
||||||
|
\ref TopicEigenExpressionTemplates) for <tt>mat.topLeftCorner(2,2)</tt>. The result is similar to
|
||||||
\code
|
\code
|
||||||
mat(1,1) = mat(0,0);
|
mat(1,1) = mat(0,0);
|
||||||
mat(1,2) = mat(0,1);
|
mat(1,2) = mat(0,1);
|
||||||
mat(2,1) = mat(1,0);
|
mat(2,1) = mat(1,0);
|
||||||
mat(2,2) = mat(1,1);
|
mat(2,2) = mat(1,1);
|
||||||
\endcode
|
\endcode
|
||||||
Thus, \c mat(2,2) is assigned the \e new value of \c mat(1,1) instead of the old value. The issue here is that
|
Thus, \c mat(2,2) is assigned the \e new value of \c mat(1,1) instead of the old value. The next section
|
||||||
the blocks <tt>mat.bottomRightCorner(2,2)</tt> and <tt>mat.topLeftCorner(2,2)</tt> overlap, because both
|
|
||||||
contain the coefficient <tt>mat(1,1)</tt> at the centre of the 3-by-3 matrix \c mat . The next section
|
|
||||||
explains how to solve this problem by calling \link DenseBase::eval() eval()\endlink.
|
explains how to solve this problem by calling \link DenseBase::eval() eval()\endlink.
|
||||||
|
|
||||||
Note that if \c mat were a bigger, then the blocks would not overlap, and there would be no aliasing
|
Note that if \c mat were a bigger, then the blocks would not overlap, and there would be no aliasing
|
||||||
@ -75,7 +75,47 @@ aliasing problem. See \ref TopicAssertions for more information about Eigen's ru
|
|||||||
|
|
||||||
\section TopicAliasingSolution Resolving aliasing issues
|
\section TopicAliasingSolution Resolving aliasing issues
|
||||||
|
|
||||||
Synopsis: xxxInPlace(), eval().
|
If you understand the cause of the aliasing issue, then it is obvious what must happen to solve it: Eigen has
|
||||||
|
to evaluate the right-hand side fully into a temporary matrix/array and then assign it to the left-hand
|
||||||
|
side. The function \link DenseBase::eval() eval() \endlink does precisely that.
|
||||||
|
|
||||||
|
For example, here is the corrected version of the first example above:
|
||||||
|
|
||||||
|
<table class="tutorial_code"><tr><td>
|
||||||
|
Example: \include TopicAliasing_block_correct.cpp
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Output: \verbinclude TopicAliasing_block_correct.out
|
||||||
|
</td></tr></table>
|
||||||
|
|
||||||
|
Now, \c mat(2,2) equals 5 after the assignment, as it should be.
|
||||||
|
|
||||||
|
The same solution also works for the second example, with the transpose: simply replace the line
|
||||||
|
<tt>a = a.transpose();</tt> with <tt>a = a.transpose().eval();</tt>. However, in this common case there is a
|
||||||
|
better solution. Eigen provides the special-purpose function
|
||||||
|
\link DenseBase::transposeInPlace() transposeInPlace() \endlink which replaces a matrix by its transpose.
|
||||||
|
This is shown below:
|
||||||
|
|
||||||
|
<table class="tutorial_code"><tr><td>
|
||||||
|
Example: \include tut_arithmetic_transpose_inplace.cpp
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
Output: \verbinclude tut_arithmetic_transpose_inplace.out
|
||||||
|
</td></tr></table>
|
||||||
|
|
||||||
|
If an xxxInPlace() function is available, then it is best to use it, because it indicate more clearly what you
|
||||||
|
are doing. This may also allow Eigen to optimize more aggressively. These are some of the xxxInPlace()
|
||||||
|
functions provided:
|
||||||
|
|
||||||
|
<table class="tutorial_code" align="center">
|
||||||
|
<tr> <td> <b>Original function</b> </td> <td> <b>In-place function</b> </td> </tr>
|
||||||
|
<tr> <td> MatrixBase::adjoint() </td> <td> MatrixBase::adjointInPlace() </td> </tr>
|
||||||
|
<tr> <td> DenseBase::reverse() </td> <td> DenseBase::reverseInPlace() </td> </tr>
|
||||||
|
<tr> <td> LDLT::solve() </td> <td> LDLT::solveInPlace() </td> </tr>
|
||||||
|
<tr> <td> LLT::solve() </td> <td> LLT::solveInPlace() </td> </tr>
|
||||||
|
<tr> <td> TriangularView::solve() </td> <td> TriangularView::solveInPlace() </td> </tr>
|
||||||
|
<tr> <td> DenseBase::transpose() </td> <td> DenseBase::transposeInPlace() </td> </tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
\section TopicAliasingCwise Aliasing and component-wise operations
|
\section TopicAliasingCwise Aliasing and component-wise operations
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
MatrixXi mat(3,3);
|
MatrixXi mat(3,3);
|
||||||
mat << 1, 2, 3, 4, 5, 6, 7, 8, 9;
|
mat << 1, 2, 3, 4, 5, 6, 7, 8, 9;
|
||||||
cout << "Here is the matrix mat:\n" << mat << endl;
|
cout << "Here is the matrix mat:\n" << mat << endl;
|
||||||
|
|
||||||
|
// This assignment shows the aliasing problem
|
||||||
mat.bottomRightCorner(2,2) = mat.topLeftCorner(2,2);
|
mat.bottomRightCorner(2,2) = mat.topLeftCorner(2,2);
|
||||||
cout << "After the assignment, mat = \n" << mat << endl;
|
cout << "After the assignment, mat = \n" << mat << endl;
|
||||||
|
7
doc/snippets/TopicAliasing_block_correct.cpp
Normal file
7
doc/snippets/TopicAliasing_block_correct.cpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
MatrixXi mat(3,3);
|
||||||
|
mat << 1, 2, 3, 4, 5, 6, 7, 8, 9;
|
||||||
|
cout << "Here is the matrix mat:\n" << mat << endl;
|
||||||
|
|
||||||
|
// The eval() solves the aliasing problem
|
||||||
|
mat.bottomRightCorner(2,2) = mat.topLeftCorner(2,2).eval();
|
||||||
|
cout << "After the assignment, mat = \n" << mat << endl;
|
Loading…
x
Reference in New Issue
Block a user