-
-
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
Differentiate between copy_oftype(A, T) and convert(AbstractArray{T}, A) for structured arrays #35165
Conversation
The issue with julia> using LinearAlgebra
julia> A = SymTridiagonal(rand(4), rand(3))
4×4 SymTridiagonal{Float64,Array{Float64,1}}:
0.75844 0.0577674 ⋅ ⋅
0.0577674 0.0622232 0.909377 ⋅
⋅ 0.909377 0.55185 0.0100493
⋅ ⋅ 0.0100493 0.64809
julia> A[1,2] = 1
ERROR: ArgumentError: cannot set off-diagonal entry (1, 2)
Stacktrace:
[1] setindex!(::SymTridiagonal{Float64,Array{Float64,1}}, ::Int64, ::Int64, ::Int64) at /home/daan/code/julia/julialang/julia/usr/share/julia/stdlib/v1.5/LinearAlgebra/src/tridiag.jl:454
[2] top-level scope at REPL[3]:1
julia> A[1,3] = 0
ERROR: ArgumentError: cannot set off-diagonal entry (1, 3) I can not set the off-diagonal entry to another value, even though it seems valid to me. Also, the type does not allow setting other elements to zero. Both of these things make the default |
On second thought, not being able to set the off-diagonal entries of a |
Adding tests has the benefit of going over the changes again, I fixed one error on my side. The tests:
For testing purposes I needed an array for which |
@daanhb This is impressive work! We have a folder |
Thanks for the feedback @dkarrasch - I will update! |
Rebased and tests passing @dkarrasch. The |
This got a bit lost. @daanhb Do you remember what was the last status? Ready for review and merge, or was there anything left for discussion/implementation? Maybe we should revive this by rebasing and fixing merge conflicts? |
Thanks, just leaving a comment here to say I still intend to rebase this pull request. At that point I'll reassess whether it is still useful and, if so, I'll bump here. |
I'm closing this in favour of #40831 |
This pull request redefines the
copy_oftype
function in LinearAlgebra and it implementsconvert(AbstractArray{T}, A)
differently for a small number of structured arrays. The motivation for this pull request has been described in #34995. It also fixes JuliaLang/LinearAlgebra.jl#701.The request is split into two commits.
The first commit has the following two major changes:
copy_oftype(A, T)
is now implemented in terms of eithercopy(A)
orcopyto!(similar(A, T), A)
. It was already like that implicitly. The function used to invokeconvert(AbstractArray{T}, A)
, which in turn calledAbstractArray{T}(A)
, which in most cases would callcopyto!(similar(A, T), A)
. The change makes the fallback explicit.AbstractMatrix{T}(A)
is now implemented for all structured matrices in LinearAlgebra by invoking theAbstractVector{T}
orAbstractMatrix{T}
constructor on its underlying data. This was already the case for several arrays. After the first change,AbstractMatrix{T}(A)
is no longer assumed to return something mutable.It is difficult to illustrate with an example in Base, because the change is helpful for immutable arrays that support conversion to a different eltype. With the latest version of StaticArrays we have:
The point is that an immutable static matrix remains immutable after conversion to
AbstractMatrix{T}
(this is implemented in StaticArrays itself), and that the upper triangular matrix also remains immutable after conversion toAbstractMatrix{T}
(this is implemented in the pull request). Previously, the conversion of the triangular matrix would surprisingly yield a mutable and less efficientMArray
as the underlying data.Design choices:
copyto!(similar(A, T), A)
should always work. This was not the case for theSymTridiagonal
type (due to another issue which I'll come back to), so I've added a definition.AbstractMatrix{T}(A)
mimicks whatsimilar(A, T)
does: it will preserve structure ifsimilar
preserves structure, and vice-versa. Thus, its application to a transposed vector is recursive, but its application to a transposed matrix is not.AbstractMatrix{T}(A)
make a copy ofA
or not? It is clear thatconvert(AbstractArray{T}, A)
is not expected to make a copy. The recursive implementation ofAbstractMatrix{T}(A)
in this pull request invokes the constructor on the underlying data, not the conversion, so the decision lies with the underlying data array and this pull request remains agnostic. I don't think the behaviour is uniform, but perhaps that is not such a big problem.The second commit makes some more aggressive changes elsewhere in LinearAlgebra. It defines the new function
copy_similar
right aftercopy_oftype
:Typically, the three-argument call to similar discards the structure of
A
. The third argument issize(A)
and it is subtly absent in the definition ofcopy_oftype
. The result ofcopy_similar
is used in many places to create a writable matrix without the structure ofA
which is suitable for an in-place algorithm. I've looked for this use-case and replaced all occurrences with a call tocopy_similar
. This hopefully improves the clarity of this subtle difference in the code, and also shortens some files (most changes are in triangular.jl). It is otherwise independent from the first commit.On my machine the entire test suite passes with these changes, that is, it does not seem to affect any of the existing tests. I have yet to add tests for the specific things I've changed.
The code is actually shorter than all my explanations here and in #34995 :-)
Do these changes look acceptable?