Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: seeing uninitialized memory in ufuncs #25953

Open
CeadeS opened this issue Mar 7, 2024 · 3 comments
Open

BUG: seeing uninitialized memory in ufuncs #25953

CeadeS opened this issue Mar 7, 2024 · 3 comments
Labels
33 - Question Question about NumPy usage or development

Comments

@CeadeS
Copy link

CeadeS commented Mar 7, 2024

Describe the issue:

I do not know what happens, but I see different behavior when I repeat the same operation. I don't know exactly if this is a bug, but if it is, it could be serious because the behavior is undefined for very basic functionality in my eyes. Please close this if I am just wrong or if my usage is wrong. In this case, an assertion could solve my issue.

Reproduce the code example:

#https://www.python.org/
#Python 3.10.5 (main, Jul 22 2022, 17:09:35) [GCC 9.4.0] on linux
#Type "help", "copyright", "credits" or "license" for more information.
import numpy as np
a = np.array([0.,0.,0.])
b = np.divide(a,a.max(), where=~np.all(np.equal(a, 0.)))

print(b)
#[6.9424691e-310 6.9424691e-310 6.9424600e-310]
print(b>0)
#[ True  True  True]
print(b)
#[6.9424691e-310 6.9424691e-310 6.9424600e-310]

a = np.array([0.,0.,0.])
b = np.divide(a,a.max(), where=~np.all(np.equal(a, 0.)))

print(b)
#[0. 0. 0.]
print(b>0)
#[False False False]
print(b)
#[0. 0. 0.]

np.__version__
'1.21.6'

import sys, numpy; print(numpy.__version__); print(sys.version)
1.21.6
3.10.5 (main, Jul 22 2022, 17:09:35) [GCC 9.4.0]

Error message:

Lines 12 and 22 yield different results for the exact same operation.

Python and NumPy Versions:

1.21.6
3.10.5 (main, Jul 22 2022, 17:09:35) [GCC 9.4.0]

Runtime Environment:

I used the www.phython.org online python 3.10 interpreter for verification.

Context for the issue:

I found undefined behavior in a larger project and it took me a week to trace the bug because, in my case, this is a very basic functionality. I faced the wrong results in testing a functionality unrelated to this behavior; I accidentally created that case and had no idea that such behavior could possibly occur.

@CeadeS CeadeS added the 00 - Bug label Mar 7, 2024
@mattip mattip changed the title BUG: <Please write a comprehensive title after the 'BUG: ' prefix> BUG: seeing uninitialized memory in ufuncs Mar 7, 2024
@seberg seberg added 33 - Question Question about NumPy usage or development and removed 00 - Bug labels Mar 7, 2024
@mattip
Copy link
Member

mattip commented Mar 7, 2024

Where is tricky: it does not touch memory where the condition is falsy. So you are seeing uninitialized memory. See the documentation of the where argument.

This comes up often enough that maybe we should add a warning if where is used and out is None. If we do that, what type of warning should it be?

@CeadeS
Copy link
Author

CeadeS commented Mar 7, 2024

I appreciate this clarification, and I understand the underlying problem you laid out. However, it is unclear why the memory is initialized in the second run.

import numpy as np

a = np.array([0.,0.,0.])

b = np.divide(a,a.max(), out=np.array([6.,3.,1.]), where=~np.all(np.equal(a, 0.)))

print(b)
>>> [6. 3. 1.]

a = np.array([0.,0.,0.])
b = np.divide(a,a.max(), where=~np.all(np.equal(a, 0.)))

print(b)
>>> [0. 0. 0.]

The behavior still differs between runs. Seemingly, one time, it is initialized with whatever is in the memory, and the second time, it zeros. After my initial question, I thought it was the same memory, but after this example, it seemingly zeros. However, using "out" with correctly initialized outputs solved my issue. But I don't know if this behavior is intended. A warning should remind the user once to initialize the output efficiently.

Thank you best regards

@bobasaurus
Copy link

I just ran into this same issue, it was maddening. I narrowed it down to two cases:

Unusual Behavior Example

The first and last elements of the resulting "c" array are unitialized memory and will just contain whatever values happen to be in RAM at the moment:

import numpy as np

a = np.array([0,1,0])
b = np.array([1,1,1])

addCondition = np.where(a != 0, True, False)
c = np.add(a, b, where=addCondition)

Fixed Example

If I initialize the array first, I get what I expected (when the condition is False, just use the element from the first array instead of adding both):

import numpy as np

a = np.array([0,1,0])
b = np.array([1,1,1])

addCondition = np.where(a != 0, True, False)
c = np.array(a)
np.add(a, b, out=c, where=addCondition)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
33 - Question Question about NumPy usage or development
Projects
None yet
Development

No branches or pull requests

4 participants