-
Notifications
You must be signed in to change notification settings - Fork 65
Specialize multiplication of AbstractQ with sparse arrays #317
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
|
Any opinions? Since this occurs in the wild, I guess there is no option to disallow that multiplication? |
|
Won't this be bad for large-ish sparse matrices, where conversion to dense will run out of memory? |
|
That conversion seems still beneficial in that case, because otherwise you'll get dense |
|
[Sh/c]ould we backport this to v1.9 (and even earlier)? It doesn't interfere with anything else AFAICT, because those products are passed through to _
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.6.7 (2022-07-19)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
julia> using LinearAlgebra, SparseArrays
julia> methods(*, (LinearAlgebra.AbstractQ, SparseMatrixCSC))
# 1 method for generic function "*":
[1] *(A::AbstractMatrix{T} where T, B::AbstractMatrix{T} where T) in LinearAlgebra at /Applications/Julia-1.6.app/Contents/Resources/julia/share/julia/stdlib/v1.6/LinearAlgebra/src/matmul.jl:151 _
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.8.3 (2022-11-14)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
julia> using LinearAlgebra, SparseArrays
julia> methods(*, (LinearAlgebra.AbstractQ, SparseMatrixCSC))
# 1 method for generic function "*":
[1] *(A::AbstractMatrix, B::AbstractMatrix) in LinearAlgebra at /Applications/Julia-1.8.app/Contents/Resources/julia/share/julia/stdlib/v1.8/LinearAlgebra/src/matmul.jl:139 _
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.9.0-alpha1 (2022-11-15)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
julia> using LinearAlgebra, SparseArrays
julia> methods(*, (LinearAlgebra.AbstractQ, SparseMatrixCSC))
# 2 methods for generic function "*" from Base:
[1] *(Q::SparseArrays.SPQR.QRSparseQ, B::SparseMatrixCSC)
@ SparseArrays.SPQR /Applications/Julia-1.9.app/Contents/Resources/julia/share/julia/stdlib/v1.9/SparseArrays/src/solvers/spqr.jl:287
[2] *(A::AbstractMatrix, B::AbstractMatrix)
@ LinearAlgebra /Applications/Julia-1.9.app/Contents/Resources/julia/share/julia/stdlib/v1.9/LinearAlgebra/src/matmul.jl:139where [1] points to (*)(Q::QRSparseQ, B::SparseMatrixCSC) = sparse(Q) * B
(*)(A::SparseMatrixCSC, Q::QRSparseQ) = A * sparse(Q) |
|
We can think about backporting this later, I guess. I'm merging this and include it in Julia master. |
|
@SobhanMP @Wimmerer Before I forget, let me bring this to your attention. Looking at (*)(Q::QRSparseQ, B::SparseMatrixCSC) = sparse(Q) * B
(*)(A::SparseMatrixCSC, Q::QRSparseQ) = A * sparse(Q)I was wondering whether for typical sparse Q's, the result of (*)(Q::QRSparseQ, B::SparseMatrixCSC) = lmul!(Q, Matrix(B))
(*)(A::SparseMatrixCSC, Q::QRSparseQ) = lmul!(Matrix(A), Q)could be a more performant option (including eltype promotion). I came to think about it because we only have |
It turns out that in a few packages (in particular optimization-related ones) there is multiplication of
AbstractQinstances andSparseArrays. Due to a lack of specialization, this falls back to_generic_matmatmul!, which is horrible for at least three reasons: (1) it's computing the elements of the matrix representation ofQone-by-one; (2) it doesn't use sparsity at all; and (3) it writes the dense result into an empty sparse output array. I have a hard time imagining anything worse than that. This popped up once we dropAbstractQ <: AbstractMatrixsubtyping, see JuliaLang/julia#46196.