Mathlib.Linear­Algebra

Linear-algebra helpers staged for Mathlib: monomial-matrix and generalized-permutation lemmas used by causal-discovery identification proofs.

Finite­Perron­Frobenius­Positive­Eigenvector 15 core · 26 supporting · 5 submodules Finite-dimensional Perron--Frobenius infrastructure for symmetric entrywise-nonnegative irreducible real matrices: Rayleigh maxima, absolute-value maximizers, positivity propagation, and restriction/zero-extension bridges.
Cholesky 3 core · 7 supporting This file proves that every real symmetric positive-definite matrix factors as the product of the transpose of an upper-triangular matrix with positive diagonal and that matrix itself, and that this factorization is uniq ★ cholesky_exists★ cholesky_unique

Real Cholesky factorization: existence and uniqueness

This file proves that every real symmetric positive-definite matrix factors as the product of the transpose of an upper-triangular matrix with positive diagonal and that matrix itself, and that this factorization is unique. Concretely, for a positive-definite matrix M there is a unique upper-triangular matrix U with strictly positive diagonal entries such that M equals the transpose of U times U.

The public API consists of the predicate IsUpperTri, the existence theorem cholesky_exists, and the uniqueness theorem cholesky_unique; the LDL and orthogonal triangular lemmas expose the proof ingredients needed by those results. Existence is obtained from the LDL decomposition by absorbing the square roots of the diagonal factor; uniqueness reduces to orthogonal_upperTri_pos_diag_eq_one, the fact that an orthogonal upper-triangular matrix with positive diagonal is the identity.

def IsUpperTri reviewed
Causalean.Mathlib.LinearAlgebra

For a matrix UU whose rows and columns are indexed by an ordered set, the upper-triangularity property holds precisely when every entry in a row strictly below its column is zero.

Definition (Lean source)
ι K :
Type*
LT ι
U :
Matrix ι ι K
i j :
j < i
IsUpperTri U :
Prop
U i j = 0
Causalean.Mathlib.LinearAlgebra.IsUpperTri · Causalean/Mathlib/LinearAlgebra/Cholesky.lean:31
theorem cholesky_exists reviewed
Causalean.Mathlib.LinearAlgebra

For a real positive-definite d × d matrix M, there exists an upper-triangular matrix U (zero below the diagonal) with strictly positive diagonal entries such that M factors as Uᵀ · U.

Formal statement
d :
Matrix (Fin d) (Fin d) ℝ
shared
hM :
M.PosDef
∃ U : Matrix (Fin d) (Fin d) ℝ,
conclusion 1
i j :
j < i
U i j = 0
conclusion 2
i :
0 < U i i
conclusion 3
M = U.transpose * U
Proof (Lean source)
theorem cholesky_exists (hM : M.PosDef) : ∃ U : Matrix (Fin d) (Fin d) ℝ, (∀ i j, j < i → U i j = 0) ∧ (∀ i, 0 < U i i) ∧ M = U.transpose * U := by classical set s : Fin d → ℝ := fun i => sqrt (diagEntries hM i) with hs set Dsqrt : Matrix (Fin d) (Fin d) ℝ := diagonal s with hDsqrt refine ⟨Dsqrt * (lower hM)ᵀ, ?_, ?_, ?_⟩ · -- upper triangular have hd : Dsqrt.BlockTriangular id := blockTriangular_diagonal s have hL : ((lower hM)ᵀ).BlockTriangular id := (ldl_lower_blockTriangular hM).transpose exact (hd.mul hL) · -- positive diagonal intro i rw [Matrix.mul_apply] rw [Finset.sum_eq_single i] · simp only [hDsqrt, Matrix.diagonal_apply_eq, Matrix.transpose_apply, ldl_lower_diag_one hM i, mul_one, hs] exact Real.sqrt_pos.mpr (ldl_diagEntries_pos hM i) · intro k _ hki rw [hDsqrt, Matrix.diagonal_apply_ne' s hki, zero_mul] · intro h; exact absurd (Finset.mem_univ i) h · -- M = Uᵀ U have hLH : (lower hM)ᴴ = (lower hM)ᵀ := Matrix.conjTranspose_eq_transpose_of_trivial _ have hDD : Dsqrt * Dsqrt = LDL.diag hM := by rw [hDsqrt, diagonal_mul_diagonal] rw [LDL.diag] congr 1 ext i simp only [hs, Real.mul_self_sqrt (le_of_lt (ldl_diagEntries_pos hM i))] have hkey := LDL.lower_conj_diag hM rw [hLH] at hkey rw [Matrix.transpose_mul, Matrix.transpose_transpose, Matrix.diagonal_transpose] rw [← hDsqrt, Matrix.mul_assoc (lower hM) Dsqrt, ← Matrix.mul_assoc Dsqrt Dsqrt, hDD, ← Matrix.mul_assoc] exact hkey.symm
Causalean.Mathlib.LinearAlgebra.cholesky_exists · Causalean/Mathlib/LinearAlgebra/Cholesky.lean:109
theorem cholesky_unique reviewed
Causalean.Mathlib.LinearAlgebra

For a linearly ordered finite index type ι and a linearly ordered field K, and two matrices U, V indexed by ι × ι and valued in K, if U is upper-triangular, i.e. zero below the diagonal, with strictly positive diagonal entries, V is likewise upper-triangular with strictly positive diagonal entries, and U and V have the same Gram matrix, Uᵀ · U = Vᵀ · V, then U equals V.

Formal statement
hUu :
∀ i j
if
j < i
then
U i j = 0
hUp :
∀ i, 0 < U i i
hVu :
∀ i j
if
j < i
then
V i j = 0
hVp :
∀ i, 0 < V i i
hGram :
U.transpose * U = V.transpose * V
U = V
Proof (Lean source)
theorem cholesky_unique {ι K : Type*} [Fintype ι] [LinearOrder ι] [Field K] [LinearOrder K] [IsStrictOrderedRing K] {U V : Matrix ι ι K} (hUu : ∀ i j, j < i → U i j = 0) (hUp : ∀ i, 0 < U i i) (hVu : ∀ i j, j < i → V i j = 0) (hVp : ∀ i, 0 < V i i) (hGram : U.transpose * U = V.transpose * V) : U = V := by classical have hUu' : U.BlockTriangular id := hUu have hVu' : V.BlockTriangular id := hVu -- `U` is invertible (positive diagonal ⟹ positive determinant). have hUdet : (0 : K) < U.det := by rw [Matrix.det_of_upperTriangular hUu']; exact Finset.prod_pos (fun i _ => hUp i) haveI : Invertible U := U.invertibleOfIsUnitDet (isUnit_iff_ne_zero.mpr hUdet.ne') -- `U⁻¹` is upper-triangular with reciprocal diagonal entries. have hUinvU : U⁻¹.BlockTriangular id := blockTriangular_inv_of_blockTriangular hUu' have hUinv_diag : ∀ i, U⁻¹ i i = (U i i)⁻¹ := by intro i have hmul : (U⁻¹ * U) i i = 1 := by rw [Matrix.inv_mul_of_invertible]; simp rw [Matrix.mul_apply, Finset.sum_eq_single i] at hmul · field_simp [(hUp i).ne'] at hmul ⊢ linarith [hmul] · intro k _ hki rcases lt_or_gt_of_ne hki with hk | hk · rw [hUinvU (by simpa using hk), zero_mul] · rw [hUu k i hk, mul_zero] · intro h; exact absurd (Finset.mem_univ i) h -- The transition matrix `W = V * U⁻¹`. set W : Matrix ι ι K := V * U⁻¹ with hW -- `W` is upper-triangular. have hWupp : ∀ i j, j < i → W i j = 0 := hVu'.mul hUinvU -- `W` has strictly positive diagonal. have hWdiag : ∀ i, W i i = V i i * (U i i)⁻¹ := by intro i rw [hW, Matrix.mul_apply, Finset.sum_eq_single i] · rw [hUinv_diag i] · intro k _ hki rcases lt_or_gt_of_ne hki with hk | hk · rw [hVu i k (by simpa using hk), zero_mul] · rw [hUinvU (by simpa using hk), mul_zero] · intro h; exact absurd (Finset.mem_univ i) h have hWpos : ∀ i, 0 < W i i := by intro i rw [hWdiag i] exact mul_pos (hVp i) (inv_pos.mpr (hUp i)) -- `W` is orthogonal: `Wᵀ * W = 1`. have hMUV : Uᵀ * U = Vᵀ * V := hGram have hWortho : Wᵀ * W = 1 := by rw [hW, Matrix.transpose_mul, Matrix.mul_assoc, ← Matrix.mul_assoc Vᵀ V, ← hMUV, Matrix.mul_assoc Uᵀ, Matrix.mul_inv_of_invertible, Matrix.mul_one, Matrix.transpose_nonsing_inv, Matrix.inv_mul_of_invertible] -- Therefore `W = 1`, i.e. `V * U⁻¹ = 1`, i.e. `V = U`. have hWeq : W = 1 := orthogonal_upperTri_pos_diag_eq_one hWortho hWupp hWpos rw [hW] at hWeq have : V = 1 * U := by rw [← hWeq, Matrix.mul_assoc, Matrix.inv_mul_of_invertible, Matrix.mul_one] rw [this, Matrix.one_mul]
Causalean.Mathlib.LinearAlgebra.cholesky_unique · Causalean/Mathlib/LinearAlgebra/Cholesky.lean:200
7 supporting declarations (lemmas, instances)
  • isUpperTri_iff_blockTriangular theorem — The entrywise upper-triangular predicate is exactly Mathlib's block-triangular predicate for the identity order.
    ι K :
    Type*
    LT ι
    Matrix ι ι K
    IsUpperTri U ↔ U.BlockTriangular id
    Proof (Lean source)
    theorem isUpperTri_iff_blockTriangular {ι K : Type*} [LT ι] [Zero K] {U : Matrix ι ι K} : IsUpperTri U ↔ U.BlockTriangular id := by rfl
    Causalean.Mathlib.LinearAlgebra.isUpperTri_iff_blockTriangular · Causalean/Mathlib/LinearAlgebra/Cholesky.lean:39
  • ldl_lowerInv_diag_one theorem — The Gram-Schmidt lower-inverse matrix is unitriangular: its diagonal entries are 1.
    d :
    Matrix (Fin d) (Fin d) ℝ
    shared
    hM :
    M.PosDef
    i :
    Fin d
    lowerInv hM i i = 1
    Proof (Lean source)
    theorem ldl_lowerInv_diag_one (hM : M.PosDef) (i : Fin d) : lowerInv hM i i = 1 := by letI := (Mᵀ.toNormedAddCommGroup hM.transpose) letI := (Mᵀ.toInnerProductSpace hM.transpose.posSemidef) have key : ∀ (c : Fin d), c < i → InnerProductSpace.gramSchmidt ℝ (⇑(Pi.basisFun ℝ (Fin d))) c i = 0 := by intro c hc have h2 := InnerProductSpace.gramSchmidt_triangular (𝕜 := ℝ) hc (Pi.basisFun ℝ (Fin d)) simpa using h2 rw [lowerInv, InnerProductSpace.gramSchmidt_def] simp only [Pi.sub_apply, Finset.sum_apply, Pi.basisFun_apply, Pi.single_eq_same, sub_eq_self] refine Finset.sum_eq_zero (fun c hc => ?_) rw [Submodule.starProjection_singleton] change _ * InnerProductSpace.gramSchmidt ℝ (⇑(Pi.basisFun ℝ (Fin d))) c i = 0 rw [key c (Finset.mem_Iio.mp hc), mul_zero]
    Causalean.Mathlib.LinearAlgebra.ldl_lowerInv_diag_one · Causalean/Mathlib/LinearAlgebra/Cholesky.lean:52
  • ldl_diagEntries_pos theorem — The diagonal entries of the LDL decomposition of a real positive-definite matrix are strictly positive.
    d :
    Matrix (Fin d) (Fin d) ℝ
    shared
    hM :
    M.PosDef
    i :
    Fin d
    0 < diagEntries hM i
    Proof (Lean source)
    theorem ldl_diagEntries_pos (hM : M.PosDef) (i : Fin d) : 0 < diagEntries hM i := by have hne : lowerInv hM i ≠ 0 := by intro h have h1 := ldl_lowerInv_diag_one hM i rw [h] at h1 simp at h1 rw [diagEntries] simp only [EuclideanSpace.inner_toLp_toLp, star_trivial] rw [dotProduct_comm] exact hM.dotProduct_mulVec_pos hne
    Causalean.Mathlib.LinearAlgebra.ldl_diagEntries_pos · Causalean/Mathlib/LinearAlgebra/Cholesky.lean:68
  • ldl_lowerInv_blockTriangular theorem — LDL.lowerInv is lower-triangular in the BlockTriangular toDual sense.
    d :
    Matrix (Fin d) (Fin d) ℝ
    shared
    hM :
    M.PosDef
    Proof (Lean source)
    theorem ldl_lowerInv_blockTriangular (hM : M.PosDef) : (lowerInv hM).BlockTriangular toDual := by intro i j hij exact LDL.lowerInv_triangular hM (by simpa using hij)
    Causalean.Mathlib.LinearAlgebra.ldl_lowerInv_blockTriangular · Causalean/Mathlib/LinearAlgebra/Cholesky.lean:81
  • ldl_lower_blockTriangular theorem — LDL.lower (the inverse of LDL.lowerInv) is lower-triangular.
    d :
    Matrix (Fin d) (Fin d) ℝ
    shared
    hM :
    M.PosDef
    Proof (Lean source)
    theorem ldl_lower_blockTriangular (hM : M.PosDef) : (lower hM).BlockTriangular toDual := by rw [lower] exact blockTriangular_inv_of_blockTriangular (ldl_lowerInv_blockTriangular hM)
    Causalean.Mathlib.LinearAlgebra.ldl_lower_blockTriangular · Causalean/Mathlib/LinearAlgebra/Cholesky.lean:87
  • ldl_lower_diag_one theorem — LDL.lower is unitriangular: its diagonal entries are 1.
    d :
    Matrix (Fin d) (Fin d) ℝ
    shared
    hM :
    M.PosDef
    i :
    Fin d
    lower hM i i = 1
    Proof (Lean source)
    theorem ldl_lower_diag_one (hM : M.PosDef) (i : Fin d) : lower hM i i = 1 := by have hlow := ldl_lower_blockTriangular hM have hupp := ldl_lowerInv_blockTriangular hM have hmul : lower hM * lowerInv hM = 1 := by rw [lower]; exact Matrix.inv_mul_of_invertible _ have hii : (lower hM * lowerInv hM) i i = 1 := by rw [hmul]; simp rw [Matrix.mul_apply] at hii rw [Finset.sum_eq_single i] at hii · rw [ldl_lowerInv_diag_one hM i, mul_one] at hii; exact hii · intro k _ hki rcases lt_or_gt_of_ne hki with hk | hk · rw [hupp (by simpa using hk), mul_zero] · rw [hlow (by simpa using hk), zero_mul] · intro h; exact absurd (Finset.mem_univ i) h
    Causalean.Mathlib.LinearAlgebra.ldl_lower_diag_one · Causalean/Mathlib/LinearAlgebra/Cholesky.lean:93
  • orthogonal_upperTri_pos_diag_eq_one theorem — An orthogonal (Wᵀ * W = 1) upper-triangular matrix with strictly positive diagonal is the identity matrix.
    hortho :
    Wᵀ * W = 1
    hupp :
    ∀ i j
    if
    j < i
    then
    W i j = 0
    hpos :
    ∀ i, 0 < W i i
    W = 1
    Proof (Lean source)
    theorem orthogonal_upperTri_pos_diag_eq_one {ι K : Type*} [Fintype ι] [LinearOrder ι] [Field K] [LinearOrder K] [IsStrictOrderedRing K] {W : Matrix ι ι K} (hortho : Wᵀ * W = 1) (hupp : ∀ i j, j < i → W i j = 0) (hpos : ∀ i, 0 < W i i) : W = 1 := by classical haveI : Invertible W := invertibleOfLeftInverse _ _ hortho -- `W⁻¹ = Wᵀ` have hinv : W⁻¹ = Wᵀ := Matrix.inv_eq_left_inv hortho have hWupp : W.BlockTriangular id := hupp -- `Wᵀ` is upper-triangular (as `W⁻¹`) and lower-triangular (as a transpose of upper). have hWTupp : (Wᵀ).BlockTriangular id := hinv ▸ blockTriangular_inv_of_blockTriangular hWupp have hWTlow : (Wᵀ).BlockTriangular toDual := hWupp.transpose -- Hence `Wᵀ` is diagonal: off-diagonal entries vanish. have hWTdiag : ∀ i j, i ≠ j → (Wᵀ) i j = 0 := by intro i j hij rcases lt_or_gt_of_ne hij with h | h · exact hWTlow (by simpa using h) · exact hWTupp (by simpa using h) -- The diagonal entries square to one and are positive, hence equal one. ext i j have hsq : ∀ k, W k k * W k k = 1 := by intro k have := congrFun (congrFun hortho k) k rw [Matrix.mul_apply] at this rw [Finset.sum_eq_single k] at this · simpa [Matrix.transpose_apply] using this · intro l _ hlk have hz : (Wᵀ) k l = 0 := hWTdiag k l (Ne.symm hlk) rw [hz, zero_mul] · intro h; exact absurd (Finset.mem_univ k) h have hdiagone : ∀ k, W k k = 1 := by intro k have h1 := hsq k nlinarith [hpos k] rcases eq_or_ne i j with rfl | hne · simp [hdiagone i] · rcases lt_or_gt_of_ne hne with h | h · -- `i < j`: read off `W i j` from the vanishing transpose entry `Wᵀ j i` have : (Wᵀ) j i = 0 := hWTdiag j i (Ne.symm hne) simpa [Matrix.transpose_apply, Matrix.one_apply_ne hne] using this · -- `j < i`: upper-triangularity kills it rw [hupp i j h, Matrix.one_apply_ne (Ne.symm (by simpa using h.ne))]
    Causalean.Mathlib.LinearAlgebra.orthogonal_upperTri_pos_diag_eq_one · Causalean/Mathlib/LinearAlgebra/Cholesky.lean:155
Confluent­Vandermonde 9 core · 18 supporting This file proves nonsingularity of the Hermite evaluation matrix at distinct complex nodes, together with the pinned variant having one simple node and all remaining nodes doubled. ★ det_confluentVandermonde_ne_zero★ det_pinnedConfluentVandermonde_ne_zero

Confluent Vandermonde matrices

This file proves nonsingularity of the Hermite evaluation matrix at distinct complex nodes, together with the pinned variant having one simple node and all remaining nodes doubled.

def doubledExponent reviewed
Causalean.Mathlib.LinearAlgebra

Given a nonnegative integer nn, the doubled exponent assigns exponent ii to the ii-th index in the first block of nn indices and exponent n+in+i to the ii-th index in the second block. The first-block assignment and the second-block assignment together define the encoding.

Definition (Lean source)
n :
doubledExponent :
Fin n ⊕ Fin n → ℕ
clause 1
| inl i => i.val
clause 2
| inr i => n + i.val
Causalean.Mathlib.LinearAlgebra.doubledExponent · Causalean/Mathlib/LinearAlgebra/ConfluentVandermonde.lean:29
def doubledCoefficientPolynomial reviewed
Causalean.Mathlib.LinearAlgebra

Given a nonnegative integer nn, a semiring of coefficients, and a coefficient vector indexed by two blocks of nn positions, the doubled coefficient polynomial is the polynomial whose coefficient at each encoded exponent is the corresponding entry of that vector.

Definition (Lean source)
n :
K :
Type*
v :
Fin n ⊕ Fin n → K
doubledCoefficientPolynomial v :
∑ i, Polynomial.monomial (doubledExponent i) (v i)
Causalean.Mathlib.LinearAlgebra.doubledCoefficientPolynomial · Causalean/Mathlib/LinearAlgebra/ConfluentVandermonde.lean:63
def confluentVandermonde reviewed
Causalean.Mathlib.LinearAlgebra

Given a nonnegative integer nn, a semiring of coefficients, and nn node values, the confluent Vandermonde matrix is the square matrix with rows indexed by monomial degrees from zero through 2n12n-1, value columns at every node, and first-derivative columns at every node.

Definition (Lean source)
n :
shared
K :
Type*
s :
Fin n → K
confluentVandermonde s :
Matrix (Fin n ⊕ Fin n) (Fin n ⊕ Fin n) K
fun a b
=> match b with | inl i => s i ^ doubledExponent a | inr i => (doubledExponent a : K) * s i ^ (doubledExponent a - 1)
Causalean.Mathlib.LinearAlgebra.confluentVandermonde · Causalean/Mathlib/LinearAlgebra/ConfluentVandermonde.lean:110
theorem det_confluentVandermonde_ne_zero reviewed
Causalean.Mathlib.LinearAlgebra

For a positive number of nodes n (1 ≤ n), a field K, and pairwise distinct nodes s : Fin n → K, the confluent Vandermonde determinant at s is nonzero.

Formal statement
n :
K :
Type*
hn :
1 ≤ n
s :
Fin n → K
hs :
Proof (Lean source)
theorem det_confluentVandermonde_ne_zero {n : ℕ} {K : Type*} [Field K] (hn : 1 ≤ n) (s : Fin n → K) (hs : Injective s) : (confluentVandermonde s).det ≠ 0 := by let M := confluentVandermonde s have hmul : Injective M.transpose.mulVec := by intro u v huv apply sub_eq_zero.mp let w := u - v have hw : M.transpose.mulVec w = 0 := by funext b simp only [w, mulVec, dotProduct, Pi.sub_apply, Pi.zero_apply, mul_sub, Finset.sum_sub_distrib] exact sub_eq_zero.mpr (congrFun huv b) apply doubledCoefficientPolynomial_eq_zero_of_eval_derivative hn s hs w · intro i have hi := congrFun hw (inl i) simpa [M, confluentVandermonde, mulVec, dotProduct, eval_doubledCoefficientPolynomial, mul_comm] using hi · intro i have hi := congrFun hw (inr i) simpa [M, confluentVandermonde, mulVec, dotProduct, eval_derivative_doubledCoefficientPolynomial, mul_comm, mul_left_comm, mul_assoc] using hi have hu : IsUnit M.transpose := Matrix.mulVec_injective_iff_isUnit.mp hmul have hdet : IsUnit M.transpose.det := hu.map (Matrix.detMonoidHom (n := Fin n ⊕ Fin n) (R := K)) simpa [M, Matrix.det_transpose] using hdet.ne_zero
Causalean.Mathlib.LinearAlgebra.det_confluentVandermonde_ne_zero · Causalean/Mathlib/LinearAlgebra/ConfluentVandermonde.lean:187 · uses confluentVandermonde
def pinnedExponent reviewed
Causalean.Mathlib.LinearAlgebra

Given a nonnegative integer nn, the pinned exponent assigns exponent ii to the ii-th index in its block of nn simple-node positions and exponent n+in+i to the ii-th index in its block of n1n-1 derivative positions. The simple-node assignment and the derivative-position assignment together define the encoding.

Definition (Lean source)
n :
pinnedExponent :
Fin n ⊕ Fin (n - 1) → ℕ
clause 1
| inl i => i.val
clause 2
| inr i => n + i.val
Causalean.Mathlib.LinearAlgebra.pinnedExponent · Causalean/Mathlib/LinearAlgebra/ConfluentVandermonde.lean:220
def pinnedSucc reviewed
Causalean.Mathlib.LinearAlgebra

Given a nonnegative integer nn and an index i<n1i<n-1, the pinned successor index is the index i+1<ni+1<n.

Definition (Lean source)
n :
i :
Fin (n - 1)
pinnedSucc i :
Fin n
⟨i.val + 1, by have := i.isLt; omega⟩
Causalean.Mathlib.LinearAlgebra.pinnedSucc · Causalean/Mathlib/LinearAlgebra/ConfluentVandermonde.lean:228
def pinnedCoefficientPolynomial reviewed
Causalean.Mathlib.LinearAlgebra

Given a nonnegative integer nn, a semiring of coefficients, and a coefficient vector indexed by nn value positions and n1n-1 derivative positions, the pinned coefficient polynomial is the polynomial whose coefficient at each pinned exponent is the corresponding vector entry.

Definition (Lean source)
n :
K :
Type*
v :
Fin n ⊕ Fin (n - 1) → K
pinnedCoefficientPolynomial v :
∑ i, Polynomial.monomial (pinnedExponent i) (v i)
Causalean.Mathlib.LinearAlgebra.pinnedCoefficientPolynomial · Causalean/Mathlib/LinearAlgebra/ConfluentVandermonde.lean:275
def pinnedConfluentVandermonde reviewed
Causalean.Mathlib.LinearAlgebra

Given a nonnegative integer nn, a semiring of coefficients, and nn node values, the pinned confluent Vandermonde matrix records values at all nodes and first derivatives at nodes one through n1n-1, omitting the derivative at node zero.

Definition (Lean source)
n :
shared
K :
Type*
s :
Fin n → K
pinnedConfluentVandermonde s :
Matrix (Fin n ⊕ Fin (n - 1)) (Fin n ⊕ Fin (n - 1)) K
fun a b
=> match b with | inl i => s i ^ pinnedExponent a | inr i => (pinnedExponent a : K) * s (pinnedSucc i) ^ (pinnedExponent a - 1)
Causalean.Mathlib.LinearAlgebra.pinnedConfluentVandermonde · Causalean/Mathlib/LinearAlgebra/ConfluentVandermonde.lean:323
theorem det_pinnedConfluentVandermonde_ne_zero reviewed
Causalean.Mathlib.LinearAlgebra

For a positive number of nodes n (1 ≤ n), a field K, and pairwise distinct nodes s : Fin n → K, the pinned confluent Vandermonde determinant at s is nonzero: one node contributes only value evaluation and every other node contributes both value and first-derivative evaluation.

Formal statement
n :
K :
Type*
hn :
1 ≤ n
s :
Fin n → K
hs :
Proof (Lean source)
theorem det_pinnedConfluentVandermonde_ne_zero {n : ℕ} {K : Type*} [Field K] (hn : 1 ≤ n) (s : Fin n → K) (hs : Injective s) : (pinnedConfluentVandermonde s).det ≠ 0 := by let M := pinnedConfluentVandermonde s have hmul : Injective M.transpose.mulVec := by intro u v huv apply sub_eq_zero.mp let w := u - v have hw : M.transpose.mulVec w = 0 := by funext b simp only [w, mulVec, dotProduct, Pi.sub_apply, Pi.zero_apply, mul_sub, Finset.sum_sub_distrib] exact sub_eq_zero.mpr (congrFun huv b) apply pinnedCoefficientPolynomial_eq_zero_of_eval_derivative hn s hs w · intro i have hi := congrFun hw (inl i) simpa [M, pinnedConfluentVandermonde, mulVec, dotProduct, eval_pinnedCoefficientPolynomial, mul_comm] using hi · intro i have hi := congrFun hw (inr i) simpa [M, pinnedConfluentVandermonde, mulVec, dotProduct, eval_derivative_pinnedCoefficientPolynomial, mul_comm, mul_left_comm, mul_assoc] using hi have hu : IsUnit M.transpose := Matrix.mulVec_injective_iff_isUnit.mp hmul have hdet : IsUnit M.transpose.det := hu.map (Matrix.detMonoidHom (n := Fin n ⊕ Fin (n - 1)) (R := K)) simpa [M, Matrix.det_transpose] using hdet.ne_zero
Causalean.Mathlib.LinearAlgebra.det_pinnedConfluentVandermonde_ne_zero · Causalean/Mathlib/LinearAlgebra/ConfluentVandermonde.lean:425 · uses pinnedConfluentVandermonde
18 supporting declarations (lemmas, instances)
Monomial­Matrix 3 core · 0 supporting This file collects the linear-algebra facts about generalized-permutation (monomial) matrices that underlie linear causal-discovery identification arguments. ★ genPerm_of_det_ne_zero_of_colSupport★ perm_uniqueness★ eq_of_genPerm_triangular_unitDiag

Generalized-permutation (monomial) matrices

This file collects the linear-algebra facts about generalized-permutation (monomial) matrices that underlie linear causal-discovery identification arguments. A generalized-permutation matrix has exactly one non-zero entry in each row and column — equivalently, it is a permutation composed with a non-zero diagonal rescaling. Such matrices are the ambiguity group of independent component analysis: a mixing matrix is recovered only up to relabelling and rescaling its columns. The three results here are: (1) an invertible matrix with at most one non-zero entry per column is automatically of this generalized-permutation form; (2) a simultaneous row/column permutation of a lower-triangular matrix with non-zero diagonal keeps a non-zero diagonal exactly when the two permutations agree; and (3) two unit-diagonal matrices related by a generalized permutation, one of them triangular in a causal order, must be equal. They are consumed by the LiNGAM and linear-causal-disentanglement developments to turn an ICA-level identification (sharp only up to generalized permutation) into a sharp structural identification.

theorem genPerm_of_det_ne_zero_of_colSupport reviewed
Causalean.Mathlib.LinearAlgebra

For a finite index type ι and a commutative ring K, and a square matrix W over ι × ι valued in K with nonzero determinant, if every column of W has at most one non-zero entry (for any two distinct rows i ≠ k, at least one of W i j, W k j vanishes at column j), then W is a generalized permutation matrix: there are a permutation τ of ι and non-zero scalings d with W i j = if j = τ i then d i else 0.

Formal statement
ι K :
hW :
W.det ≠ 0
hcol :
∀ j i k
if
i ≠ k
then
W i j = 0 ∨ W k j = 0
∃ (τ : Perm ι) (d : ι → K),
conclusion 1
i :
d i ≠ 0
conclusion 2
i j :
W i j = if j = τ i then d i else 0
Proof (Lean source)
theorem genPerm_of_det_ne_zero_of_colSupport {ι K : Type*} [Fintype ι] [DecidableEq ι] [CommRing K] {W : Matrix ι ι K} (hW : W.det ≠ 0) (hcol : ∀ j i k, i ≠ k → W i j = 0 ∨ W k j = 0) : ∃ (τ : Perm ι) (d : ι → K), (∀ i, d i ≠ 0) ∧ ∀ i j, W i j = if j = τ i then d i else 0 := by classical have hcol_nonzero : ∀ j, ∃ i, W i j ≠ 0 := by intro j by_contra hzero have hcol_zero : ∀ i, W i j = 0 := by intro i by_contra hi exact hzero ⟨i, hi⟩ exact hW (Matrix.det_eq_zero_of_column_eq_zero j hcol_zero) let ρ : ι → ι := fun j => choose (hcol_nonzero j) have hρ_ne : ∀ j, W (ρ j) j ≠ 0 := by intro j exact Classical.choose_spec (hcol_nonzero j) have hρ_unique : ∀ j i, W i j ≠ 0 → i = ρ j := by intro j i hi by_contra hne cases hcol j i (ρ j) hne with | inl h => exact hi h | inr h => exact hρ_ne j h have hρ_zero : ∀ j i, i ≠ ρ j → W i j = 0 := by intro j i hi by_contra hne exact hi (hρ_unique j i hne) have hρ_surj : Surjective ρ := by by_contra hsurj have hmissing : ∃ i, ∀ j, ρ j ≠ i := by simpa [Surjective] using hsurj obtain ⟨i, hi⟩ := hmissing have hrow_zero : ∀ j, W i j = 0 := by intro j exact hρ_zero j i (fun h => hi j h.symm) exact hW (Matrix.det_eq_zero_of_row_eq_zero i hrow_zero) have hρ_inj : Injective ρ := (Finite.injective_iff_surjective).2 hρ_surj let ρE : Perm ι := Equiv.ofBijective ρ ⟨hρ_inj, hρ_surj⟩ let τ : Perm ι := ρE.symm let d : ι → K := fun i => W i (τ i) refine ⟨τ, d, ?_, ?_⟩ · intro i have hρτ : ρ (τ i) = i := by change ρE (ρE.symm i) = i simp have hne := hρ_ne (τ i) simpa [d, hρτ] using hne · intro i j by_cases hj : j = τ i · simp [d, hj] · have hiρ : i ≠ ρ j := by intro hi apply hj calc j = ρE.symm (ρE j) := by simp _ = ρE.symm (ρ j) := rfl _ = ρE.symm i := by rw [← hi] _ = τ i := rfl have hzero : W i j = 0 := hρ_zero j i hiρ simp [hj, hzero]
Causalean.Mathlib.LinearAlgebra.genPerm_of_det_ne_zero_of_colSupport · Causalean/Mathlib/LinearAlgebra/MonomialMatrix.lean:32
theorem perm_uniqueness reviewed
Causalean.Mathlib.LinearAlgebra

Permutation uniqueness for lower-triangular matrices (LiNGAM Appendix A, Lemma 1). For a matrix M over Fin n × Fin n that is lower-triangular (M i j = 0 whenever i < j) with non-zero diagonal entries, and permutations σ, τ of Fin n, the row/column-permuted matrix (i ↦ M (σ i) (τ i)) has a non-zero diagonal at every i if and only if σ = τ.

Formal statement
n :
K :
Type*
Matrix (Fin n) (Fin n) K
hLT :
∀ i j
if
i < j
then
M i j = 0
hdiag :
∀ i, M i i ≠ 0
σ τ :
Perm (Fin n)
(∀ i, M (σ i) (τ i) ≠ 0) ↔ σ = τ
Proof (Lean source)
theorem perm_uniqueness {n : ℕ} {K : Type*} [Zero K] {M : Matrix (Fin n) (Fin n) K} (hLT : ∀ i j, i < j → M i j = 0) (hdiag : ∀ i, M i i ≠ 0) {σ τ : Perm (Fin n)} : (∀ i, M (σ i) (τ i) ≠ 0) ↔ σ = τ := by constructor · intro h have hge : ∀ i, (τ i : ℕ) ≤ (σ i : ℕ) := by intro i by_contra hlt push_neg at hlt exact h i (hLT (σ i) (τ i) (by exact_mod_cast hlt)) have hsum : ∑ i, (σ i : ℕ) = ∑ i, (τ i : ℕ) := by rw [Equiv.sum_comp σ (fun i => (i : ℕ)), Equiv.sum_comp τ (fun i => (i : ℕ))] have heq : ∀ i, (σ i : ℕ) = (τ i : ℕ) := by have hle : ∀ i ∈ univ, (τ i : ℕ) ≤ (σ i : ℕ) := fun i _ => hge i have := (Finset.sum_eq_sum_iff_of_le hle).1 hsum.symm intro i; exact ((this i (Finset.mem_univ i)).symm) exact Equiv.ext fun i => Fin.val_injective (heq i) · rintro rfl i exact hdiag (σ i)
Causalean.Mathlib.LinearAlgebra.perm_uniqueness · Causalean/Mathlib/LinearAlgebra/MonomialMatrix.lean:99
theorem eq_of_genPerm_triangular_unitDiag reviewed
Causalean.Mathlib.LinearAlgebra

Generalized-permutation reduction. For matrices C, C' over Fin n × Fin n valued in K, if C has unit diagonal and C' has unit diagonal, C is lower triangular in some causal order σ (C i j = 0 when σ i < σ j), and C' is obtained from C by a generalized permutation with permutation τ and scalings d, i.e. C' i j = d i · C (τ i) j for all i, j, then C = C': the unit diagonal plus triangularity force the underlying permutation to be the identity and every scaling to be one. (Formerly Discovery.LiNGAM.lingam_reduction.)

Formal statement
n :
K :
hCdiag :
∀ i, C i i = 1
hC'diag :
∀ i, C' i i = 1
σ :
Perm (Fin n)
hCtri :
∀ i j
if
σ i < σ j
then
C i j = 0
τ :
Perm (Fin n)
d :
Fin n → K
hW :
∀ i j, C' i j = d i * C (τ i) j
C = C'
Proof (Lean source)
theorem eq_of_genPerm_triangular_unitDiag {n : ℕ} {K : Type*} [MulZeroOneClass K] [Nontrivial K] {C C' : Matrix (Fin n) (Fin n) K} (hCdiag : ∀ i, C i i = 1) (hC'diag : ∀ i, C' i i = 1) {σ : Perm (Fin n)} (hCtri : ∀ i j, σ i < σ j → C i j = 0) {τ : Perm (Fin n)} {d : Fin n → K} (hW : ∀ i j, C' i j = d i * C (τ i) j) : C = C' := by have hne : ∀ i, C (τ i) i ≠ 0 := by intro i hzero have h := hW i i rw [hzero, mul_zero, hC'diag i] at h exact one_ne_zero h have hle : ∀ i, (σ i : ℕ) ≤ (σ (τ i) : ℕ) := by intro i by_contra h push_neg at h exact hne i (hCtri (τ i) i (by exact_mod_cast h)) have hsum : ∑ i, (σ (τ i) : ℕ) = ∑ i, (σ i : ℕ) := Equiv.sum_comp τ (fun i => (σ i : ℕ)) have heqσ : ∀ i, (σ (τ i) : ℕ) = (σ i : ℕ) := by have hle' : ∀ i ∈ univ, (σ i : ℕ) ≤ (σ (τ i) : ℕ) := fun i _ => hle i exact fun i => ((Finset.sum_eq_sum_iff_of_le hle').1 hsum.symm i (Finset.mem_univ i)).symm have hτ : ∀ i, τ i = i := fun i => σ.injective (Fin.val_injective (heqσ i)) have hd1 : ∀ i, d i = 1 := by intro i have h := hW i i rw [hτ i, hCdiag i, mul_one, hC'diag i] at h exact h.symm ext i j rw [hW i j, hτ i, hd1 i, one_mul]
Causalean.Mathlib.LinearAlgebra.eq_of_genPerm_triangular_unitDiag · Causalean/Mathlib/LinearAlgebra/MonomialMatrix.lean:125
Stacked­Vandermonde 4 core · 0 supporting This file gives a constructive injectivity certificate for a stacked family of weighted Vandermonde evaluation maps at distinct nodes in a commutative domain. ★ stacked_contraction_injective_of_generic_weights

Stacked Vandermonde systems

This file gives a constructive injectivity certificate for a stacked family of weighted Vandermonde evaluation maps at distinct nodes in a commutative domain.

def affineBinaryPower reviewed
Causalean.Mathlib.LinearAlgebra

Given an element zz of a multiplicative monoid and a nonnegative integer kk, the affine power vector is the vector indexed by the integers from zero through kk whose entry at rr is zrz^r.

Definition (Lean source)
K :
Type*
z :
K
k :
affineBinaryPower z k :
Fin (k + 1) → K
fun r => z ^ (r : ℕ)
Causalean.Mathlib.LinearAlgebra.affineBinaryPower · Causalean/Mathlib/LinearAlgebra/StackedVandermonde.lean:30
def stackedContraction reviewed
Causalean.Mathlib.LinearAlgebra

Given a nonnegative integer NN, N+1N+1 slope values, a weight assigned to each slope and each of the NN blocks, and a coefficient attached to each slope, the stacked contraction maps a block index k<Nk<N and an exponent rkr\leq k to the sum, over all slopes, of the weight times the coefficient times the rr-th power of that slope.

Definition (Lean source)
K :
Type*
N :
slopes :
Fin (N + 1) → K
weights :
Fin (N + 1) → Fin N → K
e :
Fin (N + 1) → K
k :
Fin N
stackedContraction N slopes weights e k :
Fin (k.1 + 1) → K
fun k r => ∑ j, weights j k * e j * affineBinaryPower (slopes j) k.1 r
Causalean.Mathlib.LinearAlgebra.stackedContraction · Causalean/Mathlib/LinearAlgebra/StackedVandermonde.lean:39
def blockVandermondeWitnessWeights reviewed
Causalean.Mathlib.LinearAlgebra

Given a positive integer NN, the block-Vandermonde witness weights assign weight one only to index zero in block zero and to every nonzero index in block N1N-1, and assign weight zero in all other cases. The first block is chosen as block zero, the second as block N1N-1, and the stated case assignment defines the weights.

Definition (Lean source)
K :
Type*
One K
N :
hN :
1 ≤ N
blockVandermondeWitnessWeights N hN :
Fin (N + 1) → Fin N → K
zeroBlock :
⟨0, by omega⟩ (: Fin N)
topBlock :
⟨N - 1, sub_lt (by omega) (by omega)⟩ (: Fin N)
fun j k => if j = 0 then if k = zeroBlock then 1 else 0 else if k = topBlock then 1 else 0
Causalean.Mathlib.LinearAlgebra.blockVandermondeWitnessWeights · Causalean/Mathlib/LinearAlgebra/StackedVandermonde.lean:53
theorem stacked_contraction_injective_of_generic_weights reviewed
Causalean.Mathlib.LinearAlgebra

For a commutative integral domain K, at least three indices N + 1 (2 ≤ N), and pairwise distinct slope values slopes : Fin (N + 1) → K, there exist weights Fin (N + 1) → Fin N → K for which the stacked contraction is injective. The first block detects coordinate 0, while the last block is a square Vandermonde system on coordinates 1,…,N.

Formal statement
K :
N :
hN :
2 ≤ N
slopes :
Fin (N + 1) → K
hslopes :
Injective slopes
∃ weights : Fin (N + 1) → Fin N → K,
Injective (stackedContraction N slopes weights)
Proof (Lean source)
theorem stacked_contraction_injective_of_generic_weights {K : Type*} [CommRing K] [IsDomain K] {N : ℕ} (hN : 2 ≤ N) (slopes : Fin (N + 1) → K) (hslopes : Injective slopes) : ∃ weights : Fin (N + 1) → Fin N → K, Injective (stackedContraction N slopes weights) := by let zeroBlock : Fin N := ⟨0, by omega⟩ let topBlock : Fin N := ⟨N - 1, sub_lt (by omega) (by omega)⟩ have htop_ne_zero : topBlock ≠ zeroBlock := by intro h have : N - 1 = 0 := Fin.ext_iff.mp h omega have hzero_ne_top : (0 : ℕ) ≠ N - 1 := by omega refine ⟨blockVandermondeWitnessWeights N (by omega), ?_⟩ intro e e' he have hzero : e 0 = e' 0 := by have h := congrFun (congrFun he zeroBlock) (0 : Fin 1) simpa [stackedContraction, blockVandermondeWitnessWeights, affineBinaryPower, zeroBlock, topBlock, htop_ne_zero, hzero_ne_top, Fin.sum_univ_succ] using h have hsucc : (fun i : Fin N => e i.succ) = fun i => e' i.succ := by have htop := fun r => congrFun (congrFun he topBlock) r have hsum : ∀ r : Fin N, (∑ i : Fin N, e i.succ * slopes i.succ ^ (r : ℕ)) = ∑ i : Fin N, e' i.succ * slopes i.succ ^ (r : ℕ) := by intro r let rTop : Fin (topBlock.1 + 1) := ⟨r.1, by change r.1 < N - 1 + 1 omega⟩ simpa [stackedContraction, blockVandermondeWitnessWeights, affineBinaryPower, zeroBlock, topBlock, htop_ne_zero, Fin.sum_univ_succ, rTop] using htop rTop have hv : (fun i : Fin N => e i.succ - e' i.succ) = 0 := by apply Matrix.eq_zero_of_vecMul_eq_zero (Matrix.det_vandermonde_ne_zero_iff.mpr (hslopes.comp (Fin.succ_injective N))) funext r change ∑ i : Fin N, (e i.succ - e' i.succ) * slopes i.succ ^ (r : ℕ) = 0 calc ∑ i : Fin N, (e i.succ - e' i.succ) * slopes i.succ ^ (r : ℕ) = (∑ i : Fin N, e i.succ * slopes i.succ ^ (r : ℕ)) - ∑ i : Fin N, e' i.succ * slopes i.succ ^ (r : ℕ) := by rw [← Finset.sum_sub_distrib] apply Finset.sum_congr rfl intro i _ ring _ = 0 := sub_eq_zero.mpr (hsum r) funext i exact sub_eq_zero.mp (congrFun hv i) funext j refine Fin.cases ?_ (fun i => ?_) j · exact hzero · exact congrFun hsucc i
Causalean.Mathlib.LinearAlgebra.stacked_contraction_injective_of_generic_weights · Causalean/Mathlib/LinearAlgebra/StackedVandermonde.lean:69 · uses stackedContraction
Vandermonde­Synthesis 2 core · 3 supporting This file computes the kernel dimension of a finite moment-synthesis map with distinct complex nodes and one endpoint coordinate. ★ endpointOrderSynthesis_ker_finrank

Vandermonde synthesis maps

This file computes the kernel dimension of a finite moment-synthesis map with distinct complex nodes and one endpoint coordinate.

def endpointOrderSynthesis reviewed
Causalean.Mathlib.LinearAlgebra

Given a nonnegative integer nn, a commutative semiring of coefficients, nn node values, and a nonnegative integer rr, the endpoint-order synthesis map sends n+1n+1 coefficients to the first r+1r+1 moment sums of the node coefficients, with the terminal coefficient added only to the moment of order rr.

Definition (Lean source)
n :
K :
s :
Fin n → K
r :
endpointOrderSynthesis s r :
(Fin (n + 1) → K) →ₗ[K] (Fin (r + 1) → K)
clause 1
toFun z a := ∑ j : Fin n, z j.castSucc * s j ^ a.val + if a.val
= r then z (last n) else 0
clause 2
map_add' x y := by funext a simp only [Pi.add_apply, add_mul, Finset.sum_add_distrib] split <;> ring
clause 3
map_smul' c x := by funext a simp only [Pi.smul_apply, smul_eq_mul, RingHom.id_apply] split <;> (simp [← Finset.mul_sum, mul_assoc] <;> ring)
Causalean.Mathlib.LinearAlgebra.endpointOrderSynthesis · Causalean/Mathlib/LinearAlgebra/VandermondeSynthesis.lean:28
theorem endpointOrderSynthesis_ker_finrank reviewed
Causalean.Mathlib.LinearAlgebra

For natural numbers n, r, a field K, and pairwise distinct nodes s : Fin n → K, the dimension of the kernel of the order-r endpoint synthesis map equals n - r: below the square threshold (r < n) the kernel has dimension n - r, and at or above it (r ≥ n) the kernel is zero, matching n - r = 0 under truncated subtraction.

Formal statement
n r :
K :
Type*
s :
Fin n → K
hs :
Proof (Lean source)
theorem endpointOrderSynthesis_ker_finrank {n r : ℕ} {K : Type*} [Field K] (s : Fin n → K) (hs : Injective s) : finrank K (ker (endpointOrderSynthesis s r)) = n - r := by by_cases hr : r < n · have hsurj := endpointOrderSynthesis_surjective s hs hr have hrange : range (endpointOrderSynthesis s r) = ⊤ := LinearMap.range_eq_top.mpr hsurj have hnull := LinearMap.finrank_range_add_finrank_ker (endpointOrderSynthesis s r) rw [hrange, finrank_top, Module.finrank_pi K, Module.finrank_pi K, Fintype.card_fin, Fintype.card_fin] at hnull omega · have hinj := endpointOrderSynthesis_injective (r := r) s hs (by omega) rw [LinearMap.ker_eq_bot.mpr hinj, finrank_bot] omega
Causalean.Mathlib.LinearAlgebra.endpointOrderSynthesis_ker_finrank · Causalean/Mathlib/LinearAlgebra/VandermondeSynthesis.lean:127 · uses endpointOrderSynthesis
3 supporting declarations (lemmas, instances)