-
Couldn't load subscription status.
- 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
| 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
ndimstype parameter toAbstractArrayInterface, analogous to howBroadcast.AbstractArrayStylehas the same thing.The use case is BlockSparseArrays.jl, where I want to generalize the
BlockSparseArrayInterfacetype 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 likesimilarorarraytypewhich 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
ndimstype parameter in the interface types they define.Closes #7.