"vecnorm" : column/row-wise norm

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.

1 Like

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.

5 Likes

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.

1 Like

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

Maybe it is more intuitive think about list comprehension in this kind of problem (any problem with operation across matrices and vectors, really).
My favorite way to get a list of norms of the vectors represented as lines in a matrix is :
norms = [norm(m[i,:]) for i=1:size(m)[1]]
It is not super compact as it would be in matlab, but perhaps more understandable as you can see that you are calculating some norm for each line of the matrix and getting a list of those norms. When I do this in matlab I always have to check if I’m calculating the norm “vertically” or “horizontally” in the matrix to make sure I’ll get what I want.

Or just norm.(eachcol(m))

6 Likes