Compute the logarithm of a matrix

There have already been challenges about computing the exponential of a matrix , as well as computing the natural logarithm of a number. This challenge is about finding the (natural) logarithm of matrix.

You task is to write a program of function that takes an invertible $$\n \times n\$$ matrix $$\A\$$ as input and returns the matrix logarithm of that matrix. The matrix logarithm of a matrix $$\ A\$$ is defined (similar to the real logarithm) to be a matrix $$\L\$$ with $$\ exp(L) = A\$$.

Like the complex logarithm the matrix logarithm is not unique, you can choose to return any of the possible results for a given matrix.

Examples (rounded to five significant digits):

log( [[ 1,0],[0, 1]] ) = [[0,0], [0,0]]
log( [[ 1,2],[3, 4]] ) = [[-0.3504 + 2.3911i, 0.9294 - 1.0938i], [1.3940 - 1.6406i, 1.04359 + 0.75047i]]
log( [[-1,0],[0,-1]] ) = [[0,pi],[-pi,0]] // exact
log( [[-1,0],[0,-1]] ) = [[0,-pi],[pi,0]] // also exact
log( [[-1,0],[0,-1]] ) = [[pi*i,0],[0,pi*i]] // also exact

log( [[-1,0,0],[0,1,0],[0,0,2]] ) = [[3.1416i, 0, 0], [0, 0, 0], [0, 0, 0.69315]]
log( [[1,2,3],[4,5,4],[3,2,1]] ) = [[0.6032 + 1.5708i, 0.71969, -0.0900 - 1.5708i],[1.4394, 0.87307, 1.4394],[-0.0900 - 1.5708i, 0.71969, 0.6032 + 1.5708i]]


If you want to try out more examples use the function digits 5 matrix logarithm followed by a matrix in Wolfram Alpha

Rules:

• You can Input/Output matrices as nested lists
• You can Input/Output complex numbers as pairs of real numbers
• You can assume the logarithm of the input matrix exists
• Your result should be accurate up to at least 5 significant (decimal) digits
• You only have to handle matrices of sizes $$\2\times2\$$ and $$\3\times3\$$
• You program may return different results when called multiple times on the same input as long as all of them are correct
• This is the shortest solution (per language) wins

Python + scipy, 30 bytes

from scipy.linalg import*
logm

• Should this count as builtin?
– l4m2
Jul 30, 2023 at 14:28
• @l4m2 Yes. But it was posted before I added the rule against built-in solutions. Jul 30, 2023 at 14:34

R, 61 bytes

function(m,e=eigen(m))e$ve%*%diag(log(e$va+0i))%*%solve(e\$ve)


Try it online!

Uses this method from Wikipedia for finding the logarithm of a diagonalizable (and so invertible) matrix.

R, 105 bytes*

(*)Only for matrices M for which norm(M-I)<1

function(m,i=diag(nrow(m)),R=Reduce)R(+,lapply(1:1e3,function(n)-(-1)^n*R(%*%,rep(list(m-i),n),i)/n))


Try it online!

I didn't initially spot the 'invertible' in the challenge specification, so tried to use this other method from Wikipedia which works for non-diagonalizable matrices M, but with the restriction that norm(M-I) must be <1.
In many cases, this can be extended to matrices with larger-valued elements, using L == log( M %*% X) == log( M ) + log( X ): in these cases, we divide the matrix M by a sufficiently-large power-of-2 l, and add l times the log of 2x the identity matrix to the result.
Nevertheless, this is not fully-general, and fails for matrices M that cannot be scaled to satisfy norm(M-I)<1 (for instance, the matrix [[1,2],[3,4]]).

R, 158 bytes*

(*)Only for matrices M for which norm(M*l-I)<1 for some value l

function(m,i=diag(nrow(m)),l=log2(norm(m)*2)%/%1,f=function(m,R=Reduce)R(+,lapply(1:1e3,function(n)-(-1)^n*R(%*%,rep(list(m-i),n),i)/n)))f(m/2^l)+l*f(i*2)


Try it online!

Scala + jeigen, 22 bytes

import jeigen.*
_.mlog


Try it online

Octave, 29 bytes

@(a)(a^1e-9-eye(size(a)))*1e9


Try it online!

Built-in solutions

Wolfram Language (Mathematica), 9 bytes

MatrixLog


Try it online!

Octave, 4 bytes

logm


Try it online!