arrayfire / arrayfire

ArrayFire: a general purpose GPU library.

Home Page:https://arrayfire.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[BUG] Index out of range when performing min on all nan array

dmittiga opened this issue · comments

When using the min call on an array full of NaNs, the index entry is populated with a seemingly random value, not always in the range of the array.

Description

The documentation for min here https://arrayfire.org/docs/group__reduce__func__min.htm#ga04e9dbdf3a13496f57f20d34293ac287 says that NaNs are ignored. However, it does not describe the result when the input is all NaNs. What I have observed is that the value is set to positive infinity but I see no discernible pattern in the resulting index. In some cases, it is outside the range of the input and in others, it is not.

What is the expected behavior for all NaNs? Can I rely on value being infinite?

Reproducible Code and/or Steps

As an example, when I run the below code:

float data[] = {0,  1,  2,  3,
                4,  5,  6,  7,
                8,  9, 10, 11,
                12, 13, 14, 15};
af::array A(4, 4, data);
af::array idx;
af::array val;

A(4)=af::NaN;
af::min(val, idx, A);
af::print("just one nan",A);
af::print("index",idx);
af::print("value",val);

A(af::span,af::span)=af::NaN;
af::min(val, idx, A);
af::print("this should be all NANs",A);
af::print("index",idx);
af::print("value",val);

I see the following output:

just one nan
[4 4 1 1]
    0.0000        nan     8.0000    12.0000
    1.0000     5.0000     9.0000    13.0000
    2.0000     6.0000    10.0000    14.0000
    3.0000     7.0000    11.0000    15.0000

index
[1 4 1 1]
         0          1          0          0
value
[1 4 1 1]
    0.0000     5.0000     8.0000    12.0000
this should be all NANs
[4 4 1 1]
       nan        nan        nan        nan
       nan        nan        nan        nan
       nan        nan        nan        nan
       nan        nan        nan        nan

index
[1 4 1 1]
        31         31         31         31
value
[1 4 1 1]
       inf        inf        inf        inf

System Information

ArrayFire v3.8.2 (CUDA, 64-bit Linux, build 5752f2d)
Platform: CUDA Runtime 11.2, Driver: 460.32.03
[0] Quadro P5000, 16277 MB, CUDA Compute 6.1

We talked about this. The current behavior is based on the shape and launch configuration. For the configuration above the index value is probably going to be a multiple of 31. I am not sure what is going to be the correct answer here because we don't have an invalid value for the index value since it is unsigned and all values in that range are going to be valid.

If you can suggest a better solution then please let me know and we can reopen the issue. For now I am going to mark it as wont fix and close the issue.

Thanks umar. The second question I asked in my post is "can we rely on value being infinite?". Can you shed light on that? I appreciate that what gets output for "index" is tricky, but in cases of all NaN, will the resulting value of +/- INF for min/max respectively be consistently output?

As for the index, I would suggest outputting 0 so that it is always within range of the data. That way, you can call min/max and use the outputs directly without needing to check them.

I think it should be fine to rely on the values being infinite.
Internally, we initialize all reduction values to common::Binary<T, op>::init() for example here:
cuda kernel
and cuda minmax_op, will handle NaN by resetting to ::init()
I don't see this ever changing and the different backends will be consistent.

0s for the output wouldn't be quite right imho. There is no "maximum/minimum" location if all the inputs are invalid. I think the check for af::all(is_nan(inputs)) is somewhat unavoidable.