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.

128 lines
5.3 KiB

  1. namespace StormEigen {
  2. /** \page TopicWritingEfficientProductExpression Writing efficient matrix product expressions
  3. In general achieving good performance with Eigen does no require any special effort:
  4. simply write your expressions in the most high level way. This is especially true
  5. for small fixed size matrices. For large matrices, however, it might be useful to
  6. take some care when writing your expressions in order to minimize useless evaluations
  7. and optimize the performance.
  8. In this page we will give a brief overview of the Eigen's internal mechanism to simplify
  9. and evaluate complex product expressions, and discuss the current limitations.
  10. In particular we will focus on expressions matching level 2 and 3 BLAS routines, i.e,
  11. all kind of matrix products and triangular solvers.
  12. Indeed, in Eigen we have implemented a set of highly optimized routines which are very similar
  13. to BLAS's ones. Unlike BLAS, those routines are made available to user via a high level and
  14. natural API. Each of these routines can compute in a single evaluation a wide variety of expressions.
  15. Given an expression, the challenge is then to map it to a minimal set of routines.
  16. As explained latter, this mechanism has some limitations, and knowing them will allow
  17. you to write faster code by making your expressions more Eigen friendly.
  18. \section GEMM General Matrix-Matrix product (GEMM)
  19. Let's start with the most common primitive: the matrix product of general dense matrices.
  20. In the BLAS world this corresponds to the GEMM routine. Our equivalent primitive can
  21. perform the following operation:
  22. \f$ C.noalias() += \alpha op1(A) op2(B) \f$
  23. where A, B, and C are column and/or row major matrices (or sub-matrices),
  24. alpha is a scalar value, and op1, op2 can be transpose, adjoint, conjugate, or the identity.
  25. When Eigen detects a matrix product, it analyzes both sides of the product to extract a
  26. unique scalar factor alpha, and for each side, its effective storage order, shape, and conjugation states.
  27. More precisely each side is simplified by iteratively removing trivial expressions such as scalar multiple,
  28. negation and conjugation. Transpose and Block expressions are not evaluated and they only modify the storage order
  29. and shape. All other expressions are immediately evaluated.
  30. For instance, the following expression:
  31. \code m1.noalias() -= s4 * (s1 * m2.adjoint() * (-(s3*m3).conjugate()*s2)) \endcode
  32. is automatically simplified to:
  33. \code m1.noalias() += (s1*s2*conj(s3)*s4) * m2.adjoint() * m3.conjugate() \endcode
  34. which exactly matches our GEMM routine.
  35. \subsection GEMM_Limitations Limitations
  36. Unfortunately, this simplification mechanism is not perfect yet and not all expressions which could be
  37. handled by a single GEMM-like call are correctly detected.
  38. <table class="manual" style="width:100%">
  39. <tr>
  40. <th>Not optimal expression</th>
  41. <th>Evaluated as</th>
  42. <th>Optimal version (single evaluation)</th>
  43. <th>Comments</th>
  44. </tr>
  45. <tr>
  46. <td>\code
  47. m1 += m2 * m3; \endcode</td>
  48. <td>\code
  49. temp = m2 * m3;
  50. m1 += temp; \endcode</td>
  51. <td>\code
  52. m1.noalias() += m2 * m3; \endcode</td>
  53. <td>Use .noalias() to tell Eigen the result and right-hand-sides do not alias.
  54. Otherwise the product m2 * m3 is evaluated into a temporary.</td>
  55. </tr>
  56. <tr class="alt">
  57. <td></td>
  58. <td></td>
  59. <td>\code
  60. m1.noalias() += s1 * (m2 * m3); \endcode</td>
  61. <td>This is a special feature of Eigen. Here the product between a scalar
  62. and a matrix product does not evaluate the matrix product but instead it
  63. returns a matrix product expression tracking the scalar scaling factor. <br>
  64. Without this optimization, the matrix product would be evaluated into a
  65. temporary as in the next example.</td>
  66. </tr>
  67. <tr>
  68. <td>\code
  69. m1.noalias() += (m2 * m3).adjoint(); \endcode</td>
  70. <td>\code
  71. temp = m2 * m3;
  72. m1 += temp.adjoint(); \endcode</td>
  73. <td>\code
  74. m1.noalias() += m3.adjoint()
  75. * * m2.adjoint(); \endcode</td>
  76. <td>This is because the product expression has the EvalBeforeNesting bit which
  77. enforces the evaluation of the product by the Tranpose expression.</td>
  78. </tr>
  79. <tr class="alt">
  80. <td>\code
  81. m1 = m1 + m2 * m3; \endcode</td>
  82. <td>\code
  83. temp = m2 * m3;
  84. m1 = m1 + temp; \endcode</td>
  85. <td>\code m1.noalias() += m2 * m3; \endcode</td>
  86. <td>Here there is no way to detect at compile time that the two m1 are the same,
  87. and so the matrix product will be immediately evaluated.</td>
  88. </tr>
  89. <tr>
  90. <td>\code
  91. m1.noalias() = m4 + m2 * m3; \endcode</td>
  92. <td>\code
  93. temp = m2 * m3;
  94. m1 = m4 + temp; \endcode</td>
  95. <td>\code
  96. m1 = m4;
  97. m1.noalias() += m2 * m3; \endcode</td>
  98. <td>First of all, here the .noalias() in the first expression is useless because
  99. m2*m3 will be evaluated anyway. However, note how this expression can be rewritten
  100. so that no temporary is required. (tip: for very small fixed size matrix
  101. it is slighlty better to rewrite it like this: m1.noalias() = m2 * m3; m1 += m4;</td>
  102. </tr>
  103. <tr class="alt">
  104. <td>\code
  105. m1.noalias() += (s1*m2).block(..) * m3; \endcode</td>
  106. <td>\code
  107. temp = (s1*m2).block(..);
  108. m1 += temp * m3; \endcode</td>
  109. <td>\code
  110. m1.noalias() += s1 * m2.block(..) * m3; \endcode</td>
  111. <td>This is because our expression analyzer is currently not able to extract trivial
  112. expressions nested in a Block expression. Therefore the nested scalar
  113. multiple cannot be properly extracted.</td>
  114. </tr>
  115. </table>
  116. Of course all these remarks hold for all other kind of products involving triangular or selfadjoint matrices.
  117. */
  118. }