Skip to content

Two performance problems with the Q in QR factorizations #800

Closed
JuliaLang/julia
#44615
@olof3

Description

@olof3
n = 300
B = randn(n, n)
D = Diagonal(ones(n))
F = qr(randn(n, 1))
@time F.Q * B # Works as expected
@time F.Q * D # Slow
@time F.Q * I # Slow
@time F.Q[:, :] # Slow

gives

  0.000505 seconds (4 allocations: 705.734 KiB)
  0.251926 seconds (270.00 k allocations: 448.380 MiB, 10.12% gc time)
  0.246129 seconds (270.00 k allocations: 448.380 MiB, 7.77% gc time)
  0.239383 seconds (270.01 k allocations: 448.380 MiB, 8.09% gc time)

There seems to be two problems

  1. Multiplying various matrix types with QRCompactQ.
    The same issue was reported for multiplication with UniformScaling in Unexpected performance loss #758.
    I guess the solution is to define the proper methods. Perhaps this would also fix Missing element promotion in I(n)*F.Q' #801.
  2. getindex for QRCompactQ
    This problem could be solved by defining the getindex method properly.
    A bonus would be that one could use F.Q[:,:] to retrieve the full Q, rather than the cumbersome F.Q*Matrix(I,m,m) as suggested in the docstring.

For problem 2., the following method seems to work for me, but I guess it needs further consideration and testing.

function getindex(Q::Union{AbstractQ,Adjoint{<:Any,<:AbstractQ}}, ind1, ind2)
    if ind2 isa Colon
        ind2 = 1:size(Q,2)
    end

    X = zeros(eltype(Q), size(Q,1), length(ind2))
    for (j,i) in enumerate(ind2)
        X[i,j] = 1
    end

    lmul!(Q, X)
    
    if ind2 isa Integer
        return X[ind1, 1]
    else
        return X[ind1, :]
    end
end

Perhaps it would also be good to have

getindex(Q::Union{AbstractQ,Adjoint{<:Any,<:AbstractQ}}, ::Colon, ::Colon) = lmul!(Q, Matrix{eltype(Q)}(I, size(Q)))

If the above methods are introduced it seems like the existing method,

function getindex(Q::AbstractQ, i::Integer, j::Integer)
    x = zeros(eltype(Q), size(Q, 1))
    x[i] = 1
    y = zeros(eltype(Q), size(Q, 2))
    y[j] = 1
    return dot(x, lmul!(Q, y))
end

could be removed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions