"vecnorm" : column/row-wise norm


#1

I have a 2D array, and want to treat each row (or column) as a vector and find norm of it

a = [1 2 3 ; 4 5 6]
a
2×3 Array{Int64,2}:
 1  2  3
 4  5  6

The following is what I have tried and their results.

Both norm.(a) and vecnorm.(a) gives

2×3 Array{Int64,2}:
 1  2  3
 4  5  6

While norm(a) gives 9.508032000695724 and vecnorm(a) gives 9.539392014169456

For now, to get what I want, I have to do the following

a = [[1,2,3],[4, 5, 6]]

a
2-element Array{Array{Int64,1},1}:
 [1, 2, 3]
 [4, 5, 6]

Then, both norm. and vecnorm. works

vecnorm.(a)
norm.(a)

gives

2-element Array{Float64,1}:
 3.74166
 8.77496

I would like to know how can I have something similar to this matlab example directly from a 2D array.


#2

There is currently no direct function to take the norm of a 2D array by dimension. The easiest way would probably be to do either of the 2 functions below:

julia> A = rand(5,4);
                                         
julia> f1(A,d=1) = sqrt.(sum(abs2,A,d))
f1 (generic function with 1 method)               
                                                  
julia> f2(A) = [vecnorm(A[:,i]) for i=1:size(A,2)]
f2 (generic function with 1 method)               

julia> @btime f1($A)
  128.103 ns (2 allocations: 224 bytes)
1×4 Array{Float64,2}:
 1.08137  1.1315  1.23828  1.35529

julia> @btime f2($A)                    
  327.377 ns (11 allocations: 736 bytes)
4-element Array{Float64,1}:             
 1.08137                                
 1.1315                                 
 1.23828                                
 1.35529                                

f1 is faster because it acts mostly in place. It also allows you to change the dimension more easily.


#3

While f1 is likely to always be the best, f2 can be made slightly faster by replacing A[:,i] with @view A[:,i] to avoid the copy operation.

Another alternative is to use mapslices which applies a specified function to slices through the matrix (much like is being done manually with f2)

julia> f3(A) = mapslices(norm, A, dims=1)
f3 (generic function with 1 method)

julia> @btime f3($A)
  5.358 μs (73 allocations: 3.22 KiB)
1×4 Array{Float64,2}:
 0.824996  1.40544  1.19838  1.6095

but it is painfully slow in comparison with either f1 or f2.


#4

Thanks for your additional info. I also found this discussion. Good to learn another new thing.