Function Repository Resource:

ComputeMatrixFunction

Source Notebook

Compute a function of a square matrix

Contributed by: Arturas Acus

ResourceFunction["ComputeMatrixFunction"][fun,mat]

computes the function fun of matrix mat.

Details and Options

mat must be a square matrix containing exact numeric or symbolic entries.
The function fun should be a complex-valued function. For example, Power is supported, but MatrixPower is not.
ResourceFunction["ComputeMatrixFunction"] is substantially similar to the built-in MatrixFunction. For symbolic matrices it is often both faster and can give a more concide result.
The matrix function is computed using the matrix minimal polynomial or any other polynomial that annihilates the matrix mat.
Arbitrary differentiable functions of a matrix can be computed provided they are well behaved on all matrix eigenvalues.
ResourceFunction["ComputeMatrixFunction"] supports the option "MinimalPolynomial" (default Automatic) which specifies a polynomial that annihilates the matrix. This need not actually be the minimal polynomial e.g. it could instead be the characteristic polynomial. If left unspecified, ResourceFunction["ComputeMatrixFunction"] will compute the minimal polynomial. If a polynomial is specified that does not annihilate the input matrix the computation will return wrong answer with no warning.
With the option "OutputSpectralBasis"True (default is False) ResourceFunction["ComputeMatrixFunction"] will append to the output the computed generalized spectral basis (i.e. list of polymials). This basis bears a relation to the Jordan decomposition insofar as it encode information about the generalized eigenvectors. Some details can be gleaned from the article by Garret Sobczyk linked in the references section.
With the option "FunctionDomain"Reals (default is Complexes), ComputeMatrixFunction will attempt to rewrite the function of real matrix mat again as a real matrix. In general this is possible only for specific functions and matrices. For example, for the exponent function of real matrix. The algorithm attempts to sum the function over a set of complex conjugate roots pairwise and then calls ComplexExpand on each partial sum.
ResourceFunction["ComputeMatrixFunction"] is intended to work with exact input and will not handle matrices containing approximate numbers.
ResourceFunction["ComputeMatrixFunction"] is based on computation of matrix spectra and, therefore, has the same limitations as the system command MatrixFunction. In particular the function fun must be differentiable and well behaved at matrix eigenvalues. The algorithm of ComputeMatrixFunction don't require polymial reduction and is advantageous over MatrixFunction in the cases when matrix minimal polynomial includes irreducible polynomial of high degree.
ResourceFunction["ComputeMatrixFunction"] by default will return a complex valued answer for real valued matrices. This happens because the eigenvalue equation in general is solved in the complex domain. The option "FunctionDomain"Reals attempts to rewrite answer in a real form. In particular it separates real valued and complex valued roots and manipulate the latter in complex conjugate pairs. Then ComplexExpand function is called on each transformed pair. Only very a limited subset of functions (one of them is the exponential function) can be expressed in a real matrix form. The transformation procedure thus does not guarantee that a real form will be found. This nondefault setting should be used with caution. In particular, if the matrix minimal polynomial includes a high degree irreducible polynomial, the computation of a real form can take a very long time.

Examples

Basic Examples (2) 

Cube a square matrix:

In[1]:=
ResourceFunction["ComputeMatrixFunction"][Power[#, 3] &, ({
   {1, 2 I},
   {3 + I, 0}
  })]
Out[1]=

Check the result:

In[2]:=
MatrixPower[({
   {1, 2 I},
   {3 + I, 0}
  }), 3]
Out[2]=

Invert a matrix:

In[3]:=
ResourceFunction["ComputeMatrixFunction"][#^(-1) &, ({
   {1, 0},
   {3 + 4 I, 5}
  })]
Out[3]=

Check the result:

In[4]:=
Inverse[({
   {1, 0},
   {3 + 4 I, 5}
  })]
Out[4]=

Scope (9) 

Arbitrary differentiable functions of a matrix can be computed provided that the function is well behaved on the matrix eigenvalues:

In[5]:=
input = ({
   {1, 2 I},
   {3 + 4 I, 5}
  })
Out[5]=
In[6]:=
inverseOfMatrix = ResourceFunction["ComputeMatrixFunction"][#^(-1) &, input]
Out[6]=

Check that the answer is correct:

In[7]:=
inverseOfMatrix . input // Simplify // MatrixForm
Out[7]=

Compute a 10-th power of matrix:

In[8]:=
input = ({
   {1, 2 I},
   {3 + 4 I, 5}
  })
Out[8]=
In[9]:=
power10OfMatrix = ResourceFunction["ComputeMatrixFunction"][#^(10) &, input]
Out[9]=

Check that the computation is correct:

In[10]:=
power10OfMatrix - (Dot @@ Table[input, {10}]) // Expand // Simplify
Out[10]=

A defective matrix:

In[11]:=
input = ({
    {2, 1},
    {0, 2}
   });

Compute its logarithm:

In[12]:=
logOfMatrix = ResourceFunction["ComputeMatrixFunction"][Log, input]
Out[12]=

Check that computation is correct:

In[13]:=
ResourceFunction["ComputeMatrixFunction"][Exp, logOfMatrix] // MatrixForm
Out[13]=

This matrix is not diagonalizable:

In[14]:=
DiagonalizableMatrixQ[input]
Out[14]=

A 2 dimensional matrix:

In[15]:=
input = ({
   {2, 1},
   {0, 2}
  })
Out[15]=

Compute a composition where the second function inverts the first:

In[16]:=
ResourceFunction["ComputeMatrixFunction"][Exp[Log[#]] &, input]
Out[16]=

A matrix function of small matrix can yield a long result:

In[17]:=
(logOfMatrix = ResourceFunction["ComputeMatrixFunction"][Exp, input = {{6, 2, 9, 9}, {0, 3, 8, 2}, {6, 4, 2, 7}, {2, 1, 8, 9}}]) // LeafCount
Out[17]=

For a multivalued function (for example, fractional power, inverse trigonometric, etc) a single matrix is returned:

In[18]:=
fractionalPowerOfMatrix = ResourceFunction["ComputeMatrixFunction"][#^(-1/2) &, input = {{-2, 1, -1 - I, -1}, {-1 - 2 I, 2 I, -1, 1 - I}, {1 - I, 1, -2, 1}, {1, -1 - I, -1 + 2 I, -2 I}}] // FullSimplify
Out[18]=

A check:

In[19]:=
Inverse[fractionalPowerOfMatrix . fractionalPowerOfMatrix // FullSimplify] // Simplify
Out[19]=

ComputeMatrixFunction is implemented to handle defective (nondiagonalizable) matrices:

In[20]:=
(input = {{0, 0, 0, -2, -2, 0, 2, -1}, {0, -2, 4, 2, -2, 2, 5, 2}, {4,
      0, 0, 2, 4, -3, -2, 6}, {-2, -2, 2, -2, -1, -4, 0, 2}, {0, -2, 2, -1, 0, 2, -2, -2}, {0, -4, 1, 2, -2, 2, -4, 0}, {0, 1, 0, 0, 2, 0, -4, 0}, {-1, 0, -2, 4, -2, 4, -4, -2}}) // MatrixForm
Out[20]=

The matrix is defective:

In[21]:=
DiagonalizableMatrixQ[input]
Out[21]=

So the minimal polynomial of this matrix has a factor of nontrivial multiplicity:

In[22]:=
minPoly = ResourceFunction["MatrixMinimalPolynomial"][input, x] // Factor
Out[22]=

The minimal polynomial is a polynomial of lowest degree that annihilates the matrix:

In[23]:=
ResourceFunction["MatrixPolynomial"][Function @@ {x, minPoly}, input] // MatrixForm
Out[23]=

Compute the exponential of this matrix:

In[24]:=
Timing[matexp = ResourceFunction["ComputeMatrixFunction"][Exp, input];]
Out[24]=

Check the size:

In[25]:=
LeafCount[matexp]
Out[25]=

Symbolic matrices can be input as well:

In[26]:=
minPoly = ResourceFunction["MatrixMinimalPolynomial"][input = \!\(\*
TagBox[
RowBox[{"(", "", GridBox[{
{
RowBox[{"6", " ", "r"}], 
RowBox[{
RowBox[{
RowBox[{"-", "15"}], " ", 
SuperscriptBox["r", "2"]}], "-", 
RowBox[{"3", " ", 
SuperscriptBox["y", "2"]}]}], "1", "0", "0", "0"},
{"1", "0", "0", "0", "0", "0"},
{"0", 
RowBox[{
RowBox[{"20", " ", 
SuperscriptBox["r", "3"]}], "+", 
RowBox[{"12", " ", "r", " ", 
SuperscriptBox["y", "2"]}]}], "0", 
RowBox[{
RowBox[{
RowBox[{"-", "15"}], " ", 
SuperscriptBox["r", "4"]}], "-", 
RowBox[{"18", " ", 
SuperscriptBox["r", "2"], " ", 
SuperscriptBox["y", "2"]}], "-", 
RowBox[{"3", " ", 
SuperscriptBox["y", "4"]}]}], "1", "0"},
{"0", "1", "0", "0", "0", "0"},
{"0", "0", "0", 
RowBox[{
RowBox[{"6", " ", 
SuperscriptBox["r", "5"]}], "+", 
RowBox[{"12", " ", 
SuperscriptBox["r", "3"], " ", 
SuperscriptBox["y", "2"]}], "+", 
RowBox[{"6", " ", "r", " ", 
SuperscriptBox["y", "4"]}]}], "0", 
RowBox[{
RowBox[{"-", 
SuperscriptBox["r", "6"]}], "-", 
RowBox[{"3", " ", 
SuperscriptBox["r", "4"], " ", 
SuperscriptBox["y", "2"]}], "-", 
RowBox[{"3", " ", 
SuperscriptBox["r", "2"], " ", 
SuperscriptBox["y", "4"]}], "-", 
SuperscriptBox["y", "6"]}]},
{"0", "0", "0", "1", "0", "0"}
},
GridBoxAlignment->{"Columns" -> {{Center}}, "ColumnsIndexed" -> {}, "Rows" -> {{Baseline}}, "RowsIndexed" -> {}},
GridBoxSpacings->{"Columns" -> {
Offset[0.27999999999999997`], {
Offset[0.7]}, 
Offset[0.27999999999999997`]}, "ColumnsIndexed" -> {}, "Rows" -> {
Offset[0.2], {
Offset[0.4]}, 
Offset[0.2]}, "RowsIndexed" -> {}}], "", ")"}],
Function[BoxForm`e$, 
MatrixForm[
         SparseArray[
          Automatic, {6, 6}, 0, {1, {{0, 3, 4, 7, 8, 10, 11}, {{1}, {2}, {3}, {1}, {
             2}, {4}, {5}, {2}, {6}, {4}, {
             4}}}, {6 $CellContext`r, (-15) $CellContext`r^2 - 3 $CellContext`y^2, 1, 1, 20 $CellContext`r^3 + (
               12 $CellContext`r) $CellContext`y^2, (-15) $CellContext`r^4 - (
              18 $CellContext`r^2) $CellContext`y^2 - 3 $CellContext`y^4, 1, 1, -$CellContext`r^6 - (3 $CellContext`r^4) $CellContext`y^2 - (
              3 $CellContext`r^2) $CellContext`y^4 - $CellContext`y^6,
              6 $CellContext`r^5 + (
               12 $CellContext`r^3) $CellContext`y^2 + (
               6 $CellContext`r) $CellContext`y^4, 1}}]]]]\), x] // Factor // Normal
Out[26]=

The minimal polynomial has roots with multiplicity greater that one, i.e. the matrix is defective:

In[27]:=
DiagonalizableMatrixQ[input]
Out[27]=

Since minimal polynomial was already computed, we can help ComputeMatrixFunction by providing a computed matrix polynomial:

In[28]:=
(expOfMatrix = ResourceFunction["ComputeMatrixFunction"][Exp, input, "MinimalPolynomial" -> Evaluate[(Function[x, #] &[minPoly])]]) // LeafCount
Out[28]=

Compute minimal polynomial for the matrix input*t:

In[29]:=
minPolyt = ResourceFunction["MatrixMinimalPolynomial"][input*t, x] // Factor // Normal
Out[29]=

Check expOfMatrix using the property of the exponential function to confirm the identity:

In[30]:=
(input . expOfMatrix - (D[
      ResourceFunction["ComputeMatrixFunction"][Exp, t*input, "MinimalPolynomial" -> Evaluate[(Function[x, #] &[minPolyt])]],
       t] /. {t -> 1})) // Together
Out[30]=

ComputeMatrixFunction will not work with sparse arrays/structures. Nevertheless, it can deal with larger matrices than MatrixFunction:

In[31]:=
input = \!\(\*
TagBox[
RowBox[{"(", "", GridBox[{
{"1", 
RowBox[{"-", "83"}], 
RowBox[{"-", "23"}], "43", 
RowBox[{"-", "56"}], "8", "16", "48", 
RowBox[{"-", "30"}]},
{"2", 
RowBox[{"-", "225"}], 
RowBox[{"-", "50"}], "89", 
RowBox[{"-", "140"}], "23", "52", "104", 
RowBox[{"-", "95"}]},
{"0", "475", "110", 
RowBox[{"-", "200"}], "300", 
RowBox[{"-", "50"}], 
RowBox[{"-", "100"}], 
RowBox[{"-", "225"}], "200"},
{
RowBox[{"-", "1"}], "131", "28", 
RowBox[{"-", "45"}], "81", 
RowBox[{"-", "16"}], 
RowBox[{"-", "35"}], 
RowBox[{"-", "55"}], "58"},
{
RowBox[{"-", "3"}], "12", "0", "5", "5", 
RowBox[{"-", "2"}], 
RowBox[{"-", "11"}], "0", "6"},
{"1", "295", "69", 
RowBox[{"-", "122"}], "186", 
RowBox[{"-", "33"}], 
RowBox[{"-", "64"}], 
RowBox[{"-", "137"}], "125"},
{
RowBox[{"-", "2"}], 
RowBox[{"-", "137"}], 
RowBox[{"-", "30"}], "58", 
RowBox[{"-", "84"}], "15", "26", "63", 
RowBox[{"-", "61"}]},
{"0", 
RowBox[{"-", "139"}], 
RowBox[{"-", "30"}], "49", 
RowBox[{"-", "86"}], "17", "36", "59", 
RowBox[{"-", "62"}]},
{
RowBox[{"-", "2"}], "245", "57", 
RowBox[{"-", "104"}], "155", 
RowBox[{"-", "23"}], 
RowBox[{"-", "52"}], 
RowBox[{"-", "119"}], "100"}
},
GridBoxAlignment->{"Columns" -> {{Center}}, "Rows" -> {{Baseline}}},
GridBoxSpacings->{"Columns" -> {
Offset[0.27999999999999997`], {
Offset[0.7]}, 
Offset[0.27999999999999997`]}, "Rows" -> {
Offset[0.2], {
Offset[0.4]}, 
Offset[0.2]}}], "", ")"}],
Function[BoxForm`e$, 
MatrixForm[BoxForm`e$]]]\);

The matrix is non-diagonalizable:

In[32]:=
DiagonalizableMatrixQ[input]
Out[32]=

Inverse trigonometric functions of a matrix are multi-valued; ComputeMatrixFunction returns only one of them:

In[33]:=
(arcsinOfMatrix = ResourceFunction["ComputeMatrixFunction"][ArcSin, input]) // LeafCount // AbsoluteTiming
Out[33]=

Verify the huge symbolic result numerically by computing the Sin function:

In[34]:=
N[ResourceFunction["ComputeMatrixFunction"][Sin, N[arcsinOfMatrix, 100]] - input, 30] // Chop
Out[34]=

Options (21) 

MinimalPolynomial (4) 

By default the minimal polynomial of matrix is computed using the primitive algorithm described in MatrixMinimalPolynomial; one can instead have the minimal polynomial computed externally.

Give a matrix:

In[35]:=
(input = {{5, 1, 0, 0, 0, 0, 0, 0}, {0, 5, 1, 0, 0, 0, 0, 0}, {0, 0, 5, 1, 0, 0, 0, 0}, {0, 0, 0, 5, 0, 0, 0, 0}, {0, 0, 0, 0, 2, 1, -1, 1}, {0, 0, 0, 0, -1, 4, 0, 0}, {0, 0, 0, 0, 0, 0, 3, -2}, {0, 0, 0, 0, 0, 0, 0, 1}}) // MatrixForm
Out[35]=

The computed minimal polynomial should be provided as a pure function:

In[36]:=
minPolyExternal = ResourceFunction["MatrixMinimalPolynomial"][input]
Out[36]=

We can use it inside ComputeMatrixFunction:

In[37]:=
(expOfMatrix = ResourceFunction["ComputeMatrixFunction"][Exp, input, "MinimalPolynomial" -> minPolyExternal] // Expand) // MatrixForm
Out[37]=

MatrixFunction returns the same result faster:

In[38]:=
(mmaExponent = MatrixFunction[Exp, input]) // MatrixForm
Out[38]=

FunctionDomain (5) 

An input matrix:

In[39]:=
(input = {{5, 0, 0, 0, -2, 0, 3, 3}, {0, -1, 0, 0, 0, 6, 3, -3}, {0, 0, 5, 0, 3, 3, -2, 0}, {0, 0, 0, -1, 3, -3, 0, 6}, {6, 0, 3, -3, 5, 0, 0, 0}, {0, -2, -3, -3, 0, -1, 0, 0}, {3, -3, 6, 0, 0, 0, 5,
      0}, {-3, -3, 0, -2, 0, 0, 0, -1}}) // MatrixForm
Out[39]=

Compute the matrix exponential in the (default) complex domain:

In[40]:=
(expOfMatrix = ResourceFunction["ComputeMatrixFunction"][Exp, input, "FunctionDomain" -> Complexes]) // LeafCount // AbsoluteTiming
Out[40]=

After numerical evaluation we see that negligible imaginary parts are present:

In[41]:=
N[expOfMatrix, 20]
Out[41]=

Compute the same function in the real domain:

In[42]:=
(expOfMatrixReal = ResourceFunction["ComputeMatrixFunction"][Exp, input, "FunctionDomain" -> Reals]) // LeafCount // AbsoluteTiming
Out[42]=

Numerical evaluation now shows no imaginary numeric fuzz:

In[43]:=
N[expOfMatrixReal, 20]
Out[43]=

OutputSpectralBasis (12) 

The spectral basis1 can be used to compute matrix functions. We illustrate this below, using it to replicate the computation of ComputeMatrixFunction.

Input a matrix:

In[44]:=
(input = {{5, 0, 0, 0, -2, 0, 3, 3}, {0, -1, 0, 0, 0, 6, 3, -3}, {0, 0, 5, 0, 3, 3, -2, 0}, {0, 0, 0, -1, 3, -3, 0, 6}, {6, 0, 3, -3, 5, 0, 0, 0}, {0, -2, -3, -3, 0, -1, 0, 0}, {3, -3, 6, 0, 0, 0, 5,
      0}, {-3, -3, 0, -2, 0, 0, 0, -1}}) // MatrixForm
Out[44]=

One can compute a given function of matrix along with the generalized spectral basis using option "OutputSpectralBasis"True:

In[45]:=
({expOfMatrix, spectralBasisLong} = ResourceFunction["ComputeMatrixFunction"][Exp, input, "OutputSpectralBasis" -> True]) // LeafCount
Out[45]=

The generalized spectral basis1 is presented as a list of the form {r,plist} where r is a root of the minimal polynomial and plist is a list of polynomials with length equal to the root multiplicity:

In[46]:=
(spectralBasis = Collect[spectralBasisLong[x], x, Together]) // Column
Out[46]=

Compute the minimal polynomial:

In[47]:=
ResourceFunction["MatrixMinimalPolynomial"][input, x] // Factor
Out[47]=

We see that root -1 has multiplicity 2 so the spectral basis for this root contains two polynomials:

In[48]:=
spectralBasis[[1]][[2]] // Length
Out[48]=

Once the spectral basis is known one can compute the matrix function in the following way. For an eigenvalue of multiplicity n we compute derivatives zero through n-1. Since maximal root multiplicity is 2, the zeroth and first derivatives suffice to handle all eigenvalues:

In[49]:=
thefunction = Exp;
maxMultiplicity = 2;
derivativeTable = Table[(1/Factorial[k])*
    D[thefunction[\[FormalLambda] + var], {var, k}], {k, maxMultiplicity - 1}] /. var -> 0
Out[50]=

Now compute the following sum:

In[51]:=
answerCommutativeVar = Collect[Sum[(thefunction[spectralBasis[[k]][[1]]]*
      spectralBasis[[k]][[2]][[1]] + Sum[(derivativeTable[[
          q - 1]] /. {\[FormalLambda] -> spectralBasis[[k]][[1]]})*
       spectralBasis[[k]][[2]][[q]], {q, 2, Length[spectralBasis[[k]][[2]]]}]), {k, Length[spectralBasis]}],
   x]
Out[51]=

First compute the diagonal part of matrix:

In[52]:=
diagonalPart = (answerCommutativeVar /. x -> 0)
Out[52]=

Then the off-diagonal part:

In[53]:=
nondiagonalPart = (answerCommutativeVar - diagonalPart)
Out[53]=

Compute matrix powers up the degree of answerCommutativeVar (7):

In[54]:=
allpowerRules = Prepend[Table[
   x^k -> (ResourceFunction["MatrixPolynomial"] @@ {(#^k &), input}), {k, 2, 7}], x -> input]
Out[54]=

After replacing formal variable x by the matrix (and similar for powers) we obtain the final answer:

In[55]:=
(answerManual = IdentityMatrix[Length[input]]*
     diagonalPart + (nondiagonalPart /. allpowerRules)) // LeafCount
Out[55]=

Check that it coincides with previously computed exponent of matrix:

In[56]:=
Simplify[expOfMatrix - answerManual] // MatrixForm
Out[56]=

The manually computed matrix function is considerably simpler due to manual simplification of the generalized spectral basis polynomials. Moreover, other functions of the same matrix can be computed using the same generalized spectral basis, so one can compute multiple function computation of the same matrix.

Properties and Relations (2) 

Define a matrix:

In[57]:=
mat = \!\(\*
TagBox[
RowBox[{"(", "", GridBox[{
{"2", "0", "0", "0"},
{"0", "2", "1", "0"},
{"0", "0", "2", "1"},
{"0", "0", "0", "2"}
},
GridBoxAlignment->{"Columns" -> {{Center}}, "Rows" -> {{Baseline}}},
GridBoxSpacings->{"Columns" -> {
Offset[0.27999999999999997`], {
Offset[0.7]}, 
Offset[0.27999999999999997`]}, "Rows" -> {
Offset[0.2], {
Offset[0.4]}, 
Offset[0.2]}}], "", ")"}],
Function[BoxForm`e$, 
MatrixForm[BoxForm`e$]]]\);

An arbitrary polynomial p for which p(A)=0, for example the characteristic polynomial, can be provided as a pure function:

In[58]:=
characteristicPolynomial = Function[{x}, #] &[Factor[CharacteristicPolynomial[mat, x]]]
Out[58]=

Also compute minimal polynomial:

In[59]:=
minimalPolynomial = Function[{x}, #] &[
  Factor[ResourceFunction["MatrixMinimalPolynomial"][mat, x]]]
Out[59]=

Compute the product of the characteristic and minimal polynomials:

In[60]:=
productPolynomial = Function[{x}, #] &[characteristicPolynomial[x]*minimalPolynomial[x]]
Out[60]=

Computation time increases with the degree of provided polynomial, since higher matrix powers get computed:

In[61]:=
{(theExp1 = ResourceFunction["ComputeMatrixFunction"][Exp, mat, "MinimalPolynomial" -> minimalPolynomial] // RepeatedTiming), (theExp2 = ResourceFunction["ComputeMatrixFunction"][Exp, mat, "MinimalPolynomial" -> characteristicPolynomial] // RepeatedTiming), (theExp3 = ResourceFunction["ComputeMatrixFunction"][Exp, mat, "MinimalPolynomial" -> productPolynomial] // RepeatedTiming)}
Out[61]=

In[62]:=
(input = {{0, 0, 0, -2, -2, 0, 2, -1}, {0, -2, 4, 2, -2, 2, 5, 2}, {4,
      0, 0, 2, 4, -3, -2, 6}, {-2, -2, 2, -2, -1, -4, 0, 2}, {0, -2, 2, -1, 0, 2, -2, -2}, {0, -4, 1, 2, -2, 2, -4, 0}, {0, 1, 0, 0, 2, 0, -4, 0}, {-1, 0, -2, 4, -2, 4, -4, -2}}) // MatrixForm
Out[62]=

ComputeMatrixFunction is similar to the built-in MatrixFunction but often yields a less complicated result than in a fraction of time:

In[63]:=
(expOfMatrix = ResourceFunction["ComputeMatrixFunction"][Exp, input]) // LeafCount // AbsoluteTiming
Out[63]=

Compare with MatrixFunction:

In[64]:=
(mmaExponent = MatrixFunction[Exp, input]) // LeafCount // AbsoluteTiming
Out[64]=

Numerical comparison of both results up to 100 digits takes over 10 minutes, so instead compare an arbitrary element (1,3):

In[65]:=
(N[expOfMatrix[[1, 3]], 100] - N[mmaExponent[[1, 3]], 100]) // AbsoluteTiming
Out[65]=

Possible Issues (2) 

A noninvertible matrix:

In[66]:=
mat0 = \!\(\*
TagBox[
RowBox[{"(", "", GridBox[{
{"0", "1", "0", "0"},
{"0", "2", "1", "0"},
{"0", "0", "2", "1"},
{"0", "0", "0", "2"}
},
GridBoxAlignment->{"Columns" -> {{Center}}, "Rows" -> {{Baseline}}},
GridBoxSpacings->{"Columns" -> {
Offset[0.27999999999999997`], {
Offset[0.7]}, 
Offset[0.27999999999999997`]}, "Rows" -> {
Offset[0.2], {
Offset[0.4]}, 
Offset[0.2]}}], "", ")"}],
Function[BoxForm`e$, 
MatrixForm[BoxForm`e$]]]\);

If the given function is not defined at matrix eigenvalues then the computation will fail:

In[67]:=
mat0Inv = ResourceFunction["ComputeMatrixFunction"][#^(-1) &, mat0]
Out[67]=

We can determine a problem by inserting formal function f:

In[68]:=
mat0f = ResourceFunction["ComputeMatrixFunction"][f, mat0]
Out[68]=

The algorithm tries to evaluate function and it's derivatives at points 0 and 2:

In[69]:=
Cases[mat0f, f[_] | Derivative[_][f][_], Infinity, Heads -> True] // DeleteDuplicates
Out[69]=

It is clear that the attempt to compute reciprocals 1/eigval at 0 produced the error.


ComputeMatrixFunction, like MatrixFunction, does not work with non-differentiable functions such as Abs:

In[70]:=
ResourceFunction[
 "ComputeMatrixFunction"][Abs, {{1., 1., 0.}, {0., 1., 1.}, {0., 0., 1.}}]
Out[70]=

The result is meaningless because Abs does not have a first or second derivative.

Publisher

Arturas Acus

Requirements

Wolfram Language 13.0 (December 2021) or above

Version History

  • 1.0.0 – 02 May 2025

Source Metadata

Related Resources

Author Notes

The implementation for matrices was obtained by transferring the results originally obtained for multivectors in Clifford geometric algebra (see link above). Hope that developers at Wolfram will incorporate this method in next release of Mathematica and this resource function will become obsolete.

License Information