Is there a way to specify that the assignment left-hand side is not aliased?

Issue #287 resolved
Mikhail Katliar created an issue

Consider an example:

using namespace blaze;

StaticMatrix<double, 5, 5, columnMajor> A;
randomize(A);

size_t const n = rows(A);
size_t const k = 1;
size_t const rs = n - k - 1;

auto A21 = submatrix(A, k + 1, k, rs, 1);
auto const A10 = submatrix(A, k, 0, 1, k);
auto const A20 = submatrix(A, k + 1, 0, rs, k);

A21 -= A20 * ctrans(A10);

Here the right-hand side is evaluated to a temporary HybridMatrix , because canAlias() returns true in the following piece of code:

inline auto Submatrix<MT,unaligned,true,true,CSAs...>::operator-=( const Matrix<MT2,SO>& rhs )
   -> DisableIf_t< EnforceEvaluation_v<MT,MT2>, Submatrix& >
{{
  // ....

  if( ( ( IsSymmetric_v<MT> || IsHermitian_v<MT> ) && hasOverlap() ) ||
       (~rhs).canAlias( &matrix_ ) ) {
      const SubType tmp( *this - (~rhs ) );
      smpAssign( left, tmp );
  }
  else {
     smpSubAssign( left, ~rhs );
  }

  // ....
}

This results in degraded performance. But in fact, the A21 submatrix does not overlap with A20 or A10. Is there a way in Blaze to specify that the left-hand side of an assignment is not aliased, similar to noalias() in Eigen?

Comments (8)

  1. Klaus Iglberger

    Hi Mikhail!

    Thanks for yet again raising a very good question. No, so far there is no way to explicitly specify that the assignment is not aliased. I’ve already given this some thought and I don’t want to introduce a tag for the left-hand side target (that just feels wrong). Instead the left-hand side target should be able to determine this automatically. I’ll see what can be done to improve the situation. Thanks again,

    Best regards,

    Klaus!

  2. Klaus Iglberger

    Hi Misha!

    To keep you posted on the progress of this issue: The next push will contain two solutions for this problem. The first solution is an improvement of the alias detection within views. Thus the submatrix assignment in your example code will no longer create an intermediate temporary. The second solution will be a noalias() function similar to Eigen. The major difference will be that it is applied to the right-hand side expression:

    using namespace blaze;
    
    StaticMatrix<double, 5, 5, columnMajor> A;
    randomize(A);
    
    size_t const n = rows(A);
    size_t const k = 1;
    size_t const rs = n - k - 1;
    
    auto A21 = submatrix(A, k + 1, k, rs, 1);
    auto const A10 = submatrix(A, k, 0, 1, k);
    auto const A20 = submatrix(A, k + 1, 0, rs, k);
    
    A21 -= noalias( A20 * ctrans(A10) );
    

    The additional benefit will be that there will be no runtime evaluation for alias effects at all, which will result in slightly improved performance.

    Best regards,

    Klaus!

  3. Klaus Iglberger

    Summary

    The feature has been implemented, tested, optimized, and documented as required. It is immediately available via cloning the Blaze repository and will be officially released in Blaze 3.7.

    noalias()

    The Blaze library is able to reliably detect aliasing during the assignment of vectors and matrices. In case the aliasing would lead to an incorrect result, Blaze introduces an intermediate temporary of the appropriate type to break the aliasing. For instance, in the following example Blaze performs an alias detection in both assignments, but only, in the second assignment it detects a problematic aliasing and uses an intermediate temporary in order to be able to compute the correct result:

    blaze::DynamicMatrix<double> A, B;
    
    A = A + B;  // No problematic aliasing of A, no intermediate temporary is required.
    A = A * B;  // Problematic aliasing of A; intermediate temporary required!
    

    The detection of aliasing effects, however, takes a small runtime effort. In order to disable the aliasing detection, the noalias() function can be used:

    blaze::DynamicMatrix<double> A, B;
    
    A = noalias( A + B );  // No alias detection performed, no intermediate temporary.
    A = noalias( A * B );  // No alias detection performed, no intermediate temporary.
                           // Note that the final result will be incorrect!
    

    Warning: The noalias() operation has the semantics of a cast: The caller is completely responsible and the system trusts the given information. Using noalias() in a situation where an aliasing effect occurs leads to undefined behavior (which can be violated invariants or wrong computation results)!

  4. Log in to comment