Skip to content
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

Added function to compute Diagonal*F.Q' and faster methods for other variants. #41248

Merged
merged 16 commits into from
Jun 18, 2021

Conversation

ArunS-tack
Copy link
Contributor

@ArunS-tack ArunS-tack commented Jun 16, 2021

Closes #38974.

Requesting reviews from @dkarrasch @andreasnoack .

@dkarrasch dkarrasch added the domain:linear algebra Linear algebra label Jun 17, 2021
@dkarrasch
Copy link
Member

I don't think this is the right approach. I think we should add

*(A::Diagonal, adjB::Adjoint{<:Any,<:Union{LinearAlgebra.QRCompactWYQ,LinearAlgebra.QRPackedQ}}) =
    rmul!(copyto!(Array{promote_type(eltype(A), eltype(adjB))}(undef, size(A)...), A), adjB)
*(A::BiTriSym, adjB::Adjoint{<:Any,<:Union{LinearAlgebra.QRCompactWYQ,LinearAlgebra.QRPackedQ}}) =
    rmul!(copyto!(Array{promote_type(eltype(A), eltype(adjB))}(undef, size(A)...), A), adjB)
*(adjA::Adjoint{<:Any,<:Union{LinearAlgebra.QRCompactWYQ,LinearAlgebra.QRPackedQ}}, B::Diagonal) =
    lmul!(adjA, copyto!(Array{promote_type(eltype(adjA), eltype(B))}(undef, size(B)...), B))
*(adjA::Adjoint{<:Any,<:Union{LinearAlgebra.QRCompactWYQ,LinearAlgebra.QRPackedQ}}, B::BiTriSym) =
    lmul!(adjA, copyto!(Array{promote_type(eltype(adjA), eltype(B))}(undef, size(B)...), B))

below

rmul!(A::AbstractTriangular, adjB::Adjoint{<:Any,<:Union{QRCompactWYQ,QRPackedQ}}) =
(B = adjB.parent; rmul!(full!(A), adjoint(B)))
*(A::AbstractTriangular, adjB::Adjoint{<:Any,<:Union{QRCompactWYQ,QRPackedQ}}) =
(B = adjB.parent; *(copyto!(similar(parent(A)), A), adjoint(B)))

The methods that currently handle Q' * D treat Q like a quickly indexable matrix (in adjoint!), which is likely slow.

@dkarrasch
Copy link
Member

dkarrasch commented Jun 17, 2021

Even simpler: we already have

*(D::Diagonal, adjQ::Adjoint{<:Any,<:Union{QRCompactWYQ,QRPackedQ}}) = (Q = adjQ.parent; rmul!(Array(D), adjoint(Q)))

which should be

*(D::Diagonal, adjQ::Adjoint{<:Any,<:Union{QRCompactWYQ,QRPackedQ}}) =
    rmul!(Array{promote_type(eltype(D), eltype(adjQ))}(D), adjQ)

but perhaps we take the opportunity to make sure we also cover *(adjQ, D) and the other *diagonal types as suggested above.

@ArunS-tack
Copy link
Contributor Author

Even simpler: we already have

*(D::Diagonal, adjQ::Adjoint{<:Any,<:Union{QRCompactWYQ,QRPackedQ}}) = (Q = adjQ.parent; rmul!(Array(D), adjoint(Q)))

which should be

*(D::Diagonal, adjQ::Adjoint{<:Any,<:Union{QRCompactWYQ,QRPackedQ}}) =
    rmul!(Array{promote_type(eltype(D), eltype(adjQ))}(D), adjQ)

but perhaps we take the opportunity to make sure we also cover *(adjQ, D) and the other *diagonal types as suggested above.

Even simpler: we already have

*(D::Diagonal, adjQ::Adjoint{<:Any,<:Union{QRCompactWYQ,QRPackedQ}}) = (Q = adjQ.parent; rmul!(Array(D), adjoint(Q)))

which should be

*(D::Diagonal, adjQ::Adjoint{<:Any,<:Union{QRCompactWYQ,QRPackedQ}}) =
    rmul!(Array{promote_type(eltype(D), eltype(adjQ))}(D), adjQ)

but perhaps we take the opportunity to make sure we also cover *(adjQ, D) and the other *diagonal types as suggested above.

Nice! This one seems much simpler. But to make it clear, we are not implementing the function as made in the commit because it only covers a narrow number of cases and takes longer to compute the multiplication, right?

@dkarrasch
Copy link
Member

The function as it is currently in the commit has a very narrow type signature, and it also doesn't mutate its first argument as it should. The idea is to provide [l/r]mul! with the correct eltype'd array in the * method.

@ArunS-tack
Copy link
Contributor Author

ArunS-tack commented Jun 17, 2021

function rmul!(A::StridedVecOrMat, adjB::Adjoint{<:Any,<:Union{QRCompactWYQ,QRPackedQ}})
    return rmul!(Array{promote_type(eltype(A), eltype(adjB))}(A), adjB)
end

I modified the code a bit, its also a lot faster now and most probably covers a wide range of type signature too. What are your views about this one? Also can we not use Union{Diagonal, BiTriSym} to cover it all in a single method/function?

@dkarrasch
Copy link
Member

dkarrasch commented Jun 17, 2021

In your proposal, you again create a copy of A first and then multiply into it. This is not how *mul!s are supposed to work. And this also doesn't cover the case when the first factor is a Diagonal.

Also can we not use Union{Diagonal, BiTriSym} to cover it all in a single method/function?

This will likely lead to method ambiguities.

@ArunS-tack
Copy link
Contributor Author

Got it! I will implement what you suggested above in diagonal.jl along with other methods then.

@ArunS-tack
Copy link
Contributor Author

but perhaps we take the opportunity to make sure we also cover *(adjQ, D)

A method for that already exists I guess, its working fine.

@dkarrasch
Copy link
Member

A method for that already exists I guess, its working fine.

Sure, but I guess it's slow.

@ArunS-tack
Copy link
Contributor Author

ArunS-tack commented Jun 17, 2021

well, actually it seems the methods already exist for all other types i.e BiTriSym and *(adjQ, D) as well for Diagonal.
Only one which doesn't exists is *(D,adjQ) for Diagonal. Shall I anyway add them in diagonal.jl?

@ArunS-tack
Copy link
Contributor Author

A method for that already exists I guess, its working fine.

Sure, but I guess it's slow.

Yes, indeed. It is slow.

@dkarrasch
Copy link
Member

Right. This can be fixed by my proposals above. I'll explain later why this is. Gotta leave now...

@ArunS-tack ArunS-tack changed the title Added function to compute I(n)*F.Q' [element promotion of I(n)]. Added function to compute Diagonal*F.Q' and faster methods for other variants. Jun 17, 2021
@codecov
Copy link

codecov bot commented Jun 18, 2021

Codecov Report

Merging #41248 (6dfa690) into master (004cb25) will increase coverage by 1.82%.
The diff coverage is 84.73%.

❗ Current head 6dfa690 differs from pull request most recent head be45c69. Consider uploading reports for the commit be45c69 to get more accurate results
Impacted file tree graph

@@            Coverage Diff             @@
##           master   #41248      +/-   ##
==========================================
+ Coverage   86.15%   87.97%   +1.82%     
==========================================
  Files         350      351       +1     
  Lines       65991    74690    +8699     
==========================================
+ Hits        56854    65711    +8857     
+ Misses       9137     8979     -158     
Impacted Files Coverage Δ
base/atomics.jl 84.00% <ø> (+0.66%) ⬆️
base/baseext.jl 94.73% <ø> (ø)
base/compiler/typeutils.jl 82.53% <ø> (+0.17%) ⬆️
base/compiler/utilities.jl 87.90% <ø> (+1.24%) ⬆️
base/compiler/validation.jl 88.99% <ø> (+0.64%) ⬆️
base/complex.jl 99.43% <ø> (-0.16%) ⬇️
base/condition.jl 78.00% <ø> (+4.08%) ⬆️
base/coreio.jl 68.75% <ø> (-6.25%) ⬇️
base/cpuid.jl 82.60% <ø> (ø)
base/deepcopy.jl 100.00% <ø> (ø)
... and 512 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 083272b...be45c69. Read the comment docs.

Copy link
Member

@dkarrasch dkarrasch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few redundant lines, and then we need tests for the new BiTriSym methods. Would be also great to see some benchmarks, to make sure we do the right thing.

stdlib/LinearAlgebra/src/special.jl Outdated Show resolved Hide resolved
stdlib/LinearAlgebra/src/diagonal.jl Outdated Show resolved Hide resolved
@ArunS-tack
Copy link
Contributor Author

About Benchmarks, do we have to add them in some file or shall I just post it here as a comment?

@ArunS-tack
Copy link
Contributor Author

BENCHMARKS

julia> @benchmark Tri*A
BenchmarkTools.Trial: 
  memory estimate:  320 bytes
  allocs estimate:  2
  --------------
  minimum time:     542.112 ns (0.00% GC)
  median time:      549.644 ns (0.00% GC)
  mean time:        557.678 ns (0.56% GC)
  maximum time:     4.261 μs (86.09% GC)
  --------------
  samples:          10000
  evals/sample:     188

julia> @benchmark A*Tri

BenchmarkTools.Trial: 
  memory estimate:  320 bytes
  allocs estimate:  2
  --------------
  minimum time:     527.632 ns (0.00% GC)
  median time:      535.526 ns (0.00% GC)
  mean time:        543.155 ns (0.59% GC)
  maximum time:     3.431 μs (81.91% GC)
  --------------
  samples:          10000
  evals/sample:     190

julia> 

julia> @benchmark Bi*A
BenchmarkTools.Trial: 
  memory estimate:  320 bytes
  allocs estimate:  2
  --------------
  minimum time:     540.561 ns (0.00% GC)
  median time:      548.280 ns (0.00% GC)
  mean time:        555.362 ns (0.57% GC)
  maximum time:     3.101 μs (81.05% GC)
  --------------
  samples:          10000
  evals/sample:     189

julia> @benchmark A*Bi
BenchmarkTools.Trial: 
  memory estimate:  320 bytes
  allocs estimate:  2
  --------------
  minimum time:     528.511 ns (0.00% GC)
  median time:      535.963 ns (0.00% GC)
  mean time:        542.820 ns (0.58% GC)
  maximum time:     3.123 μs (81.92% GC)
  --------------
  samples:          10000
  evals/sample:     190

julia> @benchmark Sym*A
BenchmarkTools.Trial: 
  memory estimate:  320 bytes
  allocs estimate:  2
  --------------
  minimum time:     526.316 ns (0.00% GC)
  median time:      533.553 ns (0.00% GC)
  mean time:        541.513 ns (0.60% GC)
  maximum time:     3.133 μs (81.88% GC)
  --------------
  samples:          10000
  evals/sample:     190

julia> @benchmark A*Sym 
BenchmarkTools.Trial: 
  memory estimate:  320 bytes
  allocs estimate:  2
  --------------
  minimum time:     515.406 ns (0.00% GC)
  median time:      522.786 ns (0.00% GC)
  mean time:        530.500 ns (0.60% GC)
  maximum time:     3.139 μs (79.75% GC)
  --------------
  samples:          10000
  evals/sample:     192

@dkarrasch
Copy link
Member

For comparison, what are the times on current master?

@ArunS-tack
Copy link
Contributor Author

julia> @benchmark Bi*A

BenchmarkTools.Trial: 
  memory estimate:  5.31 KiB
  allocs estimate:  50
  --------------
  minimum time:     7.781 μs (0.00% GC)
  median time:      7.979 μs (0.00% GC)
  mean time:        8.122 μs (1.18% GC)
  maximum time:     250.542 μs (96.43% GC)
  --------------
  samples:          10000
  evals/sample:     4

julia> @benchmark A*Bi
BenchmarkTools.Trial: 
  memory estimate:  13.47 KiB
  allocs estimate:  131
  --------------
  minimum time:     20.250 μs (0.00% GC)
  median time:      20.833 μs (0.00% GC)
  mean time:        21.273 μs (1.76% GC)
  maximum time:     1.292 ms (98.03% GC)
  --------------
  samples:          10000
  evals/sample:     1

julia> @benchmark Sym*A
BenchmarkTools.Trial: 
  memory estimate:  5.20 KiB
  allocs estimate:  49
  --------------
  minimum time:     7.708 μs (0.00% GC)
  median time:      8.011 μs (0.00% GC)
  mean time:        8.119 μs (0.96% GC)
  maximum time:     273.562 μs (96.52% GC)
  --------------
  samples:          10000
  evals/sample:     4

julia> @benchmark A*Sym 
BenchmarkTools.Trial: 
  memory estimate:  13.36 KiB
  allocs estimate:  130
  --------------
  minimum time:     20.250 μs (0.00% GC)
  median time:      20.875 μs (0.00% GC)
  mean time:        21.530 μs (1.88% GC)
  maximum time:     1.479 ms (98.16% GC)
  --------------
  samples:          10000
  evals/sample:     1

@ArunS-tack
Copy link
Contributor Author

Not sure why is it still showing 'Changes requested'? Afaik, I have resolved all the reviews.

@dkarrasch dkarrasch merged commit 3279e20 into JuliaLang:master Jun 18, 2021
@ArunS-tack ArunS-tack deleted the bool branch June 18, 2021 17:56
johanmon pushed a commit to johanmon/julia that referenced this pull request Jul 5, 2021
jessymilare pushed a commit to jessymilare/julia that referenced this pull request Sep 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Missing element promotion in I(n)*F.Q'
2 participants