Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#34234 normalize(a) for multidimensional arrays #34239

Merged
merged 10 commits into from
Jan 7, 2020
54 changes: 34 additions & 20 deletions stdlib/LinearAlgebra/src/generic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1582,39 +1582,39 @@ function isapprox(x::AbstractArray, y::AbstractArray;
end

"""
normalize!(v::AbstractVector, p::Real=2)
normalize!(a::AbstractArray, p::Real=2)

Normalize the vector `v` in-place so that its `p`-norm equals unity,
i.e. `norm(v, p) == 1`.
Normalize the array `a` in-place so that its `p`-norm equals unity,
i.e. `norm(a, p) == 1`.
See also [`normalize`](@ref) and [`norm`](@ref).
"""
function normalize!(v::AbstractVector, p::Real=2)
nrm = norm(v, p)
__normalize!(v, nrm)
function normalize!(a::AbstractArray, p::Real=2)
nrm = norm(a, p)
__normalize!(a, nrm)
end

@inline function __normalize!(v::AbstractVector, nrm::AbstractFloat)
@inline function __normalize!(a::AbstractArray, nrm::AbstractFloat)
# The largest positive floating point number whose inverse is less than infinity
δ = inv(prevfloat(typemax(nrm)))

if nrm ≥ δ # Safe to multiply with inverse
invnrm = inv(nrm)
rmul!(v, invnrm)
rmul!(a, invnrm)

else # scale elements to avoid overflow
εδ = eps(one(nrm))/δ
rmul!(v, εδ)
rmul!(v, inv(nrm*εδ))
rmul!(a, εδ)
rmul!(a, inv(nrm*εδ))
end

v
a
end

"""
normalize(v::AbstractVector, p::Real=2)
normalize(a::AbstractArray, p::Real=2)

Normalize the vector `v` so that its `p`-norm equals unity,
i.e. `norm(v, p) == 1`.
Normalize the array `a` so that its `p`-norm equals unity,
i.e. `norm(a, p) == 1`.
See also [`normalize!`](@ref) and [`norm`](@ref).

# Examples
Expand All @@ -1638,15 +1638,29 @@ julia> c = normalize(a, 1)

julia> norm(c, 1)
1.0

julia> a = [[1 2 4] ; [1 2 4]]
ssikdar1 marked this conversation as resolved.
Show resolved Hide resolved
2×3 Array{Int64,2}:
1 2 4
1 2 4

julia> norm(a)
6.48074069840786

julia> normalize(a)
2×3 Array{Float64,2}:
0.154303 0.308607 0.617213
0.154303 0.308607 0.617213

```
"""
function normalize(v::AbstractVector, p::Real = 2)
nrm = norm(v, p)
if !isempty(v)
vv = copy_oftype(v, typeof(v[1]/nrm))
return __normalize!(vv, nrm)
function normalize(a::AbstractArray, p::Real = 2)
nrm = norm(a, p)
if !isempty(a)
aa = copy_oftype(a, typeof(first(a)/nrm))
stevengj marked this conversation as resolved.
Show resolved Hide resolved
return __normalize!(aa, nrm)
else
T = typeof(zero(eltype(v))/nrm)
T = typeof(zero(eltype(a))/nrm)
return T[]
end
end
12 changes: 12 additions & 0 deletions stdlib/LinearAlgebra/test/generic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,18 @@ end
end
end

@testset "normalize for multidimensional arrays" begin
arr = [ [1.0 0.0]; [0.0 1.0] ]
ssikdar1 marked this conversation as resolved.
Show resolved Hide resolved
@test normalize(arr) == normalize!(copy(arr))

arr = [
[1.0 0.0 0.0];
[0.0 1.0 0.0]
]
ssikdar1 marked this conversation as resolved.
Show resolved Hide resolved
@test normalize(arr) == normalize!(copy(arr))

stevengj marked this conversation as resolved.
Show resolved Hide resolved
end

@testset "Issue #30466" begin
@test norm([typemin(Int), typemin(Int)], Inf) == -float(typemin(Int))
@test norm([typemin(Int), typemin(Int)], 1) == -2float(typemin(Int))
Expand Down