You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
BUG: Array copy does not zero out gaps in structured dtypes #10789
One would expect that array_of_metadata and other_array_of_metadata should be the same thing.
They are not. I submit that the line creating array_of_metadata is buggy. I believe this produced the same as the lines that produce other_array_of_metadata in previous versions.
But that wasn't even the primary bug I was going to talk about. I discovered that one while hunting down this one.
Take our other_array_of_metadata:
Let's make a new array from a subset of this array (not just a view)
You will see that our sub_array now has strange things in the spaces that were not exposed by our dtype. Not the nice aranges we had constructed before. In 1.11, this code would have preserved the data that was not exposed. Now it appears that the unexposed portions of sub-array are never initialized to anything. This matters because sometimes we want to only expose a part of our metadata to our code, but when we write the metadata back out to disk, want all of it preserved.
I can understand making a design choice to not initialize the unexposed portions of a dtype when constructing new elements from literals or from scratch. But when you already have an element of this dtype, ignoring the empty space seems like an inferior choice.
I think this is the same as #10752, see the discussion there. We want to drop support of np.array(arange(10)) behaving like a view when using structured dtypes, since it has led to other bugs. It should behave like astype, like in other cases.
Since change this seems to break multiple people's code though, so maybe we should consider supporting this "view-like" behavior a little longer, but I really think we should remove it eventually. Let me investigate if we can support np.array(arange(10)) style creation, with a deprecation warning, for 1.14.3.
When you do array_of_metadata = np.array(list_of_arrays, dtype=my_metadata_dtype), in 1.14 we want to make this behave as if .astype(dtype) was called on every element of the input arrays. This is how most of numpy behaves, for instance np.array([np.arange(2), np.arange(2)], dtype='f8') casts all the int values to create a 2d float64 array with values 0. and 1.. In 1.13, structured types were the exception and reinterpreted the memeory, due to what can pretty fairly be called a bug, see this list of bugs in the issue linked in my last comment.
On the other hand when you do other_array_of_metadata.dtype = my_metadata_dtype, that is equivalent to other_array_of_metadata.view(my_metadata_dtype). In numpy views reinterpret the underlying memory with a new dtype (ie, it does not cast), in contrast to .astype, which casts.
In your second example with sub_array you are effectively usign astype in the first line, and then using a view in the second line.
So I think you examples are what I, at least, think the future behavior should be. However, I am unhappy that we (I) caused people's code to break without warning.
I think I understand your logic for the decision that was made, however I would argue that the current behavior now is for np.array() to behave like assignment into an array rather than like a copy to an array.
Perhaps a better solution is to move this view-like copying to a new function. Currently I am getting around this new behavior to get view-like-copying with the following.
Wait a second.. am I confusing something? I just tried your code in 1.11.0 (and 1.11.1) and I get the same behavior as in 1.14.2. Here's a trimmed version of your example:
Unfortunately I do not have an easy way of reverting back to 1.11.0, so I can't verify, but, for that part of the code (my first example), I was going on what I thought was the behavior back then...perhaps I was wrong. Sorry.
It was the second example that broke my actual code, and trying to determine what the new behavior was led me to the first example which I apparently erroneously thought was changed.
There was old code that broke. I can get (and really already have) onboard with dropping the support for view-like behavior with structured arrays by using the array_copy() method I posted above in place of array().
A better solution might be to make .copy() behave like array_copy(), so that voids in a structured dtype are copied byte for byte into the new array rather than left uninitialized.
You will note that b looks substantially different than a or c because the voids in the dtype are left uninitialized. This is really the issue that broke my old code. Previously I had just used array() in place of copy, and that had worked for me in the past. I fixed the broken old code with array_copy() and moved on. But I think it might be a good idea to make .copy() behave this way too. I can understand why using array() was not a great idea though.
I changed the title to reflect the remaining issue: when using np.copy, gaps in the data due to offsets are not set to 0. I think this fits in with the general behavior of numpy. See for instance the warnings around the use of numpy.where.
Perhaps an addition to the documentation of np.copy could make this clearer
I am closing this, as per Matti's last comment, this is probably the desired behaviour, and it is the behaviour now for many years so there is no point in thinking about a regression. Happy if open new issues about this or related problems though (or reopen this one)!
Activity
ahaldane commentedon Mar 23, 2018
I think this is the same as #10752, see the discussion there. We want to drop support of
np.array(arange(10))behaving like a view when using structured dtypes, since it has led to other bugs. It should behave likeastype, like in other cases.Since change this seems to break multiple people's code though, so maybe we should consider supporting this "view-like" behavior a little longer, but I really think we should remove it eventually. Let me investigate if we can support
np.array(arange(10))style creation, with a deprecation warning, for 1.14.3.ahaldane commentedon Mar 23, 2018
Also, just to explain our thinking :
When you do
array_of_metadata = np.array(list_of_arrays, dtype=my_metadata_dtype), in 1.14 we want to make this behave as if.astype(dtype)was called on every element of the input arrays. This is how most of numpy behaves, for instancenp.array([np.arange(2), np.arange(2)], dtype='f8')casts all theintvalues to create a 2dfloat64array with values0.and1.. In 1.13, structured types were the exception and reinterpreted the memeory, due to what can pretty fairly be called a bug, see this list of bugs in the issue linked in my last comment.On the other hand when you do
other_array_of_metadata.dtype = my_metadata_dtype, that is equivalent toother_array_of_metadata.view(my_metadata_dtype). In numpy views reinterpret the underlying memory with a new dtype (ie, it does not cast), in contrast to.astype, which casts.In your second example with
sub_arrayyou are effectively usignastypein the first line, and then using a view in the second line.So I think you examples are what I, at least, think the future behavior should be. However, I am unhappy that we (I) caused people's code to break without warning.
ikehall commentedon Mar 23, 2018
I think I understand your logic for the decision that was made, however I would argue that the current behavior now is for np.array() to behave like assignment into an array rather than like a copy to an array.
Perhaps a better solution is to move this view-like copying to a new function. Currently I am getting around this new behavior to get view-like-copying with the following.
I'm not the biggest fan of this, but it works.
ahaldane commentedon Mar 23, 2018
Wait a second.. am I confusing something? I just tried your code in 1.11.0 (and 1.11.1) and I get the same behavior as in 1.14.2. Here's a trimmed version of your example:
I get the same output in 1.14.2. What is your output?
ikehall commentedon Mar 23, 2018
Unfortunately I do not have an easy way of reverting back to 1.11.0, so I can't verify, but, for that part of the code (my first example), I was going on what I thought was the behavior back then...perhaps I was wrong. Sorry.
It was the second example that broke my actual code, and trying to determine what the new behavior was led me to the first example which I apparently erroneously thought was changed.
eric-wieser commentedon Mar 23, 2018
I don't understand your
array_copyfunction - it looks like it's just.copy()to meikehall commentedon Mar 23, 2018
The difference is that array_copy is faithful to the voids in my dtype whereas copy ignores them.
Compare those last two arrays. subarray_array_copy still has the underlying arange with which it was created whereas subarray_copy does not.
ikehall commentedon Mar 23, 2018
After some more poking around though, my array_copy does not necessarily respect shape like I would want it to.
Now it is:
mattip commentedon Aug 8, 2018
@ikehall is this still relevant? Could you include a valid code snippet?
mattip commentedon Jan 16, 2019
If I understand correctly there are two issues here:
In both cases, I think the ship has sailed. @ikehall is there anything more we can do here?
ikehall commentedon Jan 18, 2019
There was old code that broke. I can get (and really already have) onboard with dropping the support for view-like behavior with structured arrays by using the array_copy() method I posted above in place of array().
A better solution might be to make .copy() behave like array_copy(), so that voids in a structured dtype are copied byte for byte into the new array rather than left uninitialized.
ex:
You will note that b looks substantially different than a or c because the voids in the dtype are left uninitialized. This is really the issue that broke my old code. Previously I had just used array() in place of copy, and that had worked for me in the past. I fixed the broken old code with array_copy() and moved on. But I think it might be a good idea to make .copy() behave this way too. I can understand why using array() was not a great idea though.
[-]Something broken with structured arrays[/-][+]BUG: Array copy does not zero out gaps in structured dtypes[/+]mattip commentedon Feb 14, 2019
I changed the title to reflect the remaining issue: when using np.copy, gaps in the data due to offsets are not set to
0. I think this fits in with the general behavior of numpy. See for instance the warnings around the use ofnumpy.where.Perhaps an addition to the documentation of
np.copycould make this clearerseberg commentedon Feb 14, 2019
Just to crossref gh-12686 is somewhat related (possibly a duplicate even).
seberg commentedon Oct 4, 2021
I am closing this, as per Matti's last comment, this is probably the desired behaviour, and it is the behaviour now for many years so there is no point in thinking about a regression. Happy if open new issues about this or related problems though (or reopen this one)!