Skip to content

Commit

Permalink
JuliaLang#34234 normalize(a) for multidimensional arrays (JuliaLang#3…
Browse files Browse the repository at this point in the history
…4239)

* Add support normalize multi dim arrays

* remove trailing whitespace from test

* var name v => a for inner function

* Update normalize tests

Case for OffsetArray where A[1] would fail but
first(A) would not. Also some more test cases to
compare with the vector case

* add NEWS item

* make docstring example w/ array  more julia-thonic

* reduce redundant test cases

* add test for normalize on Int64 array

* add 0 1 and high dim test cases
  • Loading branch information
ssikdar1 authored and andreasnoack committed Jan 7, 2020
1 parent 8e6a2ae commit 8f9dd5d
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 21 deletions.
2 changes: 1 addition & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ Standard library changes


#### LinearAlgebra

* The BLAS submodule now supports the level-2 BLAS subroutine `hpmv!` ([#34211]).
* `normalize` now supports multidimensional arrays ([#34239])

#### Markdown

Expand Down
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]
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))
return __normalize!(aa, nrm)
else
T = typeof(zero(eltype(v))/nrm)
T = typeof(zero(eltype(a))/nrm)
return T[]
end
end
24 changes: 24 additions & 0 deletions stdlib/LinearAlgebra/test/generic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ module TestGeneric
using Test, LinearAlgebra, Random

const BASE_TEST_PATH = joinpath(Sys.BINDIR, "..", "share", "julia", "test")

isdefined(Main, :Quaternions) || @eval Main include(joinpath($(BASE_TEST_PATH), "testhelpers", "Quaternions.jl"))
using .Main.Quaternions

isdefined(Main, :OffsetArrays) || @eval Main include(joinpath($(BASE_TEST_PATH), "testhelpers", "OffsetArrays.jl"))
using .Main.OffsetArrays


Random.seed!(123)

n = 5 # should be odd
Expand Down Expand Up @@ -248,6 +253,25 @@ end
end
end

@testset "normalize for multidimensional arrays" begin

for arr in (
fill(10.0, ()), # 0 dim
[1.0], # 1 dim
[1.0 2.0 3.0; 4.0 5.0 6.0], # 2-dim
rand(1,2,3), # higher dims
rand(1,2,3,4),
OffsetArray([-1,0], (-2,)) # no index 1
)
@test normalize(arr) == normalize!(copy(arr))
@test size(normalize(arr)) == size(arr)
@test axes(normalize(arr)) == axes(arr)
@test vec(normalize(arr)) == normalize(vec(arr))
end

@test typeof(normalize([1 2 3; 4 5 6])) == Array{Float64,2}
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

0 comments on commit 8f9dd5d

Please sign in to comment.