-
Notifications
You must be signed in to change notification settings - Fork 14
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
PermutedDimsArray etc. #64
Conversation
Codecov Report
@@ Coverage Diff @@
## master #64 +/- ##
=======================================
Coverage 86.42% 86.42%
=======================================
Files 8 8
Lines 221 221
=======================================
Hits 191 191
Misses 30 30
Continue to review full report at Codecov.
|
Can we discuss And there is more to discuss on that one, |
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.
thanks for this.
I think adding PermutedDimsArray
is probably a good idea.
though maybe we do want to think a little bit more.
Since we are now overloading a constructor to not construct its type.
Which cases issues.
(I will link to an unstream bug report in a moment.)
@iamed2 what do you think?
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.
Thanks for opening this! I have some concerns about the proposed behaviour:
src/functions_dims.jl
Outdated
function Base.PermutedDimsArray(nda::NamedDimsArray{L}, perm) where {L} | ||
numerical_perm = dim(nda, perm) | ||
new_names = permute_dimnames(L, numerical_perm) | ||
return NamedDimsArray{new_names}(PermutedDimsArray(parent(nda), numerical_perm)) |
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.
Shouldn't this return a PermutedDimsArray
(wrapping a NamedDimsArray)?
Wouldn't we just want to add a constructor that allows perm
to contain Symbol
s?
Since PermuteDimsArray
(with Ints) already works here, don't we just want:
julia> nda = NamedDimsArray{(:w, :x, :y, :z)}(ones(10, 20, 30, 40));
julia> pda = PermutedDimsArray(nda, (1, 2, 4, 3)); # already works
julia> typeof(pda)
PermutedDimsArray{Float64,4,(1, 2, 4, 3),(1, 2, 4, 3),NamedDimsArray{(:w, :x, :y, :z),Float64,4,Array{Float64,4}}}
julia> size(pda)
(10, 20, 40, 30)
julia> pda == PermutedDimsArray(nda, (:w, :x, :z, :y)); # this is the method that should be added?
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.
I was hoping PermutedDimsArray
could return something with names you can refer to. Although @oxinabox raises the issue that it's weird not to return the constructor's type. Perhaps another objection is that if you care about the order of indices, then you are moving to positional not named code anyway, and should unwrap.
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 if we keep PermutedDimsArray
returning a PermutedDimsArray
, but add some methods on PermutedDimsArray{<:NamedDimsArray}
to return/use names? That seems like the alternative option to me. The issue with that approach is that there might be a bunch of methods necessary for dealing with NamedDimsArray
× PermutedDimsArray
interactions. Could be prohibitively troublesome.
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.
Couldn't you argue the same for Transpose
? The only difference is that the function usually called is named transpose
.
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 right, that might mean that we can just include PermutedDimsArray
with existing transpose-handling code (with some augmentation).
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 Eric's suggestion is nice, but is too much work and maintainence for the gain
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.
To be clear, I think this is an interesting case... but I find PermutedDimsArray(::NamedDimsArray, perm) -> NamedDimsArray{PermuteDimsArray}
to be really surprising behaviour. I expect to get a PermuteDimsArray{NamedDimsArrays}
which is what we get on master. I do think allowing perm
to be names i.e Symbol
s make sense.
I'd be happy with special behaviour for PermuteDimsArray{NamedDimsArrays}
if the maintainence cost is proportionate .
Just a personal opinion - open to alternative views :)
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.
It does seem odd that Julia has transpose
which makes Transpose
but no lazypermutedims
which makes PermutedDimsArray
, so the name of the type does double duty. Maybe that's the core here? This PR wants to extend lazypermutedims
, although it happens not to have that spelling.
Calling lazypermutedims
is supposed to do the same as permutedims
but without moving the data; the same functions should work on the output. Although (in Base) this relies on these working on AbstractArray, not Array.
It would seem very strange to me that functions like sum(A, dims=:k)
would be expected to work on things not of the form NamedDimsArray{Storage}
. Anyone writing a function should then have to know to look inside, and not just dispatch on ::NamedDimsArray
. They don't have to do this with NamedDimsArray{Transpose}
etc.
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.
It would seem very strange to me that functions like sum(A, dims=:k) would be expected to work on things not of the form NamedDimsArray{Storage}
For the case of wrapper arrays, then unless they are also messing with dims
, I expect them to delegate that kwarg straight to the inner array type. And if they are, I kind of expect in many cases (Inc PermuteDimsArray
) they can do their messing about with it and passes them modified version to the wrapped array.
And so it just works,in theory.
Orthogonal features added via wrapper arrays should work no matter the order of the wrapping
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 seem to have deleted my comment by accident, sorry)
Orthogonal features added via wrapper arrays should work no matter the order of the wrapping
I like this vision, but for now it seems many things do care. Some examples:
julia> xy = NamedDimsArray{(:x, :y)}(rand(2,2));
julia> yx = NamedDimsArray{(:y, :x)}(rand(2,2));
julia> xy * transpose(yx) # correctly errors, as NamedDimsArray is outermost
ERROR: DimensionMismatch("Cannot take matrix product of arrays with different inner dimension names. (:x, :y) vs (:x, :y)")
julia> xy * PermutedDimsArray(yx, (2,1)) # silently falls back to AbstractArray
2×2 NamedDimsArray{(:x, :_),Float64,2,Array{Float64,2}}:
0.571736 0.94319
0.379215 0.585958
julia> sum(PermutedDimsArray(yx, (2,1)), dims=:y) # doesn't know how to pass this along
ERROR: MethodError: no method matching iterate(::Symbol)
julia> NamedDims.names(Transpose(yx)) # doesn't look inside
(:_, :_)
Perhaps one could avoid these by always dispatching on some big Union{NDA, Adjoint{NDA}, Transpose{NDA}, ...}
type, I don't know how messy that would be.
But without commutativity of wrapping, I guess deciding who goes outermost might be a hard problem. I suppose my implicit rule here was that PermutedDimsArray
is just a storage detail, like Transpose
. User code shouldn't care, so it doesn't need to be exposed.
OK, I trimmed this to just That's interesting about default constructors etc, I didn't realise this was anything beyond a convention. I can't in 5 minutes make |
|
But that's just complaining about the lack of a permutation, there's no one-arg method:
|
Ah, right, yes. This probably can't happen for things that don't have 1arg constructors. Just because of the nature that bug. |
@nickrobinson251's position sounds reasonable to me |
Closing in favour of someday making wrappers outside |
I had a go at making wrappers outside |
This treats
PermutedDimsArray
exactly likepermutedims
.And it adds a method
unname(A::NamedDimsArray, names)
which is always a view of the parent, with axes ordered to match the given names.