
O.K. here is my X.flat solution.
I've decided to make use of the fancy-new, numarray-inspired idea of the UPDATEIFCOPY flag for array creation. Basically, X.flat will create a new array if X is discontiguous but with the UPDATEIFCOPY flag set so that upon destruction the contents will get copied back to X.
So, it will seem like the X.flat array is updating the original array (provided it get's dereferenced someday (which it should because you rarely) keep references to X.flat unless you really meant ravel(X).
This is the simplest solution. It's not quite as fancy as the indexable iterator (which could still be implemented at some point) but it lets me move forward.
-Travis

On Fri, 18 Feb 2005, Travis Oliphant wrote:
O.K. here is my X.flat solution.
I've decided to make use of the fancy-new, numarray-inspired idea of the UPDATEIFCOPY flag for array creation. Basically, X.flat will create a new array if X is discontiguous but with the UPDATEIFCOPY flag set so that upon destruction the contents will get copied back to X.
So, it will seem like the X.flat array is updating the original array (provided it get's dereferenced someday (which it should because you rarely) keep references to X.flat unless you really meant ravel(X).
This is the simplest solution. It's not quite as fancy as the indexable iterator (which could still be implemented at some point) but it lets me move forward.
Hmm. It seems to me that if it is not a live view you can run into serious problems. What happens if you do this:
a = zeros((10,10)) b = a[::2,::2].flat b[4] = 1 a[0,8] = 2 del b
Doesn't your behavior lead to a[0,8] being overwritten to 1 by the copy back from b?

Hmm. It seems to me that if it is not a live view you can run into serious problems. What happens if you do this:
a = zeros((10,10)) b = a[::2,::2].flat b[4] = 1 a[0,8] = 2 del b
Doesn't your behavior lead to a[0,8] being overwritten to 1 by the copy back from b?
Well in this particular case since a is contiguous to begin with, b is not a copy so the copy-back would not occur.
But, you bring up a valid point that if "a" were discontiguous which forced a copy, then any later modifications to "a" would be ignored. Now, this could be fixed by making "a" read-only for the duration of existence of the flattened reference.
In fact, it probably stands to reason that whenever, UPDATEIFCOPY is used on the C-level, the to-be-copied-to array is flagged readonly for the duration of existence of the "reference."
Besides that point, to clarify what we are talking about here:
1) The PEP has been modified so that X[K] is interpreted as X[K,] for integer arrays, and the previously-discussed distinction disappears.
2) It is desired that X.flat[K] provide the flattened behavior. How should this be done?
a) having X.flat return an indexable iterator (with an __array__ method that will automatically return an update-if-copy array on request from asarray() or C-level equivalent)
b) having X.flat return an update-if-copy array (with X flagged as readonly while a reference to X.flat exists)
c) it shouldn't be done and X.flat should just raise an error if X is not contiguous.
Please chime in and "vote" for one of the three solutions (or another one not covered) for 2 if you haven't already expressed your view.
By the way, I think it's been settled that X.flat will not behave the same as ravel(X) (which should probably be a method---X.ravel() ).
-Travis

Travis Oliphant oliphant@ee.byu.edu writes:
Hmm. It seems to me that if it is not a live view you can run into serious problems. What happens if you do this:
a = zeros((10,10)) b = a[::2,::2].flat b[4] = 1 a[0,8] = 2 del b
Doesn't your behavior lead to a[0,8] being overwritten to 1 by the copy back from b?
Well in this particular case since a is contiguous to begin with, b is not a copy so the copy-back would not occur.
But, you bring up a valid point that if "a" were discontiguous which forced a copy, then any later modifications to "a" would be ignored. Now, this could be fixed by making "a" read-only for the duration of existence of the flattened reference.
In fact, it probably stands to reason that whenever, UPDATEIFCOPY is used on the C-level, the to-be-copied-to array is flagged readonly for the duration of existence of the "reference."
Ugh. I realize I'm going to have to sit down and think on this first, and look at code. My gut feeling is UPDATEIFCOPY and read-write-locks (which is essentially what you're proposing) will make for some odd, hard-to-track down, errors.
Besides that point, to clarify what we are talking about here:
- The PEP has been modified so that X[K] is interpreted as X[K,]
for integer arrays, and the previously-discussed distinction disappears.
- It is desired that X.flat[K] provide the flattened behavior.
How should this be done?
a) having X.flat return an indexable iterator (with an __array__
method that will automatically return an update-if-copy array on request from asarray() or C-level equivalent)
I'm +1. This feels to be the simplest (in sense of use, not necessarily implementation :-), and the obvious use. Here, X.flat is *always* a valid view of X.
b) having X.flat return an update-if-copy array (with X flagged
as readonly while a reference to X.flat exists)
-0, for the locking reasons I mention above. For this usage, I'd make it a method instead.
c) it shouldn't be done and X.flat should just raise an error if
X is not contiguous.
If this one, then I'd say that X.flat is useless and should be removed. ravel() (or X.ravel()) should return a view or copy depending on whether X is contiguous or not. A copy could be forced by a keyword argument: ravel(X, copy=True)
While we're at it, I'd argue that "ravel" is a bad word for this usage -- it's not obvious what it does. "flatten" might be a better word.

David M. Cooke wrote:
In fact, it probably stands to reason that whenever, UPDATEIFCOPY is used on the C-level, the to-be-copied-to array is flagged readonly for the duration of existence of the "reference."
Ugh. I realize I'm going to have to sit down and think on this first, and look at code. My gut feeling is UPDATEIFCOPY and read-write-locks (which is essentially what you're proposing) will make for some odd, hard-to-track down, errors.
The problem is with this idea of UPDATEIFCOPY which is borrowed from numarray and which users over there seem to like. It just seems to me that if an array is going to be "automatically" copied back to another array (this is currently done in numarray), then the array-to-be-copied to needs to be flagged read-only until the copy is complete. Then, an error will be raised whenever the users tries to do something that would cause "hard-to-track-down" bugs (like write to an array that is going to be clobbered by a copy-back).
If the UPDATEIFCOPY is only used for C-extensions where you need to get a nice array from a potentially "bad" one (e.g. contiguous from discontiguous) and the thinking is that you would not be using the original one while you played with the copy. But, if the C-extension calls arbitrary code (as is sometimes done), then this is not guaranteed. So, I think, if you are going to have UPDATEIFCOPY, you need to set the original array readonly until the copy is complete.
b) having X.flat return an update-if-copy array (with X flagged
as readonly while a reference to X.flat exists)
Yeah, I don't like this anymore either.
I like X.flatten() better than X.ravel() too.
-Travis
participants (3)
-
cookedm@physics.mcmaster.ca
-
Rick White
-
Travis Oliphant