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

```
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.