Function Repository Resource:

MatrixMinimalPolynomial

Source Notebook

Compute the minimal polynomial of a square matrix

Contributed by: Jan Mangaldan and Daniel Lichtblau

ResourceFunction["MatrixMinimalPolynomial"][mat,x]

gives the minimal polynomial for the matrix mat in the variable x.

ResourceFunction["MatrixMinimalPolynomial"][mat]

gives the minimal polynomial as a pure function.

Details and Options

mat must be a square matrix that can contain numeric or symbolic entries.
The minimal polynomial of a square matrix mat is the monic (leading coefficient 1) polynomial of lowest degree that annihilates mat.
ResourceFunction["MatrixMinimalPolynomial"] takes an Extension option to allow the handling of algebraics in the input.
With the option Modulusn, the minimal polynomial is computed modulo n.
ResourceFunction["MatrixMinimalPolynomial"] is intended to work with exact input and will not handle matrices containing both approximate numbers and an extension field.

Examples

Basic Examples (3) 

Find the minimal polynomial of a numeric matrix:

In[1]:=
ResourceFunction["MatrixMinimalPolynomial"][\!\(\*
TagBox[
RowBox[{"(", "", GridBox[{
{"22", 
RowBox[{"-", "16"}]},
{"25", 
RowBox[{"-", "18"}]}
},
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$]]]\), x]
Out[1]=

Compute the minimal polynomial of a symbolic matrix:

In[2]:=
ResourceFunction["MatrixMinimalPolynomial"][\!\(\*
TagBox[
RowBox[{"(", "", GridBox[{
{"t1", "1", "0"},
{
RowBox[{"t1", "+", "t2"}], "2", "1"},
{"1", "3", 
RowBox[{"1", "+", 
RowBox[{"t1", " ", "t2"}]}]}
},
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$]]]\), x]
Out[2]=

Compute the minimal polynomial of a matrix modulo 2:

In[3]:=
mat = {{0, 1, 0, 0}, {1, 1, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 1}};
ResourceFunction["MatrixMinimalPolynomial"][mat, t, Modulus -> 2]
Out[4]=

Compute the minimal polynomial of that same matrix modulo 29:

In[5]:=
ResourceFunction["MatrixMinimalPolynomial"][mat, t, Modulus -> 29]
Out[5]=

Scope (6) 

Minimal polynomial of a matrix with complex entries:

In[6]:=
ResourceFunction["MatrixMinimalPolynomial"][\!\(\*
TagBox[
RowBox[{"(", "", GridBox[{
{"1", 
RowBox[{"2", " ", "I"}]},
{
RowBox[{"3", "+", 
RowBox[{"4", " ", "I"}]}], "5"}
},
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$]]]\), x]
Out[6]=

The polynomial variable need not be specified:

In[7]:=
ResourceFunction["MatrixMinimalPolynomial"][\!\(\*
TagBox[
RowBox[{"(", "", GridBox[{
{"t1", "1", "0"},
{
RowBox[{"t1", "+", "t2"}], "2", "1"},
{"1", "3", 
RowBox[{"1", "+", 
RowBox[{"t1", " ", "t2"}]}]}
},
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$]]]\)]
Out[7]=

The degree of a matrix minimal polynomial can be strictly lower than the matrix dimension:

In[8]:=
ResourceFunction["MatrixMinimalPolynomial"][\!\(\*
TagBox[
RowBox[{"(", "", GridBox[{
{"0", 
RowBox[{"-", "1"}], "1"},
{"1", "2", 
RowBox[{"-", "1"}]},
{"1", "1", "0"}
},
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$]]]\), t]
Out[8]=

Minimal polynomial of a large matrix with symbolic entries:

In[9]:=
ResourceFunction["MatrixMinimalPolynomial"][\!\(\*
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
Out[9]=

Minimal polynomial of a sparse matrix:

In[10]:=
sa = SparseArray[{{1, 3} -> 2, {2, 2} -> 3, {3, 1} -> 1, {4, 2} -> 5}, {4, 4}];
ResourceFunction["MatrixMinimalPolynomial"][sa, x]
Out[10]=

Minimal polynomial of a structured matrix:

In[11]:=
sya = SymmetrizedArray[{{1, 1} -> 2, {1, 2} -> 1}, {2, 2}, Symmetric[All]];
ResourceFunction["MatrixMinimalPolynomial"][sya, x]
Out[11]=

Options (5) 

Extension (4) 

Compute a minimal polynomial where some matrix elements depend on algebraic numbers:

In[12]:=
alg = {t1^2 + 1, t2^2 + t1};
mat = \!\(\*
TagBox[
RowBox[{"(", "", GridBox[{
{"t1", "1", "0"},
{
RowBox[{"t1", "+", "t2"}], "2", "1"},
{"1", "3", 
RowBox[{"1", "+", 
RowBox[{"t1", " ", "t2"}]}]}
},
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$]]]\);
minpoly = ResourceFunction["MatrixMinimalPolynomial"][mat, x, Extension -> alg]
Out[12]=

The algebraic relations can be interpreted as replacing t1 with 𝕚 and t2 with :

In[13]:=
(minpoly /. t2 -> Sqrt[-t1]) /. t1 -> I
Out[13]=

Compare this to a direct computation using these algebraic numbers explicitly:

In[14]:=
mat2 = (mat /. t2 -> Sqrt[-t1]) /. t1 -> I;
minpoly2 = Together[
  Simplify@ResourceFunction["MatrixMinimalPolynomial"][mat2, x], Extension -> {Sqrt[-I]}]
Out[14]=

This appears to be more complicated even after simplification, so show that they are the same:

In[15]:=
PossibleZeroQ[((minpoly /. t2 -> Sqrt[-t1]) /. t1 -> I) - minpoly2]
Out[15]=

Modulus (1) 

Specify a modulus for computing the minimal polynomial:

In[16]:=
alg = {t1^2 + 1, t2^2 + t1};
mat = \!\(\*
TagBox[
RowBox[{"(", "", GridBox[{
{"t1", "1", "0"},
{
RowBox[{"t1", "+", "t2"}], "2", "1"},
{"1", "3", 
RowBox[{"1", "+", 
RowBox[{"t1", " ", "t2"}]}]}
},
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$]]]\);
minpoly = ResourceFunction["MatrixMinimalPolynomial"][mat, x, Extension -> alg,
   Modulus -> Prime[1234]]
Out[16]=

Properties and Relations (6) 

For random matrices, the minimal and characteristic polynomials will often coincide:

In[17]:=
SeedRandom[1234];
mat = RandomInteger[{-10, 10}, {4, 4}];
ResourceFunction["MatrixMinimalPolynomial"][mat, x] === CharacteristicPolynomial[mat, x]
Out[17]=

Compute a characteristic polynomial for a matrix with all eigenvalues equal to 2 and with two Jordan blocks of lengths 1 and 3, respectively:

In[18]:=
mat2 = \!\(\*
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$]]]\);
Factor[CharacteristicPolynomial[mat2, x]]
Out[18]=

In this case, the minimal polynomial properly divides the characteristic polynomial:

In[19]:=
Factor[ResourceFunction["MatrixMinimalPolynomial"][mat2, x]]
Out[19]=

The minimal polynomial of a matrix annihilates the matrix:

In[20]:=
mat3 = \!\(\*
TagBox[
RowBox[{"(", "", GridBox[{
{"2", "1", 
RowBox[{"-", "3"}], 
RowBox[{"-", "1"}], "0", "1", 
RowBox[{"-", "3"}], "0"},
{"11", "8", 
RowBox[{"-", "6"}], 
RowBox[{"-", "15"}], "0", "15", 
RowBox[{"-", "2"}], 
RowBox[{"-", "2"}]},
{
RowBox[{"-", "11"}], 
RowBox[{"-", "7"}], "3", "15", "0", 
RowBox[{"-", "15"}], 
RowBox[{"-", "2"}], "2"},
{"0", "0", "1", 
RowBox[{"-", "1"}], "0", "0", "1", "0"},
{"6", "5", 
RowBox[{"-", "4"}], 
RowBox[{"-", "8"}], 
RowBox[{"-", "1"}], "9", 
RowBox[{"-", "1"}], 
RowBox[{"-", "1"}]},
{
RowBox[{"-", "12"}], 
RowBox[{"-", "8"}], "8", "14", "0", 
RowBox[{"-", "15"}], "4", "2"},
{"11", "7", 
RowBox[{"-", "4"}], 
RowBox[{"-", "15"}], "0", "15", "1", 
RowBox[{"-", "2"}]},
{
RowBox[{"-", "6"}], 
RowBox[{"-", "4"}], "3", "8", "0", 
RowBox[{"-", "8"}], "1", "1"}
},
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$]]]\);
mp[x_] = ResourceFunction["MatrixMinimalPolynomial"][mat3, x]
Out[20]=
In[21]:=
ResourceFunction["MatrixPolynomial"][mp, mat3] // Factor
Out[21]=

Compute the minimal polynomial of a matrix with integer entries using the resource function PolynomialSmithDecomposition:

In[22]:=
mat3 = \!\(\*
TagBox[
RowBox[{"(", "", GridBox[{
{
RowBox[{"-", "3"}], "7", 
RowBox[{"-", "6"}], 
RowBox[{"-", "1"}], "8", 
RowBox[{"-", "3"}], 
RowBox[{"-", "2"}]},
{"1", 
RowBox[{"-", "5"}], "8", 
RowBox[{"-", "3"}], 
RowBox[{"-", "5"}], "4", 
RowBox[{"-", "5"}]},
{"1", "3", 
RowBox[{"-", "4"}], "6", 
RowBox[{"-", "2"}], "0", "8"},
{
RowBox[{"-", "1"}], "11", 
RowBox[{"-", "12"}], "9", "3", 
RowBox[{"-", "3"}], "9"},
{
RowBox[{"-", "3"}], "11", 
RowBox[{"-", "12"}], "5", "8", 
RowBox[{"-", "4"}], "6"},
{
RowBox[{"-", "3"}], "2", "1", 
RowBox[{"-", "4"}], "4", "1", 
RowBox[{"-", "7"}]},
{"1", 
RowBox[{"-", "5"}], "6", 
RowBox[{"-", "2"}], 
RowBox[{"-", "4"}], "3", 
RowBox[{"-", "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$]]]\);
mp = ResourceFunction["PolynomialSmithDecomposition"][
    IdentityMatrix[Length[mat3]] x - mat3, x][[2, -1, -1]];
mp = Expand[mp/Coefficient[mp, x, Exponent[mp, x]]] // Factor
Out[22]=

Compare with the result of MatrixMinimalPolynomial:

In[23]:=
ResourceFunction["MatrixMinimalPolynomial"][mat3, x] // Factor
Out[23]=

The timings in a progression of closely related matrices over an algebraic extension of the rationals appears to approximately double in size for each jump of two in dimension (the actual complexity is polynomial, though not of low degree):

In[24]:=
alg = {9 x^2 - 2, 8 y^3 - 3};
max = 5;
Table[
 mat = RandomInteger[{-max, max}, {n, n}];
 mat[[1, 1]] = x;
 mat[[2, 2]] = y;
 Timing[ResourceFunction["MatrixMinimalPolynomial"][mat, t, Extension -> alg]], {n, 8, 16, 2}]
Out[24]=

When the extension is over a prime field of modest size we can use methods that are efficient in practice.

Create a 12×12 random matrix over the integers modulo 7919, making the first two diagonal two elements into separate algebraic extension generators:

In[25]:=
SeedRandom[1234];
max = 5;
dim = 12;
mat = RandomInteger[{-max, max}, {dim, dim}];
mat[[1, 1]] = x;
mat[[2, 2]] = y;
mod = Prime[1000];

Create dense generating polynomials and time the matrix minimal polynomial computation for extensions of increasing degrees:

In[26]:=
bottomd = 15;
topd = 30;
dataQuadratic = Table[
  alg = Flatten[{x^j - j + Total@Table[
        RandomInteger[{-max, max}, k] . (x^Range[k]*y^(k - Range[k])), {k, 0, j - 1}], y^(j + 1) - (j + 1) + Total@Table[
        RandomInteger[{-max, max}, k] . (x^Range[k]*y^(k - Range[k])), {k, 0, j}]}]; PrintTemporary[{j, time = AbsoluteTiming[
       mmpD[j] = ResourceFunction["MatrixMinimalPolynomial"][mat, t, Extension -> alg, Modulus -> mod];][[1]]}];
  {j, j (j + 1), time}, {j, bottomd, topd}]
Out[27]=

A plot of the logarithms compared to a line with slope 2 shows what appears to be a quadratic relation between the timing of the matrix minimal polynomial computation and the size of the extension (as measured by the dimension of the vector space it generates over the base field):

In[28]:=
Show[{Plot[2 x, {x, 0, 1.4}], ListPlot[
   Style[Map[# - Log[dataQuadratic[[1, -2 ;; -1]]] &, Log[N@dataQuadratic[[All, -2 ;; -1]]]], Red]]}, AspectRatio -> 1]
Out[28]=

Neat Examples (3) 

Use MatrixMinimalPolynomial to compute the Drazin inverse of a singular matrix:

In[29]:=
drazin = (-1)^(id + 1) MatrixPower[mat, id] . MatrixPower[ResourceFunction["MatrixPolynomial"][il, mat], id + 1]
Out[29]=

Verify some properties of the Drazin inverse:

In[30]:=
drazin . mat . drazin == drazin
Out[30]=
In[31]:=
drazin . mat == mat . drazin
Out[31]=

Compare with the result of DrazinInverse:

In[32]:=
drazin == DrazinInverse[mat]
Out[32]=

Version History

  • 1.4.1 – 23 November 2022
  • 1.4.0 – 10 January 2022

Source Metadata

Related Resources

License Information