julia> using LinearAlgebra
julia> Q = qr(rand(30,30));
julia> Q2 = Q.Q;
julia> @code_warntype Q2 * rand(size(Q2,2))
MethodInstance for *(::LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}}, ::Vector{Float64})
from *(A::LinearAlgebra.AbstractQ, b::StridedVector{T} where T) in LinearAlgebra at /home/jb6888/julia/julia-c8b5904991/share/julia/stdlib/v1.8/LinearAlgebra/src/qr.jl:635
Arguments
#self#::Core.Const(*)
A::LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}}
b::Vector{Float64}
Locals
bnew::Vector{Float64}
Anew::LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}}
TAb::Type{Float64}
Body::Vector{Float64}
1 ─ Core.NewvarNode(:(bnew))
│ %2 = LinearAlgebra.eltype(A)::Core.Const(Float64)
│ %3 = LinearAlgebra.eltype(b)::Core.Const(Float64)
│ (TAb = LinearAlgebra.promote_type(%2, %3))
│ %5 = Core.apply_type(LinearAlgebra.AbstractMatrix, TAb::Core.Const(Float64))::Core.Const(AbstractMatrix{Float64})
│ (Anew = LinearAlgebra.convert(%5, A))
│ %7 = Base.getproperty(A, :factors)::Matrix{Float64}
│ %8 = LinearAlgebra.size(%7, 1)::Int64
│ %9 = LinearAlgebra.length(b)::Int64
│ %10 = (%8 == %9)::Bool
└── goto #3 if not %10
2 ─ (bnew = LinearAlgebra.copy_oftype(b, TAb::Core.Const(Float64)))
└── goto #6
3 ─ %14 = Base.getproperty(A, :factors)::Matrix{Float64}
│ %15 = LinearAlgebra.size(%14, 2)::Int64
│ %16 = LinearAlgebra.length(b)::Int64
│ %17 = (%15 == %16)::Bool
└── goto #5 if not %17
4 ─ %19 = TAb::Core.Const(Float64)
│ %20 = Base.getproperty(A, :factors)::Matrix{Float64}
│ %21 = LinearAlgebra.size(%20, 1)::Int64
│ %22 = LinearAlgebra.length(b)::Int64
│ %23 = (%21 - %22)::Int64
│ %24 = LinearAlgebra.zeros(%19, %23)::Vector{Float64}
│ (bnew = Base.vcat(b, %24))
└── goto #6
5 ─ %27 = Base.getproperty(A, :factors)::Any
│ %28 = LinearAlgebra.size(%27, 1)::Any
│ %29 = Base.getproperty(A, :factors)::Any
│ %30 = LinearAlgebra.size(%29, 2)::Any
│ %31 = Base.string("vector must have length either ", %28, " or ", %30)::Any
│ %32 = LinearAlgebra.DimensionMismatch(%31)::Any
└── LinearAlgebra.throw(%32)
6 ┄ %34 = LinearAlgebra.lmul!(Anew, bnew)::Vector{Float64}
└── return %34
while the overall operation is type-stable, there are several Any
around %27 where Q2.factors
is used. For some reason the type of Q2.factors
is not being inferred, which is strange since
julia> typeof(Q2)
LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}}
and the struct is defined as
struct QRCompactWYQ{S, M<:AbstractMatrix{S}} <: AbstractQ{S}
factors::M
T::Matrix{S}
function QRCompactWYQ{S,M}(factors, T) where {S,M<:AbstractMatrix{S}}
require_one_based_indexing(factors)
new{S,M}(factors, T)
end
end
and the type of factors
should be inferred from the type of Q2
. I can see this when I check
julia> @code_warntype Q2.factors
MethodInstance for getproperty(::LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}}, ::Symbol)
from getproperty(x, f::Symbol) in Base at Base.jl:38
Arguments
#self#::Core.Const(getproperty)
x::LinearAlgebra.QRCompactWYQ{Float64, Matrix{Float64}}
f::Symbol
Body::Matrix{Float64}
1 ─ nothing
│ %2 = Base.getfield(x, f)::Matrix{Float64}
└── return %2
but I’m not sure why it’s not inferred in the multiplication.