-
Notifications
You must be signed in to change notification settings - Fork 262
BF: stride_tricks produces unbroadcastable array #358
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
Conversation
@@ -609,7 +609,7 @@ def __getitem__(self, slicer): | |||
'F') | |||
# Broadcast scaling to shape of original data | |||
slopes, inters = self._slice_scaling | |||
fake_data = strided_scalar(self._shape) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah - no - that was deliberate to save memory - what is the error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I figured that was the case. The error is here: https://travis-ci.org/nipy/nibabel/jobs/85392218#L977
Seems to be an immutability issue, but hard to diagnose, so this PR was me trying to use Travis to figure out if my guess was right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ouch. I guess that's numpy 1.10.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah. Does it make sense to try to find another low-memory option, here, or is this something that needs to be addressed in numpy? And in the meantime, should we skip this test on numpy >= 1.10
, use np.zeros
, or put up with failing builds?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you just need to create a new array, as self._shape
is probably read-only. Perhaps
fake_data = strided_scalar(self._shape.copy())
will work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just tried. self._shape
is a tuple, so that doesn't work. (Failed to try the right tests, locally. Want test_proxy_api
, if you're playing along at home.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This works:
_, slopes, inters = np.broadcast_arrays(fake_data.copy(), slopes.copy(), inters.copy())
Just gotta narrow down from there.
On Wed, Oct 14, 2015 at 7:30 PM, Chris Markiewicz [email protected]
wrote:
In nibabel/parrec.py
#358 (comment):@@ -609,7 +609,7 @@ def getitem(self, slicer):
'F')
# Broadcast scaling to shape of original data
slopes, inters = self._slice_scaling
fake_data = strided_scalar(self._shape)
Just tried. self._shape is a tuple, so that doesn't work. (Failed to try
the right tests, locally. Want test_proxy_api, if you're playing along at
home.)—
Reply to this email directly or view it on GitHub
https://github.com/nipy/nibabel/pull/358/files#r42077733.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, but that creates a writeable array. Unsetting the writeable flag was the needed trick.
Of course Travis would pick now to start failing to even get to the tests... Anyway, what we're looking at is this line which seems like it can be skipped by setting the Edit: Okay, one of the previously failing checks passed, so it looks like we can move on this. |
The remaining AppVeyor error is completely different, though possibly numpy 1.10 related. Seems to be 32-bit Windows specific, and out of scope. If the Travis builds succeed, I plan to just ignore that failure for Ben's PRs. |
@@ -610,6 +610,7 @@ def __getitem__(self, slicer): | |||
# Broadcast scaling to shape of original data | |||
slopes, inters = self._slice_scaling | |||
fake_data = strided_scalar(self._shape) | |||
fake_data.flags.writeable = False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about
# Create broadcast array using writeable memory for numpy 1.10
fake_data = strided_scalar(np.array(self._shape))
? Only because the writeable line looks a bit frightening.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can try, but I really don't think the mutability of the shape tuple is relevant.
On October 15, 2015 12:35:57 AM EDT, Matthew Brett [email protected] wrote:
@@ -610,6 +610,7 @@ def getitem(self, slicer):
# Broadcast scaling to shape of original data
slopes, inters = self._slice_scaling
fake_data = strided_scalar(self._shape)
fake_data.flags.writeable = False
How about
# Create broadcast array using writeable memory for numpy 1.10 fake_data = strided_scalar(np.array(self._shape))
? Only because the writeable line looks a bit frightening.
Reply to this email directly or view it on GitHub:
https://github.com/nipy/nibabel/pull/358/files#r42082838
Chris Markiewicz
Tried a few strategies to create writeable arrays, and none of those work in 1.10. (See below for why I think that is.TLDR: It's not that fake_data is unwriteable but that when broadcast it creates an unwriteable array.) Now trying to make the shape tuple writeable, but since it's immediately cast to tuple, I don't anticipate improvement. I think I have misstated the problem, so let me try my new understanding:
It may be worthwhile to submit a PR, and we can use this as a test case, but I don't see anything on the |
@matthew-brett Just a ping, since I want to get this in before moving on Ben's PRs. Since I don't see much alternative, the current version just follows my above reasoning and modifies Left commits so you can see the changes and their effects on tests. Will squash to a single commit if you give the go-ahead. |
@@ -639,8 +639,10 @@ def test_strided_scalar(): | |||
assert_equal(observed.shape, shape) | |||
assert_equal(observed.dtype, expected.dtype) | |||
assert_array_equal(observed.strides, 0) | |||
observed[..., 0] = 99 | |||
assert_array_equal(observed, expected * 0 + 99) | |||
def setval(x): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add comment explaining reason for test?
I think you're right, setting the flag is the only way. I put in a numpy bug report : numpy/numpy#6491 |
Added a comment, one more test, and squashed to a single commit. |
# Strided scalars are set as not writeable | ||
# This addresses a numpy 1.10 breakage of broadcasting a strided | ||
# array without resizing (see GitHub PR #358) | ||
assert_false(x.flags.writeable) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@effigies this line is causing a test failure; x
is not defined. Perhaps this should be inside setval
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Woops. s/x/observed/
Fixed that new test and Travis is passing. |
@@ -767,9 +767,12 @@ def strided_scalar(shape, scalar=0.): | |||
strided_arr : array | |||
Array of shape `shape` for which all values == `scalar`, built by | |||
setting all strides of `strided_arr` to 0, so the scalar is broadcast | |||
out to the full array `shape`. | |||
out to the full array `shape`. `strided_arr` is flagged as not | |||
`writeable`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still feel that we need a comment here - otherwise it's not obvious why this is true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What kind of comment are you thinking? Noting the numpy bug (with some level of detail, or reference to this PR) or the reasoning that setting one element of the array would set all (and thus is probably not the intended behavior)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just something like We set the array read-only to avoid a numpy error when broadcasting - see https://github.com/numpy/numpy/issues/6491
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
Numpy 1.10 cannot broadcast a strided array that is set as writeable
Thanks for your patience. |
MRG: stride_tricks produces unbroadcastable array A probable bug in numpy 1.10.1 causes an error when trying to broadcast an array constructed using stride tricks. See : numpy/numpy#6491 for a full description. To work round, set the stride_tricks array as read-only, so that numpy does not try and set the output to writeable - that is the step that appears to cause the error.
Thanks! |
MRG: stride_tricks produces unbroadcastable array A probable bug in numpy 1.10.1 causes an error when trying to broadcast an array constructed using stride tricks. See : numpy/numpy#6491 for a full description. To work round, set the stride_tricks array as read-only, so that numpy does not try and set the output to writeable - that is the step that appears to cause the error.
Hopefully this will fix the Travis errors.