The coefficients of the characteristic polynomial of A in descending
degree order: entry zero is the coefficient of x^n, and entry n is the
constant coefficient.
35.7.Β HexCharPoly: characteristic polynomials
35.7.1.Β Introduction
Released as hex-char-poly, with the Mathlib correspondence in hex-char-poly-mathlib.
HexCharPoly computes the characteristic polynomial
det (xI - A) of a dense square matrix with the division-free
Samuelson--Berkowitz algorithm. The computational library is
Mathlib-free and works over every commutative ring with decidable
equality. Its only Hex dependencies are
HexMatrix and HexPoly.
The algorithm does no division or pivoting. It therefore works without
assuming that nonzero elements are invertible, and has no
failure-producing branch. Its O(n^4) ring-operation cost makes it a
portable certified implementation rather than a replacement for a
specialized characteristic-polynomial routine on very large matrices.
35.7.2.Β Representation and public API
Hex.Matrix.berkowitz returns n + 1 coefficients in descending
degree order. Entry zero is the coefficient of x^n; entry n is the
constant coefficient.
Hex.Matrix.berkowitz.{u} {R : Type u} [Lean.Grind.CommRing R] {n : β} (A : Hex.Matrix R n n) : Vector R (n + 1)Hex.Matrix.berkowitz.{u} {R : Type u} [Lean.Grind.CommRing R] {n : β} (A : Hex.Matrix R n n) : Vector R (n + 1)
The user-facing Hex.Matrix.charPoly reverses that vector and
stores it as a normalized Hex.DensePoly, whose coefficients are
in ascending order.
Hex.Matrix.charPoly.{u} {R : Type u} [Lean.Grind.CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) : Hex.DensePoly RHex.Matrix.charPoly.{u} {R : Type u} [Lean.Grind.CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) : Hex.DensePoly R
The characteristic polynomial det (x * I - A).
The result is monic, including over the zero ring. Over a nontrivial
ring it has stored size n + 1 and degree n.
Hex.Matrix.charPoly_monic.{u} {R : Type u} [Lean.Grind.CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) : A.charPoly.MonicHex.Matrix.charPoly_monic.{u} {R : Type u} [Lean.Grind.CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) : A.charPoly.Monic
The characteristic polynomial is monic, including over the zero ring.
Hex.Matrix.size_charPoly.{u} {R : Type u} [Lean.Grind.CommRing R] [DecidableEq R] {n : β} (h1 : 1 β 0) (A : Hex.Matrix R n n) : A.charPoly.size = n + 1Hex.Matrix.size_charPoly.{u} {R : Type u} [Lean.Grind.CommRing R] [DecidableEq R] {n : β} (h1 : 1 β 0) (A : Hex.Matrix R n n) : A.charPoly.size = n + 1
Over a nontrivial coefficient ring, charPoly stores exactly n+1
coefficients.
Hex.Matrix.degree?_charPoly.{u} {R : Type u} [Lean.Grind.CommRing R] [DecidableEq R] {n : β} (h1 : 1 β 0) (A : Hex.Matrix R n n) : A.charPoly.degree? = some nHex.Matrix.degree?_charPoly.{u} {R : Type u} [Lean.Grind.CommRing R] [DecidableEq R] {n : β} (h1 : 1 β 0) (A : Hex.Matrix R n n) : A.charPoly.degree? = some n
Over a nontrivial coefficient ring, charPoly has degree n.
The library also provides the matrix trace and Horner evaluation of a dense polynomial at a square matrix.
The sum of the diagonal entries of a square matrix.
Hex.Matrix.evalMatrix.{u} {R : Type u} [Lean.Grind.CommRing R] [DecidableEq R] {n : β} (p : Hex.DensePoly R) (A : Hex.Matrix R n n) : Hex.Matrix R n nHex.Matrix.evalMatrix.{u} {R : Type u} [Lean.Grind.CommRing R] [DecidableEq R] {n : β} (p : Hex.DensePoly R) (A : Hex.Matrix R n n) : Hex.Matrix R n n
Horner evaluation of a dense polynomial at a square matrix. A scalar coefficient acts by scaling the identity matrix.
35.7.3.Β The Berkowitz recursion
The recursion grows trailing principal blocks. At one step, write the
new block as [[a, R], [C, B]]. The first column of the lower-triangular
Toeplitz step is
1, -a, -(R C), -(R B C), ..., -(R B^(k-1) C).
Successive vectors B^j C are computed iteratively. Multiplying the
Toeplitz matrix by the coefficient vector for B produces the
coefficient vector for the new bordered block.
Hex.Matrix.berkowitzColumn.{u} {R : Type u} [Lean.Grind.CommRing R] {n : β} (A : Hex.Matrix R n n) (k : β) (hk : k + 1 β€ n) : Vector R (k + 2)Hex.Matrix.berkowitzColumn.{u} {R : Type u} [Lean.Grind.CommRing R] {n : β} (A : Hex.Matrix R n n) (k : β) (hk : k + 1 β€ n) : Vector R (k + 2)
The Toeplitz first column for the Berkowitz step at trailing block size
k + 1: 1, -a, and -(row dot B^j col) for 0 <= j < k.
Hex.Matrix.berkowitzStep.{u} {R : Type u} [Lean.Grind.CommRing R] {n : β} (A : Hex.Matrix R n n) (k : β) (hk : k + 1 β€ n) (v : Vector R (k + 1)) : Vector R (k + 2)Hex.Matrix.berkowitzStep.{u} {R : Type u} [Lean.Grind.CommRing R] {n : β} (A : Hex.Matrix R n n) (k : β) (hk : k + 1 β€ n) (v : Vector R (k + 1)) : Vector R (k + 2)
One Berkowitz step, growing the descending coefficient vector from length
k + 1 to length k + 2.
The leading coefficient stays one at every intermediate step, and the
coefficient of x^(n-1) in the final polynomial is the negated trace.
Hex.Matrix.berkowitzAux_zero.{u} {R : Type u} [Lean.Grind.CommRing R] {n : β} (A : Hex.Matrix R n n) (k : β) (hk : k β€ n) : (A.berkowitzAux k hk)[0] = 1Hex.Matrix.berkowitzAux_zero.{u} {R : Type u} [Lean.Grind.CommRing R] {n : β} (A : Hex.Matrix R n n) (k : β) (hk : k β€ n) : (A.berkowitzAux k hk)[0] = 1
Every intermediate descending coefficient vector has leading entry one.
Hex.Matrix.coeff_charPoly_pred.{u} {R : Type u} [Lean.Grind.CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) (hn : 0 < n) : A.charPoly.coeff (n - 1) = -A.traceHex.Matrix.coeff_charPoly_pred.{u} {R : Type u} [Lean.Grind.CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) (hn : 0 < n) : A.charPoly.coeff (n - 1) = -A.trace
The coefficient of x^(n-1) is the negative trace.
35.7.4.Β Computing certified concrete results
For a closed Hex.Matrix Int n n, char_poly A is a term containing
the computed polynomial and a proof that it equals
Hex.Matrix.charPoly applied to A. Bare char_poly closes a direct equality
in either orientation.
open Hex
open scoped Hex
namespace HexCharPolyChapterExample
private def A : Hex.Matrix Int 2 2 :=
#m[1, 2; 3, 4]
private def result := char_poly A
example : result.poly = #p[-2, -5, 1] := rfl
example : Hex.Matrix.charPoly A = #p[-2, -5, 1] := β’ A.charPoly = DensePoly.ofCoeffs #[-2, -5, 1]
All goals completed! π
example : #p[-2, -5, 1] = Hex.Matrix.charPoly A := β’ DensePoly.ofCoeffs #[-2, -5, 1] = A.charPoly
All goals completed! π
example : True := β’ True
poly:DensePoly β€ := (Matrix.CharPolyResult.ofCheck A #v[1, -5, -2] (DensePoly.ofCoeffs #[-2, -5, 1]) β― β―).polycharPoly_eq:A.charPoly = polyβ’ True
poly:DensePoly β€ := (Matrix.CharPolyResult.ofCheck A #v[1, -5, -2] (DensePoly.ofCoeffs #[-2, -5, 1]) β― β―).polycharPoly_eq:A.charPoly = polyxβ:A.charPoly = polyβ’ True
All goals completed! π
end HexCharPolyChapterExample
The explicit tactic form introduces a transparent poly local
definition and a charPoly_eq hypothesis. This is useful when the
computed polynomial is an intermediate fact rather than the goal.
Importing HexCharPolyMathlib adds the same interface for a closed
Matrix (Fin n) (Fin n) Int. Direct goals use ordinary Mathlib
polynomial notation.
open Matrix Polynomial
namespace HexCharPolyMathlibChapterExample
private def A : Matrix (Fin 2) (Fin 2) Int :=
!![1, 2; 3, 4]
example : A.charpoly = X ^ 2 - 5 * X - 2 := β’ A.charpoly = X ^ 2 - 5 * X - 2
All goals completed! π
example : X ^ 2 - 5 * X - 2 = A.charpoly := β’ X ^ 2 - 5 * X - 2 = A.charpoly
All goals completed! π
example : True := β’ True
poly:β€[X] :=
(HexCharPolyMathlib.CharPolyResult.ofCheck A { data := #v[1, 2, 3, 4] } #v[1, -5, -2] (DensePoly.ofCoeffs #[-2, -5, 1])
β― β― β―).polycharPoly_eq:A.charpoly = polyβ’ True
poly:β€[X] :=
(HexCharPolyMathlib.CharPolyResult.ofCheck A { data := #v[1, 2, 3, 4] } #v[1, -5, -2] (DensePoly.ofCoeffs #[-2, -5, 1])
β― β― β―).polycharPoly_eq:A.charpoly = polyxβ:A.charpoly = polyβ’ True
All goals completed! π
end HexCharPolyMathlibChapterExample
The term and tactic currently support integer matrices only. The
matrix, its dimension, and a polynomial appearing in a direct equality
must be closed and definitionally transparent. Mathlib polynomial goals
may use X, C, integer numerals, addition, subtraction,
multiplication, negation, and natural-literal powers; transparent named
definitions built from those forms are unfolded.
Compiled evaluation discovers the coefficients and intermediate
values. The emitted term separately certifies the scalar dot products,
matrix-vector products, Berkowitz steps, and final coefficients. For a
Mathlib matrix it additionally certifies every materialized entry and
then uses the correspondence theorem below. The compiled evaluator is
not trusted, and Mathlib's noncomputable Matrix.charpoly is not
evaluated.
35.7.5.Β The Mathlib correspondence
HexCharPolyMathlib identifies the executable polynomial with
Mathlib's Matrix.charpoly after
transporting both the matrix and polynomial through their equivalences.
HexCharPolyMathlib.equiv_charPoly.{u} {R : Type u} [CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) : HexPolyMathlib.equiv A.charPoly = (HexMatrixMathlib.matrixEquiv A).charpolyHexCharPolyMathlib.equiv_charPoly.{u} {R : Type u} [CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) : HexPolyMathlib.equiv A.charPoly = (HexMatrixMathlib.matrixEquiv A).charpoly
The executable characteristic polynomial agrees with Mathlib's characteristic polynomial under the dense-polynomial equivalence.
This correspondence supplies the determinant interpretation of evaluation and Cayley--Hamilton without adding Mathlib or a determinant dependency to the computational package.
HexCharPolyMathlib.eval_charPoly.{u} {R : Type u} [CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) (t : R) : A.charPoly.eval t = (t β’ Hex.Matrix.identity n - A).detHexCharPolyMathlib.eval_charPoly.{u} {R : Type u} [CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) (t : R) : A.charPoly.eval t = (t β’ Hex.Matrix.identity n - A).det
Evaluating the executable characteristic polynomial is taking the determinant of the scalar shift.
HexCharPolyMathlib.evalMatrix_charPoly.{u} {R : Type u} [CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) : Hex.Matrix.evalMatrix A.charPoly A = 0HexCharPolyMathlib.evalMatrix_charPoly.{u} {R : Type u} [CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) : Hex.Matrix.evalMatrix A.charPoly A = 0
Cayley--Hamilton for the executable characteristic polynomial and matrix objects.
The constant coefficient is the signed determinant, and transposition and conjugation by an explicitly supplied inverse preserve the polynomial.
HexCharPolyMathlib.coeff_zero_charPoly.{u} {R : Type u} [CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) : A.charPoly.coeff 0 = (-1) ^ n * A.detHexCharPolyMathlib.coeff_zero_charPoly.{u} {R : Type u} [CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) : A.charPoly.coeff 0 = (-1) ^ n * A.det
The constant characteristic-polynomial coefficient is the signed determinant.
HexCharPolyMathlib.charPoly_transpose.{u} {R : Type u} [CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) : A.transpose.charPoly = A.charPolyHexCharPolyMathlib.charPoly_transpose.{u} {R : Type u} [CommRing R] [DecidableEq R] {n : β} (A : Hex.Matrix R n n) : A.transpose.charPoly = A.charPoly
Transposition preserves the executable characteristic polynomial.
HexCharPolyMathlib.charPoly_conj.{u} {R : Type u} [CommRing R] [DecidableEq R] {n : β} (A U V : Hex.Matrix R n n) (h : U * V = Hex.Matrix.identity n) : (U * A * V).charPoly = A.charPolyHexCharPolyMathlib.charPoly_conj.{u} {R : Type u} [CommRing R] [DecidableEq R] {n : β} (A U V : Hex.Matrix R n n) (h : U * V = Hex.Matrix.identity n) : (U * A * V).charPoly = A.charPoly
Conjugation by a pair of mutually inverse square matrices preserves the executable characteristic polynomial.
35.7.6.Β Cross-references
-
HexMatrix supplies the dense matrix type and arithmetic used by the recursion.
-
HexPoly supplies the normalized dense polynomial representation.
-
HexDeterminant supplies the Mathlib-free Leibniz determinant used to state the evaluation law in the correspondence package.
-
HexBareiss is the fraction-free executable route for integer determinants; it computes a determinant rather than the complete characteristic polynomial.