Invariant Violation when mapping blaze::Div

Issue #226 resolved
Maximilian Bremer created an issue

Hi Klaus,

I've been running into some issues with the following example:

#include <blaze/Math.h>                                                                                                                                                                                                                       

int main() {                                                                                                                                                                                                                                  

    using namespace blaze;                                                                                                                                                                                                                    

    DynamicMatrix<double> A(3,3), B(3,3);                                                                                                                                                                                                     

    A = 4;                                                                                                                                                                                                                                    
    B = 1;                                                                                                                                                                                                                                    

    DynamicMatrix<double> C = map( A, B, Div{} );                                                                                                                                                                                             

    return 0;                                                                                                                                                                                                                                 
}

When running with BLAZE_INTERNAL_ASSERTION set to 1, the following assertion fails

blaze::DynamicMatrix< <template-parameter-1-1>, <anonymous> >::DynamicMatrix(const blaze::Matrix<MT, SO>&) [with MT = blaze::DMatDMatMapExpr<blaze::DynamicMatrix<double>, blaze::DynamicMatrix<double>, blaze::Div, false>; bool SO2 = false; Type = double; bool SO = false]: Assertion `( isIntact() ) || blaze::ASSERT_MESSAGE( "Invariant violation detected" )' failed.

Stepping through the code, my understanding is that the padded part of the matrix is having the division applied to causing the padded regions of the matrix to become nan's.

Best,

Max

Comments (6)

  1. Klaus Iglberger

    Hi Maximilian!

    Thanks a lot for reporting this defect. Your analysis is correct, in this particular case the hidden padding elements cause nans, which in debug mode result in an assertion.

    Since there are several possible fixes, ranging from completely disabling padding for map() operations (which would be a significant hit on performance for small matrices) to only fixing this particular case (which would not generally resolve the issue), we need some time to evaluate our options. However, there is a quick and simple fix that you can use until we push a fix. Please copy and paste the following code snippet directly after including the Blaze include files to temporarily resolve the issue:

    namespace blaze {
    
    template< typename MT1, typename MT2, bool SO >
    struct IsPadded< DMatDMatMapExpr<MT1,MT2,Div,SO> >
       : public FalseType
    {};
    
    } // namespace blaze
    

    We are sorry for the inconvenience. Thanks again for reporting the issue,

    Best regards,

    Klaus!

  2. Klaus Iglberger

    Summary

    Commits 553f5e1 and ac51877 resolve the runtime issue of binary, custom matrix operations with padding elements. The fix is immediately available via cloning the Blaze repository and will be officially released in Blaze 3.5.

    Details

    With commit ac51877 binary custom matrix operations are by default not using padding elements anymore, but instead use peel-off and remainder loops to deal with a number of elements that is not a multiple of the width of the packed SIMD type. However, for custom operations that can properly deals with padding elements (i.e. zero elements) it is possible to explicitly enable the use of padding elements to achieve maximum performance by providing the paddingEnabled() function with the custom operation. The following example demonstrates this by means of the Sqrt functor:

    namespace blaze {
    
    struct Sqrt
    {
       template< typename T >
       BLAZE_ALWAYS_INLINE auto operator()( const T& a ) const
       {
          return sqrt( a );
       }
    
       template< typename T >
       static constexpr bool simdEnabled() { return HasSIMDSqrt<T>::value; }
    
       static constexpr bool paddingEnabled() { return true; }
    
       template< typename T >
       BLAZE_ALWAYS_INLINE auto load( const T& a ) const
       {
          BLAZE_CONSTRAINT_MUST_BE_SIMD_PACK( T );
          return sqrt( a );
       }
    };
    
    } // namespace blaze
    

    The paddingEnabled() function must be a static, constexpr function and must return whether padding elements can be used in the custom operation. In case the function returns true, the padding elements are used during a vectorized operation, in case the function returns false, the padding elements are not used. In case no paddingEnabled() function is provided, false is assumed and no padding elements are used.

  3. Log in to comment