# I am confused using tanh(M)

Hello,
I am pritty new to Julia and try to find my first steps. I am a bit confused now.
In Python I had this (simplyfied) piece of code:

``````import numpy as np
a = [[1,2], [3,4]]
M = np.array(a)
np.tanh(M)
``````

It brings me the expected result:

``````array([[0.76159416, 0.96402758],
[0.99505475, 0.9993293 ]])
``````

Now I try my luck with Julia:

``````M = [1 2
3 4]
tanh(M)
``````

Output:

``````2×2 Array{Float64,2}:
-0.0320733  0.472079
0.708118   0.676045
``````

My question, what is calculated here?

However if I do:

``````tanh.(M)
``````

I get the expected result again. I think I understand concept of “.” as the elementwise operator. But I thought tanh() and similar are always elementwise. If I am wrong, what is tanh(M) without “.” calculating?
Thanks
Floriano

In julia, any operation on a matrix will not be element-wise unless you have a `.`. It turns out that for square matrices, you can take a hyperbolic tangent of a matrix. That’s the result you are seeing when you type `tanh(M)`.

6 Likes

thank you

``````julia> tanh(1+2im)
1.1667362572409197 - 0.24345820118572525im

julia> tanh([1 -2; 2 1])
2×2 Array{Float64,2}:
1.16674   0.243458
-0.243458  1.16674
``````
4 Likes

As Oscar_Smith said, the component-wise `tanh` and (diagonalizable, square) matrix `tanh` are different in general. The matrix `tanh` is derived from a power series expansion of the scalar tanh, where the scalar powers are replaced with matrix powers. It can be computed by taking the eigenvalue decomposition `U*diagm(evals)*U'` of the matrix, taking the component-wise `tanh` on the eigenvalues, and then reconstructing:

``````julia> A = [1 -2; 2 1]
2×2 Array{Int64,2}:
1  -2
2   1

julia> using LinearAlgebra

julia> evals, U = eigen(A)
Eigen{Complex{Float64},Complex{Float64},Array{Complex{Float64},2},Array{Complex{Float64},1}}
eigenvalues:
2-element Array{Complex{Float64},1}:
1.0 - 2.0000000000000004im
1.0 + 2.0000000000000004im
eigenvectors:
2×2 Array{Complex{Float64},2}:
0.0+0.707107im        0.0-0.707107im
-0.707107-0.0im       -0.707107+0.0im

julia> U*diagm(evals)*U'-A
2×2 Array{Complex{Float64},2}:
-2.22045e-16+0.0im  -4.44089e-16+0.0im
4.44089e-16+0.0im   2.22045e-16+0.0im

julia> U*diagm(tanh.(evals))*U'-tanh(A)
2×2 Array{Complex{Float64},2}:
-4.44089e-16+0.0im  2.22045e-16+0.0im
-2.498e-16+0.0im          0.0+0.0im

julia> tanh.(A)-tanh(A)
2×2 Array{Float64,2}:
-0.405142  -1.20749
1.20749   -0.405142

``````

The last line gives an example where the component-wise and matrix versions of `tanh` differ.

1 Like

Provided that the matrix is diagonalizable, of course.

1 Like

Yes, thanks for reminding us that the power series derivation of `tanh(A)` requires diagonalizability of `A`. But my demo used the decomposition `A=U*diagm(evals)*U'`, so we need to further assume that `A` is unitarily diagonalizable for that to work, i.e., the transpose `U'` is also the inverse of `U`, which occurs when `A` is normal (`A*A' == A'*A`). It’s sufficient that `A` is (real) symmetric for normality to hold.