[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.