![]() |
In addition to the provided operations on vectors and matrices it is possible to define custom operations. For this purpose, Blaze provides the forEach()
function, which allows to pass the required operation via functor or lambda:
This example demonstrates the most convenient way of defining a custom operation by passing a lambda to the forEach()
function. The lambda is executed on each single element of a dense vector or matrix or each non-zero element of a sparse vector or matrix.
Alternatively, it is possible to pass a custom functor:
In order for the functor to work in a call to forEach()
it must define a function call operator, which accepts arguments of the type of the according vector or matrix elements.
Although the operation is automatically parallelized depending on the size of the vector or matrix, no automatic vectorization is possible. In order to enable vectorization, a load()
function can be added to the functor, which handles the vectorized computation. Depending on the data type this function is passed one of the following Blaze SIMD data types:
blaze::SIMDint8:
Packed SIMD type for 8-bit signed integral data types blaze::SIMDuint8:
Packed SIMD type for 8-bit unsigned integral data types blaze::SIMDint16:
Packed SIMD type for 16-bit signed integral data types blaze::SIMDuint16:
Packed SIMD type for 16-bit unsigned integral data types blaze::SIMDint32:
Packed SIMD type for 32-bit signed integral data types blaze::SIMDuint32:
Packed SIMD type for 32-bit unsigned integral data types blaze::SIMDint64:
Packed SIMD type for 64-bit signed integral data types blaze::SIMDuint64:
Packed SIMD type for 64-bit unsigned integral data types blaze::SIMDfloat:
Packed SIMD type for single precision floating point data blaze::SIMDdouble:
Packed SIMD type for double precision floating point data blaze::cint8:
Packed SIMD type for complex 8-bit signed integral data types blaze::cuint8:
Packed SIMD type for complex 8-bit unsigned integral data types blaze::cint16:
Packed SIMD type for complex 16-bit signed integral data types blaze::cuint16:
Packed SIMD type for complex 16-bit unsigned integral data types blaze::cint32:
Packed SIMD type for complex 32-bit signed integral data types blaze::cuint32:
Packed SIMD type for complex 32-bit unsigned integral data types blaze::cint64:
Packed SIMD type for complex 64-bit signed integral data types blaze::cuint64:
Packed SIMD type for complex 64-bit unsigned integral data types blaze::cfloat:
Packed SIMD type for complex single precision floating point data blaze::cdouble:
Packed SIMD type for complex double precision floating point data All SIMD types provide the value
data member for a direct access to the underlying intrinsic data element. In the following example, this intrinsic element is passed to the AVX function _mm256_sqrt_pd()
:
In this example, whenever vectorization is generally applicable, the load()
function is called instead of the function call operator for as long as the number of remaining elements is larger-or-equal to the width of the packed SIMD type. In all other cases (which also includes peel-off and remainder loops) the scalar operation is used.
Please note that this example has two drawbacks: First, it will only compile in case the intrinsic _mm256_sqrt_pd()
function is available (i.e. when AVX is active). Second, the availability of AVX is not taken into account. The first drawback can be alleviated by making the load()
function a function template. The second drawback can be dealt with by adding a simdEnabled()
function template to the functor:
The simdEnabled()
function must be a static
, constexpr
function and must return whether or not vectorization is available for the given data type T
. In case the function returns true
, the load()
function is used for a vectorized evaluation, in case the function returns false
, load()
is not called.
Note that this is a simplified example that is only working when used for dense vectors and matrices with double precision floating point elements. The following code shows the complete implementation of the according functor that is used within the Blaze library. The Blaze Sqrt
functor is working for all data types that are providing a square root operation:
For more information on the available Blaze SIMD data types and functions, please see the SIMD module in the complete Blaze documentation.
Previous: Matrix/Matrix Multiplication Next: Shared Memory Parallelization