You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 lines
9.0 KiB

  1. namespace Eigen {
  2. /** \page TopicAliasing Aliasing
  3. In Eigen, aliasing refers to assignment statement in which the same matrix (or array or vector) appears on the
  4. left and on the right of the assignment operators. Statements like <tt>mat = 2 * mat;</tt> or <tt>mat =
  5. mat.transpose();</tt> exhibit aliasing. The aliasing in the first example is harmless, but the aliasing in the
  6. second example leads to unexpected results. This page explains what aliasing is, when it is harmful, and what
  7. to do about it.
  8. <b>Table of contents</b>
  9. - \ref TopicAliasingExamples
  10. - \ref TopicAliasingSolution
  11. - \ref TopicAliasingCwise
  12. - \ref TopicAliasingMatrixMult
  13. - \ref TopicAliasingSummary
  14. \section TopicAliasingExamples Examples
  15. Here is a simple example exhibiting aliasing:
  16. <table class="example">
  17. <tr><th>Example</th><th>Output</th></tr>
  18. <tr><td>
  19. \include TopicAliasing_block.cpp
  20. </td>
  21. <td>
  22. \verbinclude TopicAliasing_block.out
  23. </td></tr></table>
  24. The output is not what one would expect. The problem is the assignment
  25. \code
  26. mat.bottomRightCorner(2,2) = mat.topLeftCorner(2,2);
  27. \endcode
  28. This assignment exhibits aliasing: the coefficient \c mat(1,1) appears both in the block
  29. <tt>mat.bottomRightCorner(2,2)</tt> on the left-hand side of the assignment and the block
  30. <tt>mat.topLeftCorner(2,2)</tt> on the right-hand side. After the assignment, the (2,2) entry in the bottom
  31. right corner should have the value of \c mat(1,1) before the assignment, which is 5. However, the output shows
  32. that \c mat(2,2) is actually 1. The problem is that Eigen uses lazy evaluation (see
  33. \ref TopicEigenExpressionTemplates) for <tt>mat.topLeftCorner(2,2)</tt>. The result is similar to
  34. \code
  35. mat(1,1) = mat(0,0);
  36. mat(1,2) = mat(0,1);
  37. mat(2,1) = mat(1,0);
  38. mat(2,2) = mat(1,1);
  39. \endcode
  40. Thus, \c mat(2,2) is assigned the \e new value of \c mat(1,1) instead of the old value. The next section
  41. explains how to solve this problem by calling \link DenseBase::eval() eval()\endlink.
  42. Note that if \c mat were a bigger, then the blocks would not overlap, and there would be no aliasing
  43. problem. This means that in general aliasing cannot be detected at compile time. However, Eigen does detect
  44. some instances of aliasing, albeit at run time. The following example exhibiting aliasing was mentioned in
  45. \ref TutorialMatrixArithmetic :
  46. <table class="example">
  47. <tr><th>Example</th><th>Output</th></tr>
  48. <tr><td>
  49. \include tut_arithmetic_transpose_aliasing.cpp
  50. </td>
  51. <td>
  52. \verbinclude tut_arithmetic_transpose_aliasing.out
  53. </td></tr></table>
  54. Again, the output shows the aliasing issue. However, by default Eigen uses a run-time assertion to detect this
  55. and exits with a message like
  56. \verbatim
  57. void Eigen::DenseBase<Derived>::checkTransposeAliasing(const OtherDerived&) const
  58. [with OtherDerived = Eigen::Transpose<Eigen::Matrix<int, 2, 2, 0, 2, 2> >, Derived = Eigen::Matrix<int, 2, 2, 0, 2, 2>]:
  59. Assertion `(!internal::check_transpose_aliasing_selector<Scalar,internal::blas_traits<Derived>::IsTransposed,OtherDerived>::run(internal::extract_data(derived()), other))
  60. && "aliasing detected during tranposition, use transposeInPlace() or evaluate the rhs into a temporary using .eval()"' failed.
  61. \endverbatim
  62. The user can turn Eigen's run-time assertions like the one to detect this aliasing problem off by defining the
  63. EIGEN_NO_DEBUG macro, and the above program was compiled with this macro turned off in order to illustrate the
  64. aliasing problem. See \ref TopicAssertions for more information about Eigen's run-time assertions.
  65. \section TopicAliasingSolution Resolving aliasing issues
  66. If you understand the cause of the aliasing issue, then it is obvious what must happen to solve it: Eigen has
  67. to evaluate the right-hand side fully into a temporary matrix/array and then assign it to the left-hand
  68. side. The function \link DenseBase::eval() eval() \endlink does precisely that.
  69. For example, here is the corrected version of the first example above:
  70. <table class="example">
  71. <tr><th>Example</th><th>Output</th></tr>
  72. <tr><td>
  73. \include TopicAliasing_block_correct.cpp
  74. </td>
  75. <td>
  76. \verbinclude TopicAliasing_block_correct.out
  77. </td></tr></table>
  78. Now, \c mat(2,2) equals 5 after the assignment, as it should be.
  79. The same solution also works for the second example, with the transpose: simply replace the line
  80. <tt>a = a.transpose();</tt> with <tt>a = a.transpose().eval();</tt>. However, in this common case there is a
  81. better solution. Eigen provides the special-purpose function
  82. \link DenseBase::transposeInPlace() transposeInPlace() \endlink which replaces a matrix by its transpose.
  83. This is shown below:
  84. <table class="example">
  85. <tr><th>Example</th><th>Output</th></tr>
  86. <tr><td>
  87. \include tut_arithmetic_transpose_inplace.cpp
  88. </td>
  89. <td>
  90. \verbinclude tut_arithmetic_transpose_inplace.out
  91. </td></tr></table>
  92. If an xxxInPlace() function is available, then it is best to use it, because it indicates more clearly what you
  93. are doing. This may also allow Eigen to optimize more aggressively. These are some of the xxxInPlace()
  94. functions provided:
  95. <table class="manual">
  96. <tr><th>Original function</th><th>In-place function</th></tr>
  97. <tr> <td> MatrixBase::adjoint() </td> <td> MatrixBase::adjointInPlace() </td> </tr>
  98. <tr class="alt"> <td> DenseBase::reverse() </td> <td> DenseBase::reverseInPlace() </td> </tr>
  99. <tr> <td> LDLT::solve() </td> <td> LDLT::solveInPlace() </td> </tr>
  100. <tr class="alt"> <td> LLT::solve() </td> <td> LLT::solveInPlace() </td> </tr>
  101. <tr> <td> TriangularView::solve() </td> <td> TriangularView::solveInPlace() </td> </tr>
  102. <tr class="alt"> <td> DenseBase::transpose() </td> <td> DenseBase::transposeInPlace() </td> </tr>
  103. </table>
  104. \section TopicAliasingCwise Aliasing and component-wise operations
  105. As explained above, it may be dangerous if the same matrix or array occurs on both the left-hand side and the
  106. right-hand side of an assignment operator, and it is then often necessary to evaluate the right-hand side
  107. explicitly. However, applying component-wise operations (such as matrix addition, scalar multiplication and
  108. array multiplication) is safe.
  109. The following example has only component-wise operations. Thus, there is no need for .eval() even though
  110. the same matrix appears on both sides of the assignments.
  111. <table class="example">
  112. <tr><th>Example</th><th>Output</th></tr>
  113. <tr><td>
  114. \include TopicAliasing_cwise.cpp
  115. </td>
  116. <td>
  117. \verbinclude TopicAliasing_cwise.out
  118. </td></tr></table>
  119. In general, an assignment is safe if the (i,j) entry of the expression on the right-hand side depends only on
  120. the (i,j) entry of the matrix or array on the left-hand side and not on any other entries. In that case it is
  121. not necessary to evaluate the right-hand side explicitly.
  122. \section TopicAliasingMatrixMult Aliasing and matrix multiplication
  123. Matrix multiplication is the only operation in Eigen that assumes aliasing by default. Thus, if \c matA is a
  124. matrix, then the statement <tt>matA = matA * matA;</tt> is safe. All other operations in Eigen assume that
  125. there are no aliasing problems, either because the result is assigned to a different matrix or because it is a
  126. component-wise operation.
  127. <table class="example">
  128. <tr><th>Example</th><th>Output</th></tr>
  129. <tr><td>
  130. \include TopicAliasing_mult1.cpp
  131. </td>
  132. <td>
  133. \verbinclude TopicAliasing_mult1.out
  134. </td></tr></table>
  135. However, this comes at a price. When executing the expression <tt>matA = matA * matA</tt>, Eigen evaluates the
  136. product in a temporary matrix which is assigned to \c matA after the computation. This is fine. But Eigen does
  137. the same when the product is assigned to a different matrix (e.g., <tt>matB = matA * matA</tt>). In that case,
  138. it is more efficient to evaluate the product directly into \c matB instead of evaluating it first into a
  139. temporary matrix and copying that matrix to \c matB.
  140. The user can indicate with the \link MatrixBase::noalias() noalias()\endlink function that there is no
  141. aliasing, as follows: <tt>matB.noalias() = matA * matA</tt>. This allows Eigen to evaluate the matrix product
  142. <tt>matA * matA</tt> directly into \c matB.
  143. <table class="example">
  144. <tr><th>Example</th><th>Output</th></tr>
  145. <tr><td>
  146. \include TopicAliasing_mult2.cpp
  147. </td>
  148. <td>
  149. \verbinclude TopicAliasing_mult2.out
  150. </td></tr></table>
  151. Of course, you should not use \c noalias() when there is in fact aliasing taking place. If you do, then you
  152. may get wrong results:
  153. <table class="example">
  154. <tr><th>Example</th><th>Output</th></tr>
  155. <tr><td>
  156. \include TopicAliasing_mult3.cpp
  157. </td>
  158. <td>
  159. \verbinclude TopicAliasing_mult3.out
  160. </td></tr></table>
  161. \section TopicAliasingSummary Summary
  162. Aliasing occurs when the same matrix or array coefficients appear both on the left- and the right-hand side of
  163. an assignment operator.
  164. - Aliasing is harmless with coefficient-wise computations; this includes scalar multiplication and matrix or
  165. array addition.
  166. - When you multiply two matrices, Eigen assumes that aliasing occurs. If you know that there is no aliasing,
  167. then you can use \link MatrixBase::noalias() noalias()\endlink.
  168. - In all other situations, Eigen assumes that there is no aliasing issue and thus gives the wrong result if
  169. aliasing does in fact occur. To prevent this, you have to use \link DenseBase::eval() eval() \endlink or
  170. one of the xxxInPlace() functions.
  171. */
  172. }