Incorrect behavior of element type detection during blaze::map'ping of matrix with StaticVector as elements

Issue #344 resolved
Olzhas Zhumabek created an issue

Case explanation

As the title says, it seems like blaze::map doesn’t correctly infer the element type of blaze::DynamicMatrix<blaze::StaticVector<double, 8>>, for example. It seems like it tries to match both double and StaticVector, and then chooses the right one at the end if the insides of the lambda compile for both types, otherwise it just fails to compile saying that there is no conversion from double to static vector.

Here is the full code to reproduce (attached as a file too):

#include <blaze/Blaze.h>
#include <type_traits>

template <typename T>
struct identify_type;

int main() {
    // auto mat = blaze::generate(10, 10, [](std::size_t, std::size_t) {
    //     return blaze::StaticVector<double, 8>{1, 1, 1, 1, 1, 1, 1};
    // });
    blaze::DynamicMatrix<blaze::StaticVector<double, 8>> mat(10, 10, blaze::StaticVector<double, 8>{1, 1, 1, 1, 1, 1, 1, 1});
    double counter = 0;
    auto mapped = blaze::map(mat, [&counter](auto element) {
        ++counter;
        // return element * counter;
        return blaze::StaticVector<double, 8>{
            element[0] * counter,
            element[1] * counter,
            element[2] * counter,
            element[3] * counter,
            element[4] * counter,
            element[5] * counter,
            element[6] * counter,
            element[7] * counter
        };
    });
    return mapped(0, 0)[0];
}

Notice that if you’ll write just return element * counter it will work fine (the correct type is deduced, e.g. vector type), but if you’ll try to apply any operation for which double wouldn’t work, it will fail to compile.

There is also a problem when the autoed output of blaze::generate is used in blaze::map, it says that it cannot find OppositeType inside of the returned expression type.

The example above is just stub code, in reality I’m trying to do anisotropic diffusion, the last 4 elements need to be halved.

Environment

OS: Ubuntu 18.04.4 LTS

compilers:

g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0

g++-10 (Ubuntu 10-20200405-0ubuntu1~18.04) 10.0.1 20200405 (experimental) [master revision 0be9efad938:fcb98e4978a:705510a708d3642c9c962beb663c476167e4e8a4]

Blaze config: 64 bit BLAS, Intel MKL as BLAS library

Question

Am I doing something wrong? Is this expected behavior? If not, is there anything I can do to fix it?

Please let me know if you need more information.

Best regards,

Olzhas

Comments (7)

  1. Klaus Iglberger

    Hi Olzhas!

    Thanks a lot for pointing out this defect. You are correct, the result type deduction for the map() operations does not work as expected in your example. We apologize for the inconvenience and the lost time and promise to resolve the issue as quickly as possible. Till then, please add the following code snippet to your code. It will resolve the compilation issue for the given problem, independent of the operation you are trying to perform inside the lambda:

    namespace blaze {
    
    template< typename OP >
    struct MapTrait< DynamicMatrix<StaticVector<double,8>>, OP >
    {
       using Type = DynamicMatrix<StaticVector<double,8>>;
    };
    
    } // namespace blaze
    

    Best regards,

    Klaus!

  2. Olzhas Zhumabek reporter

    Thanks for such a quick response! And for building such a great library!

    I slapped std::invoke_result_t on your solution for some more flexibility.

  3. Klaus Iglberger

    Commits ef28b3b and 4be412f fix the compilation issue of all map() functions for vectors and matrices with vector or matrix element types. The fix is immediately available via cloning the Blaze repository and will be officially released in Blaze 3.8.

  4. Log in to comment