From 2d8b708f4c077b6cd610e8ce13db4636aa922d97 Mon Sep 17 00:00:00 2001 From: ssikdar1 Date: Tue, 7 Jan 2020 03:12:51 -0500 Subject: [PATCH] #34234 normalize(a) for multidimensional arrays (#34239) * 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 --- NEWS.md | 2 +- stdlib/LinearAlgebra/src/generic.jl | 54 +++++++++++++++++----------- stdlib/LinearAlgebra/test/generic.jl | 24 +++++++++++++ 3 files changed, 59 insertions(+), 21 deletions(-) diff --git a/NEWS.md b/NEWS.md index 139c9238de7f1..ba021b1d4adca 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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 diff --git a/stdlib/LinearAlgebra/src/generic.jl b/stdlib/LinearAlgebra/src/generic.jl index 0b5c1af380257..fd5da53c9ba87 100644 --- a/stdlib/LinearAlgebra/src/generic.jl +++ b/stdlib/LinearAlgebra/src/generic.jl @@ -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 @@ -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 diff --git a/stdlib/LinearAlgebra/test/generic.jl b/stdlib/LinearAlgebra/test/generic.jl index 407aa2e8423f7..933029f540f2c 100644 --- a/stdlib/LinearAlgebra/test/generic.jl +++ b/stdlib/LinearAlgebra/test/generic.jl @@ -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 @@ -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))