-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
drop dimensions indexed with a scalar? #5949
Comments
Looking at this in isolation, it sounds fine to me. However, problems may arise if we consider it in conjunction with broadcasting. Consider this: A .+ A[1,:] At the first glance, I would suppose that the behavior is to add the first row of To extend this little bit, shall we squeezed reduced dimension for reduction operation? What would be the shape of A .- mean(A, dim) |
It would simply become Another perspective on this: currently In my view, it's pretty clear that reductions shouldn't squeeze, but I recognize this is potentially contentious. |
I would be happier with not dropping any dimensions and having slicing always return a tensor of the same rank as the tensor that is being sliced. Are there any downsides to that? Vectors would tend to get turned into column matrices, but that's fine, imo. We could also make |
I think that would be ok; I suspect it's more important to formalize the embedding of N-d tensors in (N+1)-d tensors with a trailing singleton dimension. Then extra dimensions can generally be ignored, rather than explicitly dropped. |
I'm also a big supporter of @timholy's proposal. Since in Julia you can distinguish scalars from vectors and ranges, it sounds natural to allow using this difference to indicate what the shape of the resulting slice should be. |
I have an unorthodox proposal: how about someone who's in favor of this go ahead and implement a Julia array type that has this indexing behavior. It doesn't have to be completely functional – I just think it would help a lot to have a mockup to play with. Then people (like me), who are skeptical of this idea can try it out and see if it's really as odious as it sounds ;-) |
I opened this issue because I'm basically intending to do just that; this is the "shot across the bow" from someone with a dangerous track record 😄 when it comes to reworking much of Julia's array indexing. Like you, I don't actually know how this will work out, and I am kind of curious to know whether I will like it. But my general feeling is that perhaps this should be timed with other disruptions, like switching to views---both will break code, this much more than views. That said, if you really would play with this well in advance of getting serious about merging it, then perhaps one doesn't need to wait. |
I think the issue has served its purpose, and the next step is just to do it. So this can be closed. |
@nalimilan, while I agree with you in that this proposal is logical and adds power---which is why I think it's worth exploring---the part I'm worried about is that it may be so much more common to want not to slice dimensions that I'll get annoyed at writing ranges all the time. Moreover, |
Actually, let me use this to ask one more thing: if I make the core changes to |
Should we go full APL and make the rank of the result the sum of the ranks of the indexes? |
Instead of changing what's in base, can you add a new type? (Maybe that's what you plan.) |
@JeffBezanson, can you point me to a link? I think I understand what you're asking, but not sure. I'd have to think about the implementation, but it sounds doable. @tshort, I don't think it will be an effective experiment if we don't really try it. IF we do try it (and it's by no means too late to convince me otherwise), my plan would be to post a branch and people could play with it. I'm also mulling over whether there's a way to make the transition safely with an appropriate macro or two. It's not obvious there is, but I think it's worth careful consideration. |
I we do make this change, then it only makes sense to go "full APL", imo. |
Can someone provide a link on what APL indexing semantics actually are? |
Also, since there seem to be definite use cases for both dropping and keeping dimensions, how about that we provide both operations? This could even make the transition non-breaking. Or does |
Agree that we may seriously consider adopting the APL rules, which are much more expressive. |
Having looked at the rules briefly, yes, it sounds like a good idea to go all the way if we do this. @toivoh, the new behavior would imitate
What's your idea for making this non-breaking? I currently have what might be an effective, but somewhat complex, plan for migration. The key is to use deprecation on indexing operations whose behavior is changing, but provide users a mechanism for indicating that other indexing operations should follow the new behavior and therefore not be subject to the deprecation behavior:
A bit ugly, but I'm not sure I see a good alternative. |
I'm going to be occupied for the next several weeks with other tasks, and in any event this is 0.4 material. Let me make sure that folks noticed my request for collaboration on this issue, specifically on converting the files in While I am curious to know how this indexing would work out in practice, much of my motivation for being willing to try it is because of the complaints about the current scheme. (I've implemented much of Julia's current array indexing, so I feel a certain amount of responsibility for handling complaints about how it works.) I'm reasonably happy with Julia's current behavior; if none of you are willing to share the pain of this transition, then I know I don't need to feel guilty about anything 😄 and just might find better uses for my time. |
Looks like that should have been CC @lsorber. |
Forgot @malmaud |
@timholy If we agree to change behavior (in whatever way), better to do it along with the array view framework. If we are going to deprecate sub-arrays in favor of array views (with the |
@timholy Full APL sounds good to me. |
So |
As I said, I have no strong opinion on one way or the other. However, I agree with @StefanKarpinski that the argument for dropping all singular dimensions (as opposed to only dropping the trailing dimensions) is not strong enough. Frankly, I still have a hard time understanding why dropping trailing dimensions (without dropping non-trailing singular dimension) is such a big problem. I have never encountered any real problems caused by this behavior even when writing very generic codes. I am not against this proposal. But I believe such a breaking change needs more justification. |
Another option: make @lindahua IMHO dropping trailing dimensions introduces more complexity and I don't think in most cases it makes sense. For example, you may often want to extract a vector from a row as well as from a column of a matrix. |
This is the very claim that's not substantiated. I don't actually find myself wanting to extract rows as pure vectors. Ever, really. If the thing is a row, it's rowness is pretty important. If I need it to act like a column, then I transpose it. The only reason one might need it to really be a vector and not a column matrix is to resize it. But that a radically different use case (stack/queue) and I think it's reasonable to apply the |
There certainly are cases where you want to drop a dimension. Consider a 3d image where you want to take an If folks dislike dropping on scalars, alternatively we could introduce a type,
Or something shorter, of course. Once #3721 gets fixed, I vote we exploit unicode and choose pizza. After all, we are taking slices 😄. |
My gut feeling about that case is that you're doing two steps: you want to select a certain xz plane, and then treat it like an xy plane. It's not obvious to me that one most often wants dimensions permuted into the leading dimensions. |
Depends on what code you want to interact with next---lots of people write image-processing algorithms thinking only of 2d (as a 4d images person, I happen to think this is abominable, but whatever). I'd go so far as to say most code you see online for image processing makes that assumption.
|
...though I should add that if what you're trying to do is confer meaning, naming dimensions is much more robust than trying to do it by position. Just wait until someone feeds you a huge file using a different storage order than you expected. So in a sense maybe |
Now that's a rather interesting idea. I rather like it, but it would be awkward to always have to name your dimensions. However, it might be an interesting angle to think about the problem from. What if 1, 2 and so on are just default dimension names? Then you could have a pure vector whose only dimension is 2. This is a bit like absent dimensions, but seems more sensible. |
@StefanKarpinski I don't deny that. But I don't understand why the "columnness" of columns of a matrix wouldn't be equally important. I guess we have very different use cases. I work with contingency tables all the time, where the choice of putting one variable as rows and one as columns is completely arbitrary. I'd like them to behave the same. The idea of having dimension names so that a vector's only dimension could be named 2 is interesting, but orthogonal to the issue of the special treatment of trailing dimensions. |
From all these discussion (together with my own experience), my take is that when taking a row of a matrix, people may desire a We really need an approach with which people can freely and easily express their intention, instead of forcing one way while leaving a lot of other people unhappy. |
To me it's beginning to sound like the best choice might be (1) to stop dropping trailing dimensions, and (2) implement either (a) |
What about using negative indices to denote dropped dimensions? Would that be a bad idea or just not possible? I haven't really thought it through very much yet since I only just found this thread. A[2:4, -2, 3] So the range behaviour Edit: |
@MichaelHatherly, that would be very confusing for people converting from python. They need a Just to throw out yet another syntax for creating single value ranges, that can work outside of indexing also: colon(x,f::Function) = colon(x,x)
#And now we can use
a[frobozz + 2gazonk:&, 2] We will probably want the implementation to be more specific, but the point is the syntax. |
@lindahua Fully agreed. |
@ivarne, your right. I think Ruby and Mathematica (maybe) also have that style of indexing, so it would be quite confusing. Probably not something prominent documentation would solve either since people would still try anyway. |
That's a clever solution, @ivarne. |
I also think that we should cater to both people/use cases who want to drop dimensions, and who dont. To me, the reason not to drop is that you want to preserve the dimensions that are already present, and then it doesn't make sense to drop some of them. It would seem to me that separate operations would also make code less verbose and error prone than mixing the two in Of course, it could be very nice to go to a setting like named dimensions where dropping a dimensions just never makes sense, but for that case I think that we still need to figure out if matrix algebra could work in a sane way, and if such a scheme would add too much complexity to the basic |
- change float environment of dispatch statistics table from figure to float - move 'symbolic programming' subsection to be second to last ('implications' feels like a more natural ending) - more precise subsection headings - remove comments addressing points already made and rephrased - tighten spacing of "(n-1)-array" - less repetitive phrasing - eliminate most parenthetical comments - hyphenation - cite issue JuliaLang/julia#5949
- footnote comes after punctuation - change tense since issue is closed
This issue was brought to my attention by https://groups.google.com/d/topic/julia-users/aUahMSjJ-o0/discussion My unsolicited opinion: not dropping singleton dimensions is the biggest wart in Julia from my POV. I often take slices from many dimensioned arrays and always choke on the extra syntax/effort required to drop the dimensions. I like the idea of the APL rules - and would be willing to help @timholy fix the tests etc. as a vote of support! |
An example in favor of dropping singleton dimensions comes from solving partial differential equations, where it is common to use multidimensional array to represent function values on Cartesian mesh (of arbitrary dimension). In this context, array slices represent the slices of the Cartesian mesh. Say I would like to take a look at function values on a particular 2d section of a larger 3d mesh. Without dropping the singleton dimensions, dealing with such slice depends on which plane I choose and passing the slice to a function that would perform some operations on it (e.g. plot the slice) requires some kind of wrapping. I posted the example in the mailing list: https://groups.google.com/d/msg/julia-users/aUahMSjJ-o0/kle-wuGJVXgJ In this case, dropping singular dimensions has a well defined geometric interpretation. |
Offers of help are wonderful. In general I think any transition needs to be made in conjunction with a transition to better ArrayViews, which is one of several reasons I haven't made any moves on this front (see below for another). My current opinion, largely based on the earlier discussion, is that the change to dropping dimensions in expressions like
Finally, implementing APL rules will require #6437, and there's little point doing anything until that's resolved. |
Although I read the whole discussion I honestly still fail to see what is wrong with requiring the programmer to explicitly state the intention of getting the 2d array via |
Another syntax suggestion, if issue #2403 gets implemented, then the call operator could be overloaded for Arrays for the slice syntax. Then |
It seems likely that 0.4 will see a transition to array views (#5556). This change will surely break some code, e.g., for anyone who was relying on the behavior of
setindex!
applied to the output ofA[3:15, 7]
. Perhaps we should take the occasion to simultaneously think about another (much worse) breakage.As we've gotten less concerned about breaking Matlab compatibility (and as I've learned more about the wider scientific ecosystem), I've increasingly begun to wonder whether NumPy's slicing rules are the right way to go. It's very simple: if you index along a particular dimension with an
AbstractVector
, that dimension is retained; if you index with a scalar, that dimension is dropped. So for a 2d arrayA
,A[:,:]
produces 2d output,A[3,:]
andA[:,3]
both produce 1d output, andA[3:3,:]
,A[:,3:3]
both produce 2d output. Note this scheme is type-stable, so AFAICT there are no performance gotchas.But wow would it be a breaking change.
The text was updated successfully, but these errors were encountered: