From cb757c41102e4cdc899d76464acde0938c36de9e Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Tue, 29 Oct 2024 13:30:18 +0530 Subject: [PATCH] Add one-arg `norm` method (#56330) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reduces the latency of `norm` calls, as the single-argument method lacks branches and doesn't use aggressive constant propagation, and is therefore simpler to compile. Given that a lot of `norm` calls use `p==2`, it makes sense for us to reduce the latency on this call. ```julia julia> using LinearAlgebra julia> A = rand(2,2); julia> @time norm(A); 0.247515 seconds (390.09 k allocations: 19.993 MiB, 33.57% gc time, 99.99% compilation time) # master 0.067201 seconds (121.24 k allocations: 6.067 MiB, 99.98% compilation time) # this PR ``` An example of an improvement in ttfx because of this: ```julia julia> A = rand(2,2); julia> @time A ≈ A; 0.556475 seconds (1.16 M allocations: 59.949 MiB, 24.14% gc time, 100.00% compilation time) # master 0.333114 seconds (899.85 k allocations: 46.574 MiB, 8.11% gc time, 99.99% compilation time) # this PR ``` --- stdlib/LinearAlgebra/src/generic.jl | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/stdlib/LinearAlgebra/src/generic.jl b/stdlib/LinearAlgebra/src/generic.jl index 20c58e593d3f6..21719c0c50127 100644 --- a/stdlib/LinearAlgebra/src/generic.jl +++ b/stdlib/LinearAlgebra/src/generic.jl @@ -669,11 +669,9 @@ julia> norm(hcat(v,v), Inf) == norm(vcat(v,v), Inf) != norm([v,v], Inf) true ``` """ -Base.@constprop :aggressive function norm(itr, p::Real=2) +Base.@constprop :aggressive function norm(itr, p::Real) isempty(itr) && return float(norm(zero(eltype(itr)))) - v, s = iterate(itr) - !isnothing(s) && !ismissing(v) && v == itr && throw(ArgumentError( - "cannot evaluate norm recursively if the type of the initial element is identical to that of the container")) + norm_recursive_check(itr) if p == 2 return norm2(itr) elseif p == 1 @@ -688,6 +686,18 @@ Base.@constprop :aggressive function norm(itr, p::Real=2) normp(itr, p) end end +# Split into a separate method to reduce latency in norm(x) calls (#56330) +function norm(itr) + isempty(itr) && return float(norm(zero(eltype(itr)))) + norm_recursive_check(itr) + norm2(itr) +end +function norm_recursive_check(itr) + v, s = iterate(itr) + !isnothing(s) && !ismissing(v) && v == itr && throw(ArgumentError( + "cannot evaluate norm recursively if the type of the initial element is identical to that of the container")) + return nothing +end """ norm(x::Number, p::Real=2) @@ -808,7 +818,7 @@ julia> opnorm(A, 1) 5.0 ``` """ -Base.@constprop :aggressive function opnorm(A::AbstractMatrix, p::Real=2) +Base.@constprop :aggressive function opnorm(A::AbstractMatrix, p::Real) if p == 2 return opnorm2(A) elseif p == 1 @@ -819,6 +829,7 @@ Base.@constprop :aggressive function opnorm(A::AbstractMatrix, p::Real=2) throw(ArgumentError(lazy"invalid p-norm p=$p. Valid: 1, 2, Inf")) end end +opnorm(A::AbstractMatrix) = opnorm2(A) """ opnorm(x::Number, p::Real=2)