Skip to content

Commit

Permalink
Add one-arg norm method (#56330)
Browse files Browse the repository at this point in the history
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
```
  • Loading branch information
jishnub authored Oct 29, 2024
1 parent 710e1f9 commit cb757c4
Showing 1 changed file with 16 additions and 5 deletions.
21 changes: 16 additions & 5 deletions stdlib/LinearAlgebra/src/generic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down

0 comments on commit cb757c4

Please sign in to comment.