-
-
Notifications
You must be signed in to change notification settings - Fork 32
diag
with a Val
band index
#1424
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
base: master
Are you sure you want to change the base?
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1424 +/- ##
=======================================
Coverage 93.88% 93.89%
=======================================
Files 34 34
Lines 15891 15913 +22
=======================================
+ Hits 14920 14942 +22
Misses 971 971 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
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.
Nice stuff! Should we use it in multiplication code? Looking at your example, we should perhaps do it only in cases where we only read from the bands, but don't write to them?
Co-authored-by: Daniel Karrasch <[email protected]>
This may increase latency a bit, but should decrease allocations and potentially speed-up reading from the bands? |
Yes, I see this primarily as an optimization that downstream packages may find useful. We may be able to write to the bands as well, but this isn't guaranteed in general. Reading should always be possible. An example use case may be that We are already using something similar in our multiplication code that unwraps the fields ( |
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.
IMO it's ugly to introduce more ::Val
methods, instead of relying on the "static integer" types present in some packages, possibly through package extensions.
If you really do want Val
, I'd suggest doing ::Int
typeassert
s on the method static parameter in the beginning of the body of each method with a Val{k}
method static parameter.
Why: The value of the static parameter is intended to be Int
. This is both usual with Val
usage in general and implied by the fact that you define methods for Val{0}
, but not for, e.g., Val{0x0}
. Adding typeassert
s provides some measure of type safety, protecting users who might choose the wrong type for the static parameter isbits
value from performance gotchas/unexpected dispatch.
The typeassert
s might also improve worst-case inference results.
|
||
diagview(A::Transpose, k::Integer = 0) = _vectranspose(diagview(parent(A), -k)) | ||
diagview(A::Adjoint, k::Integer = 0) = _vecadjoint(diagview(parent(A), -k)) | ||
diag(A::Transpose, ::Val{k}) where {k} = _vectranspose(diag(parent(A), Val(-k))) |
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.
diag(A::Transpose, ::Val{k}) where {k} = _vectranspose(diag(parent(A), Val(-k))) | |
diag(A::Transpose, ::Val{k}) where {k} = _vectranspose(diag(parent(A), Val(-k::Int))) |
diagview(A::Transpose, k::Integer = 0) = _vectranspose(diagview(parent(A), -k)) | ||
diagview(A::Adjoint, k::Integer = 0) = _vecadjoint(diagview(parent(A), -k)) | ||
diag(A::Transpose, ::Val{k}) where {k} = _vectranspose(diag(parent(A), Val(-k))) | ||
diag(A::Adjoint, ::Val{k}) where {k} = _vecadjoint(diag(parent(A), Val(-k))) |
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.
diag(A::Adjoint, ::Val{k}) where {k} = _vecadjoint(diag(parent(A), Val(-k))) | |
diag(A::Adjoint, ::Val{k}) where {k} = _vecadjoint(diag(parent(A), Val(-k::Int))) |
!!! note | ||
The type of the result may vary depending on the values of `k`. | ||
""" | ||
function diag(A::AbstractMatrix, ::Val{k}) where {k} |
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.
function diag(A::AbstractMatrix, ::Val{k}) where {k} | |
function diag(A::AbstractMatrix, ::Val{K}) where {K} | |
k = K::Int |
end | ||
|
||
diag(A::UpperHessenberg) = diag(A.data) | ||
diag(A::UpperHessenberg, ::Val{k}) where {k} = k >= -1 ? diag(A.data, Val(k)) : diag(A, k) |
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.
diag(A::UpperHessenberg, ::Val{k}) where {k} = k >= -1 ? diag(A.data, Val(k)) : diag(A, k) | |
function diag(A::UpperHessenberg, ::Val{K}) where {K} | |
k = K::Int | |
k >= -1 ? diag(A.data, Val(k)) : diag(A, k) | |
end |
|
||
diag(A::UpperOrLowerTriangular) = diag(A.data) | ||
diag(A::Union{UnitLowerTriangular, UnitUpperTriangular}) = fill(oneunit(eltype(A)), size(A,1)) | ||
diag(A::UpperTriangular, ::Val{k}) where {k} = k >= 0 ? diag(A.data, Val(k)) : diag(A, k) |
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.
diag(A::UpperTriangular, ::Val{k}) where {k} = k >= 0 ? diag(A.data, Val(k)) : diag(A, k) | |
function diag(A::UpperTriangular, ::Val{K}) where {K} | |
k = K::Int | |
k >= 0 ? diag(A.data, Val(k)) : diag(A, k) | |
end |
diag(A::UpperOrLowerTriangular) = diag(A.data) | ||
diag(A::Union{UnitLowerTriangular, UnitUpperTriangular}) = fill(oneunit(eltype(A)), size(A,1)) | ||
diag(A::UpperTriangular, ::Val{k}) where {k} = k >= 0 ? diag(A.data, Val(k)) : diag(A, k) | ||
diag(A::LowerTriangular, ::Val{k}) where {k} = k <= 0 ? diag(A.data, Val(k)) : diag(A, k) |
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.
diag(A::LowerTriangular, ::Val{k}) where {k} = k <= 0 ? diag(A.data, Val(k)) : diag(A, k) | |
function diag(A::LowerTriangular, ::Val{K}) where {K} | |
k = K::Int | |
k <= 0 ? diag(A.data, Val(k)) : diag(A, k) | |
end |
diag(A::LowerTriangular, ::Val{k}) where {k} = k <= 0 ? diag(A.data, Val(k)) : diag(A, k) | ||
diag(A::UnitUpperTriangular, ::Val{0}) = diag(A) | ||
diag(A::UnitLowerTriangular, ::Val{0}) = diag(A) | ||
diag(A::UnitUpperTriangular, ::Val{k}) where {k} = k > 0 ? diag(A.data, Val(k)) : diag(A, k) |
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.
diag(A::UnitUpperTriangular, ::Val{k}) where {k} = k > 0 ? diag(A.data, Val(k)) : diag(A, k) | |
function diag(A::UnitUpperTriangular, ::Val{K}) where {K} | |
k = K::Int | |
k > 0 ? diag(A.data, Val(k)) : diag(A, k) | |
end |
diag(A::UnitUpperTriangular, ::Val{0}) = diag(A) | ||
diag(A::UnitLowerTriangular, ::Val{0}) = diag(A) | ||
diag(A::UnitUpperTriangular, ::Val{k}) where {k} = k > 0 ? diag(A.data, Val(k)) : diag(A, k) | ||
diag(A::UnitLowerTriangular, ::Val{k}) where {k} = k < 0 ? diag(A.data, Val(k)) : diag(A, k) |
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.
diag(A::UnitLowerTriangular, ::Val{k}) where {k} = k < 0 ? diag(A.data, Val(k)) : diag(A, k) | |
function diag(A::UnitLowerTriangular, ::Val{K}) where {K} | |
k = K::Int | |
k < 0 ? diag(A.data, Val(k)) : diag(A, k) | |
end |
Would it make sense to let |
That might be too breaking. It's usually reasonable to assume that We may try something like that to see how much it impacts the ecosystem, but let's do it in another PR. |
I think this should be based on |
Are you suggesting a The only concern there is type-stability. The current PR was embedding the band index in the |
Looking at what julia> B = brand(Int8, 5,5, 1,1)
5×5 BandedMatrix{Int8} with bandwidths (1, 1):
-81 -73 ⋅ ⋅ ⋅
92 -122 -80 ⋅ ⋅
⋅ -120 37 -100 ⋅
⋅ ⋅ -111 -80 -32
⋅ ⋅ ⋅ 69 28
julia> @view B[Band(1)]
4-element view(reshape(::BandedMatrix{Int8, Matrix{Int8}, Base.OneTo{Int64}}, 25), BandedMatrices.BandSlice(Band(1), 6:6:24)) with eltype Int8:
-73
-80
-100
-32 This returns a view of the |
This provides a public API to access the underlying bands of a structured matrix without having to access its fields. These bands are often used by packages, so this method seems useful.
This generalizes better to other structured matrix types for which we can't specialize the 1-argument
diag
.Currently,
diag(M, ::Val{k}) where {k}
falls back todiag(M, k::Integer)
when a specialized implementation isn't available.