Closed
Description
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
- Multiplying various matrix types with
QRCompactQ
.
The same issue was reported for multiplication withUniformScaling
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. getindex
forQRCompactQ
This problem could be solved by defining thegetindex
method properly.
A bonus would be that one could useF.Q[:,:]
to retrieve the fullQ
, rather than the cumbersomeF.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.