-
Notifications
You must be signed in to change notification settings - Fork 0
Add ndims
type parameter to AbstractArrayInterface
#42
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
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #42 +/- ##
==========================================
+ Coverage 71.67% 72.23% +0.56%
==========================================
Files 11 11
Lines 353 371 +18
==========================================
+ Hits 253 268 +15
- Misses 100 103 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Just briefly checking this, isn't the ndims in the axes? Because it's not that uncommon to want to alter the number of dimensions, for example when you reduce over one or more of them, and then this interface wouldn't really support that. At least this is what I remember from not putting it there |
The axes aren't stored in the interface, maybe you are thinking of the |
You can see an example of updates that are needed for downstream packages here: ITensor/SparseArraysBase.jl#61. |
Sorry, I should have been more clear: What I have in mind is that in calls to I can see that it might be easier to work with fully instantiated arraytypes, but my experience is that this can become quite messy quickly, imagine having a Obviously I might also be missing something, this is just the case I have in mind and obviously I haven't looked at every usecase, just wanted to bring up this particular case. |
I see, thanks for the clarification. I agree the interplay between encoding The situation I'm thinking of is this one: similar(BlockSparseArray{Float64,3,Array{Float64,3}}, blockedrange.(([2, 3], [2, 3], [2, 3]))) where I want to derive the block sparse type from an interface, so for example from So, stepping back, I agree with your point that there may be other solutions to the narrower problem I'm looking at, but also I think having |
I was thinking about this a bit more, and I think the point you are bringing up is a good one. Basically, it is hard to tell when you really want to use the This PR approaches that with the following rules:
I think those rules should cover a lot of cases automatically, and provides a reasonable way to customize as needed. I'm thinking more about the case I brought up above. To summarize, we want an interface object: BlockSparseArrayInterface{3}(DefaultArrayInterface{3}()) and a set of axes similar(BlockSparseArray{Float64,3,Array{Float64,3}}, blockedrange.(([2, 3], [2, 3], [2, 3]))) which forwards to the constructor: BlockSparseArray{Float64,3,Array{Float64,3}}(undef, blockedrange.(([2, 3], [2, 3], [2, 3]))) Thinking through how this works if the similar(BlockSparseArray{Float64,<:Any,Array{Float64}}, blockedrange.(([2, 3], [2, 3], [2, 3]))) which means we should define the constructor: BlockSparseArray{Float64,<:Any,Array{Float64}}(undef, blockedrange.(([2, 3], [2, 3], [2, 3]))) or more generally the constructor where |
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.
Overall looks good to me + our discussion on arraytype
etc, should be good to go after!
@lkdvos in the latest I removed |
src/concatenate.jl
Outdated
end | ||
function Concatenated{Interface}(dims::Val, args::Tuple) where {Interface} | ||
return Concatenated(Interface(), dims, args) | ||
N = cat_ndims(dims, args...) | ||
return _Concatenated(set_interface_ndims(Interface, Val(N)), dims, args) |
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.
With this new call to similar
, do you need to set the interface ndims already at this point? I guess this would be automatically determined from the ax
later down the line, so I'm just wondering if there is any difference.
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.
That's true, when you call similar
, the ndims
in the interface will get overridden by the axes input to similar
. I kept it in case there is some other use case where storing the ndims
in the interface is useful, but I admit I don't have a particular use case in mind for Concatenated
.
I suppose what this does is catch cases where a user specifies an interface but it actually has the wrong ndims
for the concatenation expression, I guess that could be checked.
But also thinking about this particular constructor, it should change the Interface
type since that mean this constructor doesn't satisfy T(args...) isa T
, so I'll change this 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.
In the latest commits I propose a compromise. If the interface object is passed explicitly, it is taken "as is" and isn't modified, even if the ndims
aren't specified or are incorrect, but when it is constructed from the arguments the correct ndims
are computed explicitly.
That matches the behavior of Broadcasted
:
julia> using Base.Broadcast: DefaultArrayStyle, Broadcasted
julia> bc = Broadcasted(DefaultArrayStyle{1}(), +, (randn(2, 2), randn(2, 2)))
Broadcasted(+, ([0.095430782012298 0.4338409876936397; -0.2285907590132556 2.0739880112106475], [-0.6626604337472756 0.5369654075753642; 0.2681815713554777 -0.7930248596990674]))
julia> bc.style
DefaultArrayStyle{1}()
julia> bc = Broadcasted(+, (randn(2, 2), randn(2, 2)))
Broadcasted(+, ([-0.08113666651442918 -0.11158415095613558; -0.5031937898445847 -1.1018574952687241], [-1.595659893181313 0.12746978522353117; 0.026558187695457296 -0.22363363427492086]))
julia> bc.style
DefaultArrayStyle{2}()
That seems reasonable, since the interface is meant to be something where you can specify it to decide on the dispatch, I think we shouldn't be too opinionated about modifying what the user input since it may have been deliberate.
This adds an
ndims
type parameter toAbstractArrayInterface
, analogous to howBroadcast.AbstractArrayStyle
has the same thing.The use case is BlockSparseArrays.jl, where I want to generalize the
BlockSparseArrayInterface
type to store the interface of the blocks. It's helpful to have the number of dimensions stored in the interface so the block interface can be translated to a fully formed block type in calls likesimilar
orarraytype
which take an interface and construct a prototypical array or array type.To be more specific, right now we construct a prototypical array type from an interface with functions calls
DerivableInterfaces.arraytype(DefaultArrayInterface(), Float32) == Array{Float32}
. This PR continues to support that, but additionally enables doingDerivableInterfaces.arraytype(DefaultArrayInterface{2}(), Float32) == Matrix{Float32}
. An alternative design could be to specify the number of dimensions as a separate argument toarraytype
, i.e.DerivableInterfaces.arraytype(DefaultArrayInterface(), Val(2), Float32) == Matrix{Float32}
, but I think putting that information in the interface makes sense since then it can be used in other situations, such as for dispatch.Note that this is marked as breaking since packages like SparseArraysBase.jl, DiagonalArrays.jl, BlockSparseArrays.jl, etc. will need to account for the new
ndims
type parameter in the interface types they define.Closes #7.