Discovery.LinearDisentanglement
Entry point for the formalization of Squires, Seigal, Bhate & Uhler, *Linear Causal Disentanglement via Interventions* (ICML 2023, arXiv:2211.16467).
Model 7 core · 1 supporting Formalization of the setup of Squires, Seigal, Bhate & Uhler, *Linear Causal Disentanglement via Interventions* (ICML 2023), arXiv:2211.16467. ★ Solution★ InSG★ permMat_mul_transpose
Linear causal disentanglement: model layer
Formalization of the setup of Squires, Seigal, Bhate & Uhler, Linear Causal
Disentanglement via Interventions (ICML 2023), arXiv:2211.16467.
We work over d latent variables (Fin d) and p ≥ d observed variables
(Fin p). The latent DAG 𝒢 is ordered so that an edge j → i implies j > i;
this makes the structural matrices upper triangular in the Fin d order.
For a fixed context, the latent SEM is Z = A Z + Ω^{1/2} ε, equivalently
Z = B⁻¹ ε with B = Ω^{-1/2}(I − A). The observed vector is X = G Z with
G ∈ ℝ^{p×d} full column rank, and H := G⁺ its left inverse (a full-row-rank
d × p matrix with H G = I_d). The only observable content is the family of
precision matrices Θ_k = Hᵀ Bₖᵀ Bₖ H ∈ ℝ^{p×p} (one per context).
We take the algebraic (matrix-level) view of the paper's Theorem 2: the data of
a disentanglement model is a tuple (H, {B_k}, {i_k}, {λ_k}) satisfying the
structural assumptions, and identifiability compares two such tuples that produce
the same family {Θ_k}. No Moore–Penrose pseudoinverse is needed: H enters
only through LinearIndependent ℝ H (full row rank) and the formula for Θ_k.
Conventions for a Solution d p K:
* context 0 is observational with matrix B0; contexts 1 … K are interventional
with matrices Bint k, intervention target target k, and (perfect-intervention)
scaling lam k > 0;
* Edge j i means the latent edge j → i (j a parent of i), forced by hAcyc
to satisfy i < j;
* B0 is upper triangular (B0 i j = 0 for j < i), has positive diagonal, and its
off-diagonal support is exactly Edge — this is what defines 𝒢;
* hInt is Assumption 1(b) specialized to perfect interventions (Assumption 2):
Bₖ = B₀ + e_{iₖ} cₖᵀ with cₖ = λₖ e_{iₖ} − B₀ᵀ e_{iₖ}.
S(𝒢) is the set of node relabelings preserving edge orientation
(Edge j i → σ i < σ j); permMat σ is the corresponding permutation matrix
(P_σ)_{ij} = ⟦i = σ j⟧, matching the paper.
For a nonnegative integer dimension and an index in that dimension, the standard basis vector is the real vector that equals one at the specified index and zero at every other index.
For a nonnegative integer dimension and a permutation of its indices, the permutation matrix is the real square matrix whose entry in row i and column j is one exactly when i is the image of j under the permutation, and is zero otherwise.
A linear causal disentanglement model with d latent variables, p observed variables, and K interventional contexts (Squires, Seigal, Bhate & Uhler 2023) bundles a full-row-rank mixing pseudoinverse from the observed to the latent space, a latent edge relation that respects the node order, and an observational structural matrix that is upper triangular, has a positive diagonal, and has off-diagonal support exactly equal to the edge set. For each interventional context it further carries a structural matrix, an intervention target node, and a positive perfect-intervention scaling, tied to the observational matrix by the perfect-single-node-intervention formula.
Definition (Lean source)
For a linear causal disentanglement solution with d latent variables, p observed variables, and K intervention contexts, the observational precision matrix is the p-by-p real matrix obtained by sandwiching the observational structural matrix's Gram matrix between the mixing pseudoinverse and its transpose.
For a linear causal disentanglement solution with d latent variables, p observed variables, and K intervention contexts and an intervention context, the interventional precision matrix is the p-by-p real matrix obtained by sandwiching that context's structural-matrix Gram matrix between the mixing pseudoinverse and its transpose.
For a linear causal disentanglement solution with d latent variables, p observed variables, and K intervention contexts and a permutation of the latent-node indices, the order-preserving relabeling condition holds exactly when every directed edge from a parent to a child remains ordered with the child's relabeled index strictly smaller than the parent's.
For a dimension d and a permutation σ of Fin d, the permutation matrix permMat σ is orthogonal: its product with its own transpose is the identity matrix.
Proof (Lean source)
1 supporting declaration (lemmas, instances)
-
permMat_transpose_multheorem — permMat σ is orthogonal: (permMat σ)ᵀ * permMat σ = 1.Proof (Lean source)
theorem permMat_transpose_mul {d : ℕ} (σ : Perm (Fin d)) : (permMat σ).transpose * permMat σ = 1 := by ext i k rw [Matrix.mul_apply, Matrix.one_apply] simp only [Matrix.transpose_apply, permMat, Matrix.of_apply] rw [Finset.sum_eq_single (σ i)] · simp [σ.injective.eq_iff] · intro j _ hj simp [hj] · intro h; exact absurd (Finset.mem_univ _) h
PartialOrderRQ 11 core · 16 supporting We package the graph-theoretic notions used throughout (parents, ancestors, and the partial order ≺_𝒢 with i ≺ j ↔ j ∈ an(i)), and the partial order RQ decomposition of the paper (Definition 1, Appendix B): a generaliza ★ IsPORQ★ porq_exists★ porq_unique
Linear causal disentanglement: graph order and the partial-order RQ decomposition
We package the graph-theoretic notions used throughout (parents, ancestors, and the
partial order ≺_𝒢 with i ≺ j ↔ j ∈ an(i)), and the partial order RQ
decomposition of the paper (Definition 1, Appendix B): a generalization of the
reduced RQ decomposition where the upper-triangular support of R is replaced by
the partial order, and orthogonality of the rows of Q is required only along the
order. porq_exists / porq_unique are its existence and uniqueness (their
Proposition in Appendix B), proved there by the Gram–Schmidt-style construction in
Algorithm "Partial Order RQ Decomposition".
For a linear causal disentanglement solution with d latent variables, p observed variables, and K intervention contexts and a latent node, the parent set is the set of latent nodes having a directed edge into that node.
For a linear causal disentanglement solution with d latent variables, p observed variables, and K intervention contexts and a latent node, the inclusive parent set is the union of that node's parent set and the node itself.
For a linear causal disentanglement solution with d latent variables, p observed variables, and K intervention contexts and a latent node, the ancestor set is the set of latent nodes from which a nonempty directed path leads to that node.
For a linear causal disentanglement solution with d latent variables, p observed variables, and K intervention contexts and a latent node, the inclusive ancestor set is the union of that node's ancestor set and the node itself.
For a linear causal disentanglement solution with d latent variables, p observed variables, and K intervention contexts and two latent nodes, the strict causal precedence relation holds exactly when the second node is a strict ancestor of the first.
For a linear causal disentanglement solution with d latent variables, p observed variables, and K intervention contexts and two latent nodes, the weak causal precedence relation holds exactly when the nodes coincide or the second is a strict ancestor of the first.
Definition 1 (partial order RQ decomposition). A witness that a full-row-rank matrix H factors as H = R Q with R having a non-negative diagonal and support confined to the reflexive partial order — Rᵢⱼ = 0 unless i ⪯ j, and the rows of Q each of unit Euclidean norm and pairwise orthogonal along the strict order.
Definition (Lean source)
H factors as R Q.
R has non-negative diagonal.
R is supported on the partial order: Rᵢⱼ = 0 unless i ⪯ j.
Each row of Q has unit norm.
Rows of Q are orthogonal along the strict order.
For a linear causal disentanglement solution with d latent variables, p observed variables, and K intervention contexts and a latent node, the partial-order RQ residual is that node's mixing-pseudoinverse row, viewed as a Euclidean vector, minus its orthogonal projection onto the span of residuals of all strict ancestors. The ancestor-residual span used in this subtraction is generated by the residuals of precisely those strict ancestors.
Definition (Lean source)
For a linear causal disentanglement solution with d latent variables, p observed variables, and K intervention contexts and a latent node, the strict-ancestor residual span is the real linear subspace generated by the partial-order RQ residuals of all strict ancestors of that node.
Definition (Lean source)
Existence of the partial order RQ decomposition (Appendix B Proposition). For a linear causal disentanglement solution, there exist matrices R and Q realizing a partial order RQ decomposition of S's factor loading matrix H — that is, H = R·Q with R's diagonal entries nonnegative and R's support confined to the partial order on nodes, and with Q's rows unit-norm and mutually orthogonal along that order.
Formal statement
Proof (Lean source)
Uniqueness of the partial order RQ decomposition (Appendix B Proposition). Given a solution S, if both (R,Q) and (R',Q') are partial order RQ decompositions of S's latent-direction matrix H — factoring H as a lower- triangular-along-the-order matrix R times a row-orthonormal-along-the-order matrix Q, then the two decompositions coincide: R = R' and Q = Q'.
Formal statement
Proof (Lean source)
16 supporting declarations (lemmas, instances)
-
prec_lttheorem — The strict partial order embeds into the Fin d linear order: if i ≺ j (j is a strict ancestor of i) then i < j. This is the acyclicity of 𝒢 lifted through the transitive closure, and the engine behind every "process the nodes in a topological order" argument below.hypothesesconclusioni < j -
not_prec_selftheorem — ≺ is irreflexive: a node is never its own strict ancestor.hypothesesconclusion¬ S.prec i iProof (Lean source)
theorem not_prec_self (S : Solution d p K) (i : Fin d) : ¬ S.prec i i := fun h => lt_irrefl i (S.prec_lt h) -
inner_toLp_eq_dotProducttheorem — The EuclideanSpace ℝ (Fin p) inner product of toLp x and toLp y is exactly the dotProduct x ⬝ᵥ y. This is the bridge used to import all of Mathlib's inner-product-space machinery into the dotProduct world.Proof (Lean source)
theorem inner_toLp_eq_dotProduct (x y : Fin p → ℝ) : (inner ℝ (toLp 2 x : EuclideanSpace ℝ (Fin p)) (toLp 2 y) : ℝ) = dotProduct x y := by rw [PiLp.inner_apply, dotProduct] apply Finset.sum_congr rfl intro i _ rw [WithLp.ofLp_toLp, WithLp.ofLp_toLp, real_inner_eq_re_inner, mul_comm] simp -
dotProduct_self_postheorem — The self dotProduct of a nonzero real vector is strictly positive (positive-definiteness of ⬝ᵥ). Equivalently, x ⬝ᵥ x = 0 ↔ x = 0; this is what makes "normalize the projection residual" well defined in the construction.Proof (Lean source)
theorem dotProduct_self_pos {x : Fin p → ℝ} (hx : x ≠ 0) : 0 < dotProduct x x := by rcases Function.ne_iff.mp hx with ⟨i, hi⟩ have hnn : 0 ≤ dotProduct x x := sum_nonneg (fun j _ => mul_self_nonneg _) rcases lt_or_eq_of_le hnn with h | h · exact h · exfalso have hzero := (Finset.sum_eq_zero_iff_of_nonneg (fun j _ => mul_self_nonneg (x j))).mp h.symm i (Finset.mem_univ i) exact hi (by simpa using (mul_self_eq_zero).mp hzero) -
eq_of_mul_eq_mul_row_indeptheorem — Right cancellation by a full-row-rank Q. If the rows of Q are linearly independent and R Q = R' Q, then R = R'. This pins the R factor once Q is fixed, and is the algebraic half of the uniqueness proof.hypothesesconclusionR = R'Proof (Lean source)
theorem eq_of_mul_eq_mul_row_indep {R R' : Matrix (Fin d) (Fin d) ℝ} {Q : Matrix (Fin d) (Fin p) ℝ} (hQ : LinearIndependent ℝ Q.row) (hRQ : R * Q = R' * Q) : R = R' := by have hinj : Injective (fun v => vecMul v Q) := Matrix.vecMul_injective_iff.mpr hQ ext i j have hrow : vecMul (R i) Q = vecMul (R' i) Q := by rw [← Matrix.mul_apply_eq_vecMul, ← Matrix.mul_apply_eq_vecMul, hRQ] exact congrFun (hinj hrow) j -
row_indep_of_mul_row_indeptheorem — A full-row-rank product forces a full-row-rank right factor. If the rows of R Q are linearly independent (d of them), then so are the rows of Q. The rows of R Q lie in the span of the rows of Q, which has at most d of them, so a dimension count forces the d rows of Q to be independent. Applied to H = R Q with H of full row rank, this shows the rows qᵢ of any PORQ factor are independent — the hypothesis eq_of_mul_eq_mul_row_indep needs.hypothesesconclusionLinearIndependent ℝ Q.rowProof (Lean source)
theorem row_indep_of_mul_row_indep (R : Matrix (Fin d) (Fin d) ℝ) (Q : Matrix (Fin d) (Fin p) ℝ) (hH : LinearIndependent ℝ (R * Q).row) : LinearIndependent ℝ Q.row := by have hHcard := (linearIndependent_iff_card_le_finrank_span (b := (R * Q).row)).mp hH rw [linearIndependent_iff_card_le_finrank_span] refine le_trans hHcard ?_ have hsub : span ℝ (range (R * Q).row) ≤ span ℝ (range Q.row) := by rw [Submodule.span_le] rintro x ⟨i, rfl⟩ simp only [SetLike.mem_coe, Matrix.row_def, Matrix.mul_apply_eq_vecMul, Matrix.vecMul_eq_sum] apply Submodule.sum_mem intro j _ exact Submodule.smul_mem _ _ (Submodule.subset_span ⟨j, rfl⟩) exact Submodule.finrank_mono hsub -
porq_diag_postheorem — The diagonal of any PORQ factor is strictly positive.hypothesesconclusion0 < R i iProof (Lean source)
theorem porq_diag_pos (S : Solution d p K) {R : Matrix (Fin d) (Fin d) ℝ} {Q : Matrix (Fin d) (Fin p) ℝ} (h : IsPORQ S R Q) (i : Fin d) : 0 < R i i := by -- `H = R Q` has full row rank. have hHrow : LinearIndependent ℝ (R * Q).row := by have hind := S.hH rw [h.factor] at hind rwa [Matrix.row_def] -- `R` itself has full row rank: `v R = 0 ⟹ v (R Q) = 0 ⟹ v = 0`. have hRrow : LinearIndependent ℝ R.row := by rw [← Matrix.vecMul_injective_iff] have hinjH : Injective (fun v => vecMul v (R * Q)) := Matrix.vecMul_injective_iff.mpr hHrow intro v w hvw apply hinjH simp only at hvw ⊢ rw [← Matrix.vecMul_vecMul, ← Matrix.vecMul_vecMul, hvw] -- Hence `R` is a unit, so `det R ≠ 0`. have hdet : R.det ≠ 0 := by have hunit : IsUnit R := Matrix.linearIndependent_rows_iff_isUnit.mp hRrow exact (Matrix.isUnit_iff_isUnit_det R).mp hunit |>.ne_zero -- `R` is upper triangular, so `det R = ∏ Rᵢᵢ`. have hupper : R.BlockTriangular id := by intro a b hba apply h.supp rintro (rfl | hprec) · exact lt_irrefl _ hba · exact lt_irrefl _ (lt_trans hba (S.prec_lt hprec)) rw [Matrix.det_of_upperTriangular hupper] at hdet -- Each diagonal entry is nonzero, hence (with `diag_nonneg`) positive. have hne : R i i ≠ 0 := by intro hzero exact hdet (Finset.prod_eq_zero (Finset.mem_univ i) hzero) exact lt_of_le_of_ne (h.diag_nonneg i) (Ne.symm hne) -
porq_row_splittheorem — Row-split of a PORQ factorization. Splitting off the diagonal term, the i-th row of H is Rᵢᵢ • qᵢ plus a combination of the *other* rows qₖ (k ≠ i); by supp only the strict ancestors i ≺ k contribute, so this is exactly the triangular equation hᵢ = Rᵢᵢ qᵢ + ∑_{i ≺ k} Rᵢₖ qₖ. It is the membership half of the orthogonal-decomposition uniqueness argument.hypothesesconclusionS.H i = R i i • Q i + ∑ k ∈ Finset.univ.erase i, R i k • Q kProof (Lean source)
theorem porq_row_split (S : Solution d p K) {R : Matrix (Fin d) (Fin d) ℝ} {Q : Matrix (Fin d) (Fin p) ℝ} (h : IsPORQ S R Q) (i : Fin d) : S.H i = R i i • Q i + ∑ k ∈ Finset.univ.erase i, R i k • Q k := by have hrow : S.H i = ∑ k, R i k • Q k := by rw [h.factor, Matrix.mul_apply_eq_vecMul, Matrix.vecMul_eq_sum] rw [hrow, ← Finset.add_sum_erase univ (fun k => R i k • Q k) (Finset.mem_univ i)] -
porqResidual_eqtheorem — Unfolding equation for porqResidual: it is toLp hᵢ minus its orthogonal projection onto the ancestor span porqAncSpan i.hypothesesconclusionporqResidual S iProof (Lean source)
theorem porqResidual_eq (S : Solution d p K) (i : Fin d) : porqResidual S i = (toLp 2 (S.H i) : EuclideanSpace ℝ (Fin p)) - (porqAncSpan S i).starProjection (toLp 2 (S.H i)) := by rw [porqResidual, porqAncSpan] -
porqResidual_mem_ancSpantheorem — Each strict-ancestor residual lies in the ancestor span porqAncSpan i.hypothesesconclusionporqResidual S k ∈ porqAncSpan S iProof (Lean source)
theorem porqResidual_mem_ancSpan (S : Solution d p K) {i k : Fin d} (hk : S.prec i k) : porqResidual S k ∈ porqAncSpan S i := by classical rw [porqAncSpan] exact Submodule.subset_span ⟨⟨k, hk⟩, rfl⟩ -
porqResidual_mem_orthogonaltheorem — The i-th residual is orthogonal to its ancestor span: porqResidual i ∈ (Wᵢ)ᗮ.hypothesesconclusionporqResidual S i ∈ (porqAncSpan S i)ᗮProof (Lean source)
theorem porqResidual_mem_orthogonal (S : Solution d p K) (i : Fin d) : porqResidual S i ∈ (porqAncSpan S i)ᗮ := by rw [porqResidual_eq] exact Submodule.sub_starProjection_mem_orthogonal _ -
porqResidual_orthogonaltheorem — Orthogonality along the order. The i-th residual is orthogonal to every strict-ancestor residual porqResidual k (i ≺ k), since the latter lies in Wᵢ and the former in (Wᵢ)ᗮ.hypothesesconclusionProof (Lean source)
theorem porqResidual_orthogonal (S : Solution d p K) {i k : Fin d} (hk : S.prec i k) : (inner ℝ (porqResidual S i) (porqResidual S k) : ℝ) = 0 := by rw [real_inner_comm] exact Submodule.inner_right_of_mem_orthogonal (porqResidual_mem_ancSpan S hk) (porqResidual_mem_orthogonal S i) -
toLp_H_linearIndependenttheorem — The images of the rows of H under toLp are linearly independent (full row rank of H transported through the linear isomorphism toLp).hypothesesconclusionProof (Lean source)
theorem toLp_H_linearIndependent (S : Solution d p K) : LinearIndependent ℝ (fun j : Fin d => (toLp 2 (S.H j) : EuclideanSpace ℝ (Fin p))) := by have hker : ((WithLp.linearEquiv 2 ℝ (Fin p → ℝ)).symm.toLinearMap).ker = ⊥ := LinearMap.ker_eq_bot.mpr (WithLp.linearEquiv 2 ℝ (Fin p → ℝ)).symm.injective have h := S.hH.map' (WithLp.linearEquiv 2 ℝ (Fin p → ℝ)).symm.toLinearMap hker exact h -
porqResidual_mem_HspanLEtheorem — The i-th residual lies in the span of {toLp hₘ : i ⪯ m} (the row itself and its strict ancestors). Proved by strong induction on the reversed Fin d order: the diagonal term is toLp hᵢ, and the projection lives in Wᵢ, whose generators porqResidual k (i ≺ k) lie, by induction, in span {toLp hₘ : k ⪯ m} ⊆ span {toLp hₘ : i ⪯ m} (by transitivity of ⪯).hypothesesconclusionProof (Lean source)
theorem porqResidual_mem_HspanLE (S : Solution d p K) (i : Fin d) : porqResidual S i ∈ span ℝ {x | ∃ m, S.preceq i m ∧ x = (toLp 2 (S.H m) : EuclideanSpace ℝ (Fin p))} := by induction i using WellFoundedGT.induction with | _ i hIH => rw [porqResidual_eq] apply Submodule.sub_mem · exact Submodule.subset_span ⟨i, inl rfl, rfl⟩ · -- The projection lies in `Wᵢ`, which is contained in the target span. have hproj : (porqAncSpan S i).starProjection (toLp 2 (S.H i)) ∈ porqAncSpan S i := Submodule.starProjection_apply_mem _ _ have hsub : porqAncSpan S i ≤ span ℝ {x | ∃ m, S.preceq i m ∧ x = (toLp 2 (S.H m) : EuclideanSpace ℝ (Fin p))} := by rw [porqAncSpan, Submodule.span_le] rintro x ⟨⟨k, hik⟩, rfl⟩ -- `porqResidual k ∈ span {toLp hₘ : k ⪯ m} ⊆ span {toLp hₘ : i ⪯ m}`. have hk := hIH k (S.prec_lt hik) refine Submodule.span_mono ?_ hk rintro y ⟨m, hkm, rfl⟩ refine ⟨m, ?_, rfl⟩ rcases hkm with rfl | hkm · exact inr hik · exact inr (Relation.TransGen.trans hkm hik) exact hsub hproj -
porqResidual_ne_zerotheorem — Non-vanishing of the residual. porqResidual i ≠ 0: if it were zero then toLp hᵢ would lie in Wᵢ ⊆ span {toLp hₘ : i ≺ m}, contradicting the linear independence of {toLp hⱼ} (a member is never in the span of the strictly-others).hypothesesconclusionporqResidual S i ≠ 0Proof (Lean source)
theorem porqResidual_ne_zero (S : Solution d p K) (i : Fin d) : porqResidual S i ≠ 0 := by intro hzero -- From `porqResidual i = 0`, `toLp hᵢ` equals its projection, hence lies in `Wᵢ`. have hmem : (toLp 2 (S.H i) : EuclideanSpace ℝ (Fin p)) ∈ porqAncSpan S i := by have := porqResidual_eq S i rw [hzero] at this have heq : (toLp 2 (S.H i) : EuclideanSpace ℝ (Fin p)) = (porqAncSpan S i).starProjection (toLp 2 (S.H i)) := eq_of_sub_eq_zero this.symm rw [heq] exact Submodule.starProjection_apply_mem _ _ -- `Wᵢ ⊆ span {toLp hₘ : i ≺ m}`, so `toLp hᵢ ∈ span {toLp hₘ : m ≠ i}`. have hsub : porqAncSpan S i ≤ span ℝ ((fun j : Fin d => (toLp 2 (S.H j) : EuclideanSpace ℝ (Fin p))) '' {j | j ≠ i}) := by rw [porqAncSpan, Submodule.span_le] rintro x ⟨⟨k, hik⟩, rfl⟩ have hk := porqResidual_mem_HspanLE S k refine Submodule.span_mono ?_ hk rintro y ⟨m, hkm, rfl⟩ refine ⟨m, ?_, rfl⟩ -- `k ⪯ m` and `i ≺ k` give `i ≺ m`, so `m ≠ i`. have him : S.prec i m := by rcases hkm with rfl | hkm · exact hik · exact Relation.TransGen.trans hkm hik exact fun hmi => S.not_prec_self i (hmi ▸ him) have hmem' : (toLp 2 (S.H i) : EuclideanSpace ℝ (Fin p)) ∈ span ℝ ((fun j : Fin d => (toLp 2 (S.H j) : EuclideanSpace ℝ (Fin p))) '' {j | j ≠ i}) := hsub hmem -- Contradiction with linear independence of `{toLp hⱼ}`. exact (toLp_H_linearIndependent S).notMem_span_image (by simp) hmem' -
porq_rowCoeffstheorem — Row coefficients of the existence factorization. Writing qₘ = ‖rₘ‖⁻¹ • rₘ for the normalized residuals, the row toLp hᵢ decomposes as ‖rᵢ‖ • qᵢ + ∑_{i ≺ k} (coefficient) • qₖ: the diagonal coefficient is the residual norm ‖rᵢ‖ ≥ 0, the off-diagonal coefficients are supported on the strict ancestors i ≺ k, and there are none off ⪯. This packages factor, diag_nonneg and supp into one existence statement (the i-th row of R).hypothesesconclusion∃ c : Fin d → ℝ,conclusion 1j :¬ S.preceq i jc j = 0conclusion 2c i = ‖porqResidual S i‖conclusion 3= ∑ m, c m • ((‖porqResidual S m‖)⁻¹ • porqResidual S m)Proof (Lean source)
theorem porq_rowCoeffs (S : Solution d p K) (i : Fin d) : ∃ c : Fin d → ℝ, (∀ j, ¬ S.preceq i j → c j = 0) ∧ c i = ‖porqResidual S i‖ ∧ (toLp 2 (S.H i) : EuclideanSpace ℝ (Fin p)) = ∑ m, c m • ((‖porqResidual S m‖)⁻¹ • porqResidual S m) := by classical set q : Fin d → EuclideanSpace ℝ (Fin p) := fun m => (‖porqResidual S m‖)⁻¹ • porqResidual S m with hq have hrne : ∀ m, porqResidual S m ≠ 0 := porqResidual_ne_zero S have hnne : ∀ m, ‖porqResidual S m‖ ≠ 0 := fun m => norm_ne_zero_iff.mpr (hrne m) -- `rₘ = ‖rₘ‖ • qₘ`. have hrq : ∀ m, porqResidual S m = ‖porqResidual S m‖ • q m := by intro m rw [hq] simp only rw [smul_smul, mul_inv_cancel₀ (hnne m), one_smul] -- The projection lies in `Wᵢ = span (range rₖ)`; extract subtype coefficients. have hproj : (porqAncSpan S i).starProjection (toLp 2 (S.H i)) ∈ porqAncSpan S i := Submodule.starProjection_apply_mem _ _ rw [porqAncSpan, Submodule.mem_span_range_iff_exists_fun] at hproj obtain ⟨c0, hc0⟩ := hproj rw [← porqAncSpan] at hc0 -- Assemble the `Fin d`-indexed coefficient vector. refine ⟨fun m => if m = i then ‖porqResidual S i‖ else if h : S.prec i m then c0 ⟨m, h⟩ * ‖porqResidual S m‖ else 0, ?_, ?_, ?_⟩ · -- support on `⪯` intro j hj have hji : j ≠ i := fun h => hj (inl h.symm) have hnp : ¬ S.prec i j := fun h => hj (inr h) simp only [hji, if_false, hnp, dite_false] · -- diagonal simp · -- factor -- `toLp hᵢ = rᵢ + proj`. have hsplit : (toLp 2 (S.H i) : EuclideanSpace ℝ (Fin p)) = porqResidual S i + (porqAncSpan S i).starProjection (toLp 2 (S.H i)) := by rw [porqResidual_eq]; abel rw [hsplit, ← hc0] -- Split the universe sum off the diagonal `m = i`. rw [← Finset.add_sum_erase univ _ (Finset.mem_univ i)] beta_reduce -- Diagonal: `‖rᵢ‖ • qᵢ = rᵢ`. rw [if_pos rfl, smul_smul, mul_inv_cancel₀ (hnne i), one_smul] congr 1 -- Off-diagonal: the erased sum equals `∑ k, c0 k • r_k` (subtype reindexing). -- The common summand `f m = if prec i m then c0⟨m,_⟩ • r_m else 0`. set f : Fin d → EuclideanSpace ℝ (Fin p) := fun m => if h : S.prec i m then c0 ⟨m, h⟩ • porqResidual S m else 0 with hf -- Step 1: each erased term equals `f m`. have hterm : ∀ m ∈ Finset.univ.erase i, (if m = i then ‖porqResidual S i‖ else if h : S.prec i m then c0 ⟨m, h⟩ * ‖porqResidual S m‖ else 0) • ((‖porqResidual S m‖)⁻¹ • porqResidual S m) = f m := by intro m hm have hmi : m ≠ i := Finset.ne_of_mem_erase hm simp only [hf, if_neg hmi] by_cases hpm : S.prec i m · rw [dif_pos hpm, dif_pos hpm, smul_smul, mul_assoc, mul_inv_cancel₀ (hnne m), mul_one] · rw [dif_neg hpm, dif_neg hpm, zero_smul] rw [Finset.sum_congr rfl hterm] -- Step 2: drop the terms off the ancestor filter (f vanishes there). have hvanish : ∀ m ∈ Finset.univ.erase i, f m ≠ 0 → S.prec i m := by intro m _ hfm by_contra hpm exact hfm (by simp only [hf, dif_neg hpm]) rw [← Finset.sum_filter_of_ne hvanish] -- Step 3: reindex the filter sum to the subtype sum. have hmem_iff : ∀ m, m ∈ (Finset.univ.erase i).filter (fun m => S.prec i m) ↔ S.prec i m := by intro m rw [mem_filter] refine ⟨fun hm => hm.2, fun hm => ⟨?_, hm⟩⟩ exact Finset.mem_erase.mpr ⟨fun h => S.not_prec_self i (h ▸ hm), Finset.mem_univ m⟩ rw [Finset.sum_subtype _ hmem_iff f] -- `f ↑k = c0 k • r_k`. refine Finset.sum_congr rfl fun k _ => ?_ simp only [hf, dif_pos k.2]
Identifiability 1 core · 0 supporting Flagship Theorem 2. ★ disentanglement_identifiability
Linear causal disentanglement: identifiability up to S(𝒢) and signed scaling
Flagship Theorem 2.
The headline result of Squires, Seigal, Bhate & Uhler, Linear Causal Disentanglement
via Interventions (ICML 2023), Theorem 2 (thm:main_id_non_constructive), in its
algebraic (matrix-level) form.
Under Assumption 1 (linear latent model, single-node interventions, linear
observations) and Assumption 2 (perfect interventions), with one intervention per
latent node, the latent graph and intervention targets are identifiable up to
S(𝒢), the order-preserving relabelings, while the latent directions are identifiable
only up to nonzero signed diagonal scaling. The signed diagonal is unavoidable because
the observable precision matrices are even in H.
The (⊆) inclusion is disentanglement_uniqueness; the (⊇) inclusion is
sigma_solutions.
Linear causal disentanglement identifiability (Theorem 2). Let S and S' be two solutions of the linear causal disentanglement model such that each solution's intervention-target map is a bijection onto the latent coordinates, i.e. one intervention per latent node and S's interventions are non-degenerate (the paper's genericity / Assumption 1(b)): every intervened precision matrix Θ_k differs from the observational precision matrix Θ_0. If S and S' share the same observational precision matrix and agree, context by context, on every interventional precision matrix, then S and S' are related by a single order-preserving relabeling σ of the latent coordinates, a nonzero scaling vector μ, and a ±1 sign vector ν: σ, μ, ν transport S's latent-direction matrix and structural coefficient matrices onto S''s, and σ carries S's intervention targets onto S''s.
Formal statement
Proof (Lean source)
KeyIdentity 1 core · 1 supporting The algebraic backbone of the identifiability results (Squires–Seigal–Bhate–Uhler, §3.1). ★ key_identity
Linear causal disentanglement: the key rank-one identity
The algebraic backbone of the identifiability results (Squires–Seigal–Bhate–Uhler,
§3.1). fact_transpose_mul is the rank-one decomposition BᵀB = Σᵢ (Bᵀeᵢ)⊗²;
key_identity (their Proposition driving everything) computes the difference of
precision matrices between an interventional and the observational context as a
difference of two rank-one (outer-product) matrices, using that a single-node
intervention changes only one row of B.
Key identity (Proposition). For a linear causal disentanglement solution and an interventional context k with target iₖ, the difference of precision matrices Θ_k − Θ₀ equals exactly the difference between two outer products: one built from the target row of the interventional structural matrix, and one built from the target row of the observational structural matrix.
Formal statement
Proof (Lean source)
1 supporting declaration (lemmas, instances)
-
fact_transpose_multheorem — Fact (rank-one decomposition). For any square B, BᵀB = Σᵢ (Bᵀeᵢ)⊗², where v⊗² = v vᵀ (Matrix.vecMulVec v v).hypothesesProof (Lean source)
theorem fact_transpose_mul (B : Matrix (Fin d) (Fin d) ℝ) : B.transpose * B = ∑ i, vecMulVec (B.transpose *ᵥ stdVec d i) (B.transpose *ᵥ stdVec d i) := by ext a b simp only [Matrix.mul_apply, Matrix.transpose_apply, Matrix.sum_apply, Matrix.vecMulVec_apply, stdVec, Matrix.mulVec_single_one, Matrix.col_apply]
Rowspan 6 core · 0 supporting The technical heart linking the *observable* precision differences to the *latent* graph structure (their Lemma 1). ★ rowspan_inclusion_a★ rowspan_inclusion_b★ rowspan_inclusion_c
Linear causal disentanglement: the rowspan inclusion lemma (Lemma 1)
The technical heart linking the observable precision differences to the latent
graph structure (their Lemma 1). By key_identity, rowspan(Θₖ − Θ₀) is spanned by
the two vectors Hᵀ Bₖᵀ e_{iₖ}, Hᵀ B₀ᵀ e_{iₖ}, both lying in ⟨hᵢ : i ∈ Pa(iₖ)⟩.
Full row rank of H makes this containment characterize the parent set:
* (a) rowspan(Θₖ − Θ₀) ⊆ ⟨hᵢ : i ∈ 𝓘⟩ iff Pa(iₖ) ⊆ 𝓘;
* (b) rowspan(Θₖ − Θ₀) ⊆ ⟨qᵢ : i ∈ An(iₖ)⟩;
* (c) if the intervention changes the precision matrix, 𝓘 is ancestor-closed, and
Pa(iₖ) ⊄ 𝓘, then rowspan(Θₖ − Θ₀) ⊄ ⟨qᵢ : i ∈ 𝓘⟩.
The file also defines the three spans used in those statements: rowSpan for rows
of an observable precision-difference matrix, hSpan for selected rows of the
mixing pseudoinverse H, and qSpan for selected rows of a partial-order RQ
factor Q.
For a nonnegative integer observed dimension and a real square matrix of that dimension, the row span is the real linear subspace generated by all rows of the matrix.
For a linear causal disentanglement solution with d latent variables, p observed variables, and K intervention contexts and a set of latent-node indices, the selected mixing-row span is the real linear subspace generated by the mixing-pseudoinverse rows indexed by that set.
For a nonnegative latent dimension, a nonnegative observed dimension, a real matrix with d rows and p columns, and a set of latent-row indices, the selected RQ-row span is the real linear subspace generated by the rows indexed by that set.
Lemma 1(a). For a solution S, an intervention k, and a set of latent indices I, provided the intervention actually changes the observational precision matrix, Θₖ ≠ Θ₀ (the paper's genericity / Assumption (b)), the row span of the precision difference Θₖ − Θ₀ is contained in the span of the rows of the mixing pseudoinverse H indexed by I if and only if the parent set of the intervened target node is contained in I.
Formal statement
Proof (Lean source)
Lemma 1(b). For a solution S, an intervention k, and any partial order RQ decomposition of S's latent-direction matrix H, witnessed by R and Q, the row span of the precision difference Θₖ − Θ₀ is contained in the span of the rows of Q indexed by the ancestor set of the intervened target node.
Formal statement
Proof (Lean source)
Lemma 1(c). For a solution S, an intervention k, and a set of latent indices I, given a partial order RQ decomposition of S's latent-direction matrix H, witnessed by R and Q, the non-degeneracy condition Θₖ ≠ Θ₀ (the paper's genericity / Assumption (b)), that I is ancestor-closed, and that the parent set of the intervened target node is not contained in I, then the row span of the precision difference Θₖ − Θ₀ is not contained in the span of the rows of Q indexed by I.
Formal statement
Proof (Lean source)
SigmaSolutions 2 core · 0 supporting This file proves the solution-orbit direction of the linear-disentanglement identifiability result. ★ sigma_solutions
Linear causal disentanglement: solution orbits under order-preserving permutations
This file proves the solution-orbit direction of the linear-disentanglement
identifiability result. The definition Solution.permute constructs the
relabelled model: it sends H to Pσ H, conjugates B₀ and every Bₖ by the
permutation matrix, and sends each intervention target iₖ to σ(iₖ). The
order-preservation hypothesis σ ∈ S(𝒢) is exactly what keeps the transformed
observational matrix triangular in the ambient node order.
The theorem sigma_solutions then proves that this transformed solution has the
same observable precision matrices Θ₀ and Θₖ. Together with
disentanglement_identifiability, it gives the orbit characterization of all
solutions.
For a linear causal disentanglement solution with d latent variables, p observed variables, and K intervention contexts, a permutation of its latent-node indices, and the condition that this permutation preserves the directed node order, the permuted solution is a linear causal disentanglement solution obtained by relabeling every latent coordinate with that permutation. Its mixing pseudoinverse is the row-permuted original, its observational structural matrix is the original conjugated by the permutation matrix, its interventional structural matrices are conjugated in the same way, and its intervention targets are relabeled by the permutation.
Definition (Lean source)
For a solution S and a permutation σ of the latent coordinates such that σ is order-preserving, i.e. lies in the paper's group S(𝒢), the relabeled solution obtained by applying σ to S produces exactly the same observational precision matrix Θ₀, and for every intervention k the same interventional precision matrix Θₖ, as S itself.
Formal statement
Proof (Lean source)
Uniqueness 2 core · 38 supporting This is the hard half of the flagship: any two parameter tuples producing the same family of precision matrices {Θ_k} differ by a single order-preserving relabeling σ ∈ S(𝒢). ★ disentanglement_uniqueness
Linear causal disentanglement: uniqueness (⊆ direction of Theorem 2)
This is the hard half of the flagship: any two parameter tuples producing the same
family of precision matrices {Θ_k} differ by a single order-preserving relabeling
σ ∈ S(𝒢). The proof follows the constructive argument of the paper:
1. recover the orthogonal factor Q of a partial order RQ decomposition of H, up
to S(𝒢) and signs, from the spans rowspan(Θₖ − Θ₀) (rowspan_inclusion);
2. orthogonalize: (Q⁺)ᵀ Θₖ Q⁺ is the Cholesky factor of the latent precision, which
recovers R and hence H = R Q up to S(𝒢);
3. read off {Bₖ} from H and {Θₖ} via Cholesky factorization.
The main public declarations expose these stages. exists_change_of_basis
recovers the invertible matrix M with H' = M H; gram_identity and
gram_diff_transport move the precision equalities down to latent d × d
Gram identities; central_rank2_eq rewrites those identities in rank-two
outer-product form; exists_orderPerm performs the orthogonal-correctness
collapse and reads off the target relabeling; and disentanglement_uniqueness
packages the final signed-monomial conclusion.
The order-preservation pinning runs the same triangular-support logic as
Causalean.Mathlib.LinearAlgebra.perm_uniqueness: positive diagonals,
triangularity, and nonzero support entries force the recovered relabeling to lie
in S(𝒢).
For a linear causal disentanglement solution with d latent variables, p observed variables, and K intervention contexts and an intervention context, the perfect-intervention perturbation row assigns to each latent node the intervention scaling times the standard-basis indicator of the target node, minus the corresponding entry of the observational structural matrix.
Uniqueness (⊆ direction of Theorem 2). Let S and S' be two solutions of the linear causal disentanglement model such that each solution's intervention-target map is a bijection onto the latent coordinates, i.e. one intervention per latent node and S's interventions are non-degenerate (the paper's genericity / Assumption 1(b)): every intervened precision matrix Θ_k differs from the observational precision matrix Θ_0. If S and S' share the same observational precision matrix and agree, context by context, on every interventional precision matrix, then S and S' are related by a single order-preserving relabeling σ of the latent coordinates, a nonzero scaling vector μ, and a ±1 sign vector ν, transporting S's latent-direction and structural coefficient matrices onto S''s, with σ carrying S's intervention targets onto S''s.
Formal statement
Proof (Lean source)
38 supporting declarations (lemmas, instances)
-
gram_to_orthogonaltheorem — (L3) Gram ⟹ orthogonal. If XᵀX = YᵀY with X, Y invertible, then the transition matrix O = Y X⁻¹ is orthogonal: Oᵀ O = 1. This is the algebraic step that turns the equality of Gram matrices BᵀB = (B' M)ᵀ(B' M) into an orthogonality statement about O = B' M B⁻¹.hypothesesconclusion(Y * X⁻¹)ᵀ * (Y * X⁻¹) = 1Proof (Lean source)
theorem gram_to_orthogonal {q : ℕ} {X Y : Matrix (Fin q) (Fin q) ℝ} [Invertible X] [Invertible Y] (h : Xᵀ * X = Yᵀ * Y) : (Y * X⁻¹)ᵀ * (Y * X⁻¹) = 1 := by rw [Matrix.transpose_mul, Matrix.mul_assoc, ← Matrix.mul_assoc Yᵀ Y, ← h, Matrix.mul_assoc Xᵀ, Matrix.mul_inv_of_invertible, Matrix.mul_one, Matrix.transpose_nonsing_inv, Matrix.inv_mul_of_invertible] -
B0_blockTriangulartheorem — B0 is upper triangular in the BlockTriangular id sense.hypothesesconclusionS.B0.BlockTriangular idProof (Lean source)
theorem B0_blockTriangular (S : Solution d p K) : S.B0.BlockTriangular id := S.hB0up -
Bint_blockTriangulartheorem — Bint k is upper triangular: the perfect intervention only rewrites the target row (which keeps the diagonal at λₖ and zeroes the strictly-lower entries already zero in B0).hypothesesconclusion(S.Bint k).BlockTriangular idProof (Lean source)
theorem Bint_blockTriangular (S : Solution d p K) (k : Fin K) : (S.Bint k).BlockTriangular id := by intro i j hji simp only [id_eq] at hji rw [S.hInt k, Matrix.add_apply, S.hB0up i j hji, zero_add, Matrix.vecMulVec_apply] by_cases hi : i = S.target k · -- target row: off-diagonal lower entries vanish since `j < i = target k` have hjlt : j < S.target k := hi ▸ hji have hjne : j ≠ S.target k := ne_of_lt hjlt rw [S.hB0up (S.target k) j hjlt] simp [stdVec, Pi.single_eq_of_ne hjne] · simp [stdVec, Pi.single_eq_of_ne hi] -
B0_det_postheorem — det B0 = ∏ᵢ (B0)ᵢᵢ > 0.Proof (Lean source)
theorem B0_det_pos (S : Solution d p K) : 0 < S.B0.det := by rw [Matrix.det_of_upperTriangular (B0_blockTriangular S)] exact Finset.prod_pos (fun i _ => S.hB0pos i) -
Bint_diag_postheorem — (Bint k)ᵢᵢ = (B0)ᵢᵢ off the target, and = λₖ on the target — in both cases strictly positive.hypothesesconclusion0 < S.Bint k i iProof (Lean source)
theorem Bint_diag_pos (S : Solution d p K) (k : Fin K) (i : Fin d) : 0 < S.Bint k i i := by rw [S.hInt k, Matrix.add_apply, Matrix.vecMulVec_apply] by_cases hi : i = S.target k · rw [hi] simp only [stdVec, Pi.single_eq_same, one_mul] have : S.B0 (S.target k) (S.target k) + (S.lam k * 1 - S.B0 (S.target k) (S.target k)) = S.lam k := by ring rw [this]; exact S.hlam k · simp only [stdVec, Pi.single_eq_of_ne hi, zero_mul, add_zero] exact S.hB0pos i -
Bint_det_postheorem — det (Bint k) = ∏ᵢ (Bint k)ᵢᵢ > 0.hypothesesconclusion0 < (S.Bint k).detProof (Lean source)
theorem Bint_det_pos (S : Solution d p K) (k : Fin K) : 0 < (S.Bint k).det := by rw [Matrix.det_of_upperTriangular (Bint_blockTriangular S k)] exact Finset.prod_pos (fun i _ => Bint_diag_pos S k i) -
B0_invertibleinstance — For every linear causal disentanglement solution, specified by natural numbers of latent variables, observed variables, and intervention contexts, an invertibility certificate for its observational structural matrix is constructed from that matrix's nonzero determinant. -
Bint_invertibleinstance — For every linear causal disentanglement solution, specified by natural numbers of latent variables, observed variables, and intervention contexts and every intervention context in that solution, an invertibility certificate for the corresponding interventional structural matrix is constructed from that matrix's nonzero determinant.parametersinstancegiven by(S.Bint k).invertibleOfIsUnitDet (isUnit_iff_ne_zero.mpr (Bint_det_pos S k).ne') -
vecMul_H_injectivetheorem — vecMul · H is injective (full row rank of H).hypothesesProof (Lean source)
theorem vecMul_H_injective (S : Solution d p K) : Injective (fun v => vecMul v S.H) := Matrix.vecMul_injective_iff.mpr (by rw [Matrix.row_def]; exact S.hH) -
HHt_posDeftheorem — The latent Gram matrix H Hᵀ is positive definite.hypothesesconclusion(S.H * S.H.transpose).PosDefProof (Lean source)
theorem HHt_posDef (S : Solution d p K) : (S.H * S.H.transpose).PosDef := by have := Matrix.PosDef.mul_conjTranspose_self S.H (vecMul_H_injective S) rwa [Matrix.conjTranspose_eq_transpose_of_trivial] at this -
HHt_invertibleinstance — For every linear causal disentanglement solution, specified by natural numbers of latent variables, observed variables, and intervention contexts, an invertibility certificate for the Gram matrix of its mixing pseudoinverse is constructed from that Gram matrix's positive definiteness.parametersinstancegiven by(S.H * S.H.transpose).invertibleOfIsUnitDet ((Matrix.isUnit_iff_isUnit_det _).mp (HHt_posDef S).isUnit) -
B0H_gram_invertibleinstance — For every linear causal disentanglement solution, specified by natural numbers of latent variables, observed variables, and intervention contexts, an invertibility certificate for the Gram matrix of the product of its observational structural matrix and mixing pseudoinverse is constructed as a product of invertible matrices.parametersinstancegiven byby rw [Matrix.transpose_mul, ← Matrix.mul_assoc, Matrix.mul_assoc S.B0] exact ((B0_invertible S).mul (HHt_invertible S)).mul (inferInstanceAs (Invertible S.B0.transpose)) -
H_mul_rightInvtheorem — R := Hᵀ (H Hᵀ)⁻¹ is a right inverse of H: H R = 1.hypothesesconclusionS.H * (S.H.transpose * (S.H * S.H.transpose)⁻¹) = 1Proof (Lean source)
theorem H_mul_rightInv (S : Solution d p K) : S.H * (S.H.transpose * (S.H * S.H.transpose)⁻¹) = 1 := by rw [← Matrix.mul_assoc, Matrix.mul_inv_of_invertible] -
leftInv_mul_Httheorem — L := (H Hᵀ)⁻¹ H is a left inverse of Hᵀ: L Hᵀ = 1.hypothesesconclusion((S.H * S.H.transpose)⁻¹ * S.H) * S.H.transpose = 1Proof (Lean source)
theorem leftInv_mul_Ht (S : Solution d p K) : ((S.H * S.H.transpose)⁻¹ * S.H) * S.H.transpose = 1 := by rw [Matrix.mul_assoc, Matrix.inv_mul_of_invertible] -
H_eq_recover_mul_Theta0theorem — The recovery identity H = W Θ₀. With C = B₀ H and Θ₀ = Cᵀ C, the matrix W = B₀⁻¹ (C Cᵀ)⁻¹ C satisfies W Θ₀ = H.hypothesesconclusion(S.B0⁻¹ * ((S.B0 * S.H) * (S.B0 * S.H).transpose)⁻¹ * (S.B0 * S.H)) * S.Theta0 = S.HProof (Lean source)
theorem H_eq_recover_mul_Theta0 (S : Solution d p K) : (S.B0⁻¹ * ((S.B0 * S.H) * (S.B0 * S.H).transpose)⁻¹ * (S.B0 * S.H)) * S.Theta0 = S.H := by have hΘ : S.Theta0 = (S.B0 * S.H).transpose * (S.B0 * S.H) := by simp only [Solution.Theta0, Matrix.transpose_mul, Matrix.mul_assoc] rw [hΘ] set G := (S.B0 * S.H) * (S.B0 * S.H).transpose with hG rw [Matrix.mul_assoc (S.B0⁻¹ * G⁻¹), ← Matrix.mul_assoc (S.B0 * S.H), ← hG, ← Matrix.mul_assoc, Matrix.mul_assoc S.B0⁻¹, Matrix.inv_mul_of_invertible, Matrix.mul_one, ← Matrix.mul_assoc, Matrix.inv_mul_of_invertible, Matrix.one_mul] -
exists_change_of_basistheorem — (L1) The change-of-basis matrix. There is an invertible M with H' = M H. M is built from the recovery identity for H' (H' = W' Θ₀') by substituting Θ₀' = Θ₀ = Hᵀ B₀ᵀ B₀ H, giving H' = (W' Hᵀ B₀ᵀ B₀) H. Invertibility follows from the symmetric matrix N with H = N H' by right-cancelling the full-row-rank H/H'.hypothesesProof (Lean source)
theorem exists_change_of_basis (S S' : Solution d p K) (hΘ0 : S.Theta0 = S'.Theta0) : ∃ M : Matrix (Fin d) (Fin d) ℝ, IsUnit M ∧ S'.H = M * S.H := by -- `M := W' Hᵀ B₀ᵀ B₀` from `H' = W' Θ₀' = W' Θ₀ = W' (Hᵀ B₀ᵀ B₀ H)`. set W' := S'.B0⁻¹ * ((S'.B0 * S'.H) * (S'.B0 * S'.H).transpose)⁻¹ * (S'.B0 * S'.H) with hW' set N' := S.B0⁻¹ * ((S.B0 * S.H) * (S.B0 * S.H).transpose)⁻¹ * (S.B0 * S.H) with hN' have hH' : S'.H = (W' * S.H.transpose * S.B0.transpose * S.B0) * S.H := by have h1 : W' * S'.Theta0 = S'.H := H_eq_recover_mul_Theta0 S' rw [← hΘ0, Solution.Theta0] at h1 rw [← h1] simp only [Matrix.mul_assoc] have hH : S.H = (N' * S'.H.transpose * S'.B0.transpose * S'.B0) * S'.H := by have h1 : N' * S.Theta0 = S.H := H_eq_recover_mul_Theta0 S rw [hΘ0, Solution.Theta0] at h1 rw [← h1] simp only [Matrix.mul_assoc] set M := W' * S.H.transpose * S.B0.transpose * S.B0 with hM set N := N' * S'.H.transpose * S'.B0.transpose * S'.B0 with hN refine ⟨M, ?_, hH'⟩ -- `M` is a unit: `M N = 1` via right-cancellation by the full-row-rank `H`. have hMN : M * N = 1 := by have hcomp : (M * N) * S'.H = (1 : Matrix (Fin d) (Fin d) ℝ) * S'.H := by rw [Matrix.mul_assoc, ← hH, ← hH', Matrix.one_mul] -- right-cancel `H'` (it has right inverse `H'ᵀ (H' H'ᵀ)⁻¹`). have hrcancel : ∀ A B : Matrix (Fin d) (Fin d) ℝ, A * S'.H = B * S'.H → A = B := by intro A B hAB have h2 := congrArg (fun X => X * (S'.H.transpose * (S'.H * S'.H.transpose)⁻¹)) hAB simp only [Matrix.mul_assoc] at h2 rwa [H_mul_rightInv S', Matrix.mul_one, Matrix.mul_one] at h2 exact hrcancel _ _ hcomp exact IsUnit.of_mul_eq_one N hMN -
cancel_Ht_Htheorem — Left-cancel Hᵀ and right-cancel H in Hᵀ X H = Hᵀ Y H. H has full row rank, so Hᵀ has a left inverse and H a right inverse.hypothesesd :sharedℕp :sharedℕK :sharedℕS :Solution d p Kh :S.H.transpose * X * S.H = S.H.transpose * Y * S.HconclusionX = YProof (Lean source)
theorem cancel_Ht_H (S : Solution d p K) {X Y : Matrix (Fin d) (Fin d) ℝ} (h : S.H.transpose * X * S.H = S.H.transpose * Y * S.H) : X = Y := by set R := S.H.transpose * (S.H * S.H.transpose)⁻¹ with hR set L := (S.H * S.H.transpose)⁻¹ * S.H with hL -- right-cancel `H`: multiply by `R` on the right. have hr : S.H.transpose * X = S.H.transpose * Y := by have h2 := congrArg (fun Z => Z * R) h simp only [Matrix.mul_assoc] at h2 rwa [H_mul_rightInv S, Matrix.mul_one, Matrix.mul_one] at h2 -- left-cancel `Hᵀ`: multiply by `L` on the left. have h3 := congrArg (fun Z => L * Z) hr simp only [← Matrix.mul_assoc] at h3 rwa [leftInv_mul_Ht S, Matrix.one_mul, Matrix.one_mul] at h3 -
gram_identitytheorem — (L2) The per-context Gram identity. Given H' = M H and Θₖ = Θₖ' for the observational (B₀/B'₀) and interventional (Bₖ/B'ₖ) matrices, the d × d Gram identity BᵀB = (B' M)ᵀ (B' M) holds.hypothesesd :sharedℕp :sharedℕK :sharedℕS S' :Solution d p KhM :S'.H = M * S.HhΘ :S.H.transpose * B.transpose * B * S.H = S'.H.transpose * B'.transpose * B' * S'.HconclusionB.transpose * B = (B' * M).transpose * (B' * M)Proof (Lean source)
theorem gram_identity (S S' : Solution d p K) {M : Matrix (Fin d) (Fin d) ℝ} (hM : S'.H = M * S.H) {B B' : Matrix (Fin d) (Fin d) ℝ} (hΘ : S.H.transpose * B.transpose * B * S.H = S'.H.transpose * B'.transpose * B' * S'.H) : B.transpose * B = (B' * M).transpose * (B' * M) := by apply cancel_Ht_H S have e1 : S.H.transpose * (B.transpose * B) * S.H = S'.H.transpose * B'.transpose * B' * S'.H := by rw [← hΘ]; simp only [Matrix.mul_assoc] rw [e1, hM] simp only [Matrix.transpose_mul, Matrix.mul_assoc] -
Bint_sub_B0theorem — Rank-one perturbation. Bₖ − B₀ = e_{iₖ} cₖᵀ (Matrix.vecMulVec): a perfect single-node intervention rewrites only the target row of B₀.hypotheses -
cvec_ne_zerotheorem — (C, target-row form / sub-lemma (B)). The perturbation row is non-degenerate exactly when the intervention changes the precision matrix. Under Θₖ ≠ Θ₀, cₖ ≠ 0 (equivalently Bₖ ≠ B₀): if cₖ = 0 then Bₖ = B₀, hence Θₖ = Θ₀.hypothesesconclusioncvec S k ≠ 0Proof (Lean source)
theorem cvec_ne_zero (S : Solution d p K) (k : Fin K) (hk : S.Theta k ≠ S.Theta0) : cvec S k ≠ 0 := by intro hc apply hk have hBeq : S.Bint k = S.B0 := by have := Bint_sub_B0 S k rw [hc, Matrix.vecMulVec_zero] at this exact sub_eq_zero.mp this rw [Solution.Theta, Solution.Theta0, hBeq] -
Bint_transpose_mulVec_targettheorem — (B) Target row of Bₖ. (Bₖ)ᵀ *ᵥ e_{iₖ} = λₖ • e_{iₖ}: the iₖ-th row of a perfect-intervention matrix is λₖ e_{iₖ}ᵀ (the intervention zeroes the parent entries and sets the diagonal to λₖ).hypothesesProof (Lean source)
theorem Bint_transpose_mulVec_target (S : Solution d p K) (k : Fin K) : (S.Bint k).transpose *ᵥ stdVec d (S.target k) = (S.lam k) • stdVec d (S.target k) := by funext j rw [Matrix.mulVec_transpose, Matrix.vecMul_eq_sum] simp only [stdVec, Finset.sum_apply, Pi.smul_apply, smul_eq_mul, Pi.single_apply] rw [Finset.sum_eq_single (S.target k)] · by_cases hj : j = S.target k · rw [hj, S.hInt k]; simp [Matrix.add_apply, Matrix.vecMulVec_apply, stdVec] · simp only [if_neg hj, mul_zero] rw [S.hInt k]; simp [Matrix.add_apply, Matrix.vecMulVec_apply, stdVec, hj] · intro x _ hx; simp [if_neg hx] · intro hx; exact absurd (Finset.mem_univ _) hx -
latent_key_identitytheorem — (C) Latent key identity. At the d × d (latent) level the difference of Gram matrices is a difference of two rank-one (outer-product) matrices: BₖᵀBₖ − B₀ᵀB₀ = λₖ² (e_{iₖ} e_{iₖ}ᵀ) − wₖ wₖᵀ where wₖ = B₀ᵀ *ᵥ e_{iₖ} is the iₖ-th row of B₀ (supported on Pa(iₖ)). This is the latent analogue of key_identity, and the structural engine of the orthogonal-correctness core.hypothesesProof (Lean source)
theorem latent_key_identity (S : Solution d p K) (k : Fin K) : (S.Bint k).transpose * S.Bint k - S.B0.transpose * S.B0 = (S.lam k) ^ 2 • vecMulVec (stdVec d (S.target k)) (stdVec d (S.target k)) - vecMulVec (S.B0.transpose *ᵥ stdVec d (S.target k)) (S.B0.transpose *ᵥ stdVec d (S.target k)) := by -- Off-target rows of `Bₖ` agree with `B₀`, so the rank-one decompositions cancel except -- in the target row (mirrors the latent step inside `key_identity`). set i := S.target k with hi have hrow : ∀ l : Fin d, l ≠ i → ((S.Bint k).transpose *ᵥ stdVec d l) = (S.B0.transpose *ᵥ stdVec d l) := by intro l hl have hl' : l ≠ S.target k := hi ▸ hl funext a rw [S.hInt k] simp only [stdVec, Matrix.mulVec_single_one, Matrix.col_apply, Matrix.transpose_apply, Matrix.add_apply, Matrix.vecMulVec_apply, Pi.single_eq_of_ne hl', zero_mul, add_zero] rw [fact_transpose_mul (S.Bint k), fact_transpose_mul S.B0, ← Finset.add_sum_erase _ _ (Finset.mem_univ i), ← Finset.add_sum_erase _ _ (Finset.mem_univ i)] have hcancel : (∑ l ∈ Finset.univ.erase i, vecMulVec ((S.Bint k).transpose *ᵥ stdVec d l) ((S.Bint k).transpose *ᵥ stdVec d l)) = ∑ l ∈ Finset.univ.erase i, vecMulVec (S.B0.transpose *ᵥ stdVec d l) (S.B0.transpose *ᵥ stdVec d l) := by refine Finset.sum_congr rfl (fun l hl => ?_) rw [hrow l (Finset.ne_of_mem_erase hl)] rw [hcancel, Bint_transpose_mulVec_target, Matrix.vecMulVec_smul, Matrix.smul_vecMulVec, smul_smul, ← pow_two] abel -
transition_orthogonaltheorem — (D) The transition factor is orthogonal. From the per-context Gram identity BₖᵀBₖ = (B'ₖ M)ᵀ(B'ₖ M) and invertibility, Oₖ = B'ₖ M Bₖ⁻¹ satisfies Oₖᵀ Oₖ = 1.hypothesesd :sharedℕp :sharedℕK :sharedℕS S' :Solution d p KhM :S'.H = M * S.HB B' :hΘ :S.H.transpose * B.transpose * B * S.H = S'.H.transpose * B'.transpose * B' * S'.Hconclusion((B' * M) * B⁻¹)ᵀ * ((B' * M) * B⁻¹) = 1Proof (Lean source)
theorem transition_orthogonal (S S' : Solution d p K) {M : Matrix (Fin d) (Fin d) ℝ} (hM : S'.H = M * S.H) {B B' : Matrix (Fin d) (Fin d) ℝ} [Invertible B] [Invertible (B' * M)] (hΘ : S.H.transpose * B.transpose * B * S.H = S'.H.transpose * B'.transpose * B' * S'.H) : ((B' * M) * B⁻¹)ᵀ * ((B' * M) * B⁻¹) = 1 := gram_to_orthogonal (gram_identity S S' hM hΘ) -
gram_identity_conjtheorem — The per-context Gram identity in the symmetric form BᵀB = Mᵀ B'ᵀ B' M (the conjugation form of gram_identity).hypothesesd :sharedℕp :sharedℕK :sharedℕS S' :Solution d p KhM :S'.H = M * S.HhΘ :S.H.transpose * B.transpose * B * S.H = S'.H.transpose * B'.transpose * B' * S'.HconclusionB.transpose * B = M.transpose * (B'.transpose * B') * MProof (Lean source)
theorem gram_identity_conj (S S' : Solution d p K) {M : Matrix (Fin d) (Fin d) ℝ} (hM : S'.H = M * S.H) {B B' : Matrix (Fin d) (Fin d) ℝ} (hΘ : S.H.transpose * B.transpose * B * S.H = S'.H.transpose * B'.transpose * B' * S'.H) : B.transpose * B = M.transpose * (B'.transpose * B') * M := by rw [gram_identity S S' hM hΘ, Matrix.transpose_mul] simp only [Matrix.mul_assoc] -
gram_diff_transporttheorem — (R1) Latent Gram-difference transport. Bₖᵀ Bₖ − B₀ᵀ B₀ = Mᵀ (B'ₖᵀ B'ₖ − B'₀ᵀ B'₀) M. Subtracting the observational conjugation identity from the k-th one.hypothesesProof (Lean source)
theorem gram_diff_transport (S S' : Solution d p K) {M : Matrix (Fin d) (Fin d) ℝ} (hM : S'.H = M * S.H) (hΘ0 : S.Theta0 = S'.Theta0) (hΘ : ∀ k, S.Theta k = S'.Theta k) (k : Fin K) : (S.Bint k).transpose * S.Bint k - S.B0.transpose * S.B0 = M.transpose * ((S'.Bint k).transpose * S'.Bint k - (S'.B0).transpose * S'.B0) * M := by have hk : (S.Bint k).transpose * S.Bint k = M.transpose * ((S'.Bint k).transpose * S'.Bint k) * M := by refine gram_identity_conj S S' hM ?_ have := hΘ k simp only [Solution.Theta, Matrix.mul_assoc] at this ⊢ exact this have h0 : S.B0.transpose * S.B0 = M.transpose * ((S'.B0).transpose * S'.B0) * M := by refine gram_identity_conj S S' hM ?_ simp only [Solution.Theta0, Matrix.mul_assoc] at hΘ0 ⊢ exact hΘ0 rw [hk, h0, Matrix.mul_sub, Matrix.sub_mul] -
conj_vecMulVec_transposetheorem — Mᵀ (u vᵀ) M = (Mᵀ u)(Mᵀ v)ᵀ (conjugation of a rank-one matrix by Mᵀ · M).hypotheses -
central_rank2_eqtheorem — (R1+C) The central rank-≤2 equation. Combining the Gram-difference transport Δₖ = Mᵀ Δ'ₖ M (gram_diff_transport) with the latent key identity (C) on both sides, Δₖ = λₖ²(eₖeₖᵀ) − wₖwₖᵀ and Δ'ₖ = λ'ₖ²(e'ₖe'ₖᵀ) − w'ₖw'ₖᵀ, gives the rank-≤2 identity in fully outer-product form, with the primed outer products transported by Mᵀ: λₖ²(eₖeₖᵀ) − wₖwₖᵀ = λ'ₖ²((Mᵀe'ₖ)(Mᵀe'ₖ)ᵀ) − (Mᵀw'ₖ)(Mᵀw'ₖ)ᵀ.hypothesesd :sharedℕp :sharedℕK :sharedℕS S' :Solution d p KhM :S'.H = M * S.HhΘ0 :S.Theta0 = S'.Theta0hΘ :∀ k, S.Theta k = S'.Theta kk :Fin KProof (Lean source)
theorem central_rank2_eq (S S' : Solution d p K) {M : Matrix (Fin d) (Fin d) ℝ} (hM : S'.H = M * S.H) (hΘ0 : S.Theta0 = S'.Theta0) (hΘ : ∀ k, S.Theta k = S'.Theta k) (k : Fin K) : (S.lam k) ^ 2 • vecMulVec (stdVec d (S.target k)) (stdVec d (S.target k)) - vecMulVec (S.B0.transpose *ᵥ stdVec d (S.target k)) (S.B0.transpose *ᵥ stdVec d (S.target k)) = (S'.lam k) ^ 2 • vecMulVec (M.transpose *ᵥ stdVec d (S'.target k)) (M.transpose *ᵥ stdVec d (S'.target k)) - vecMulVec (M.transpose *ᵥ (S'.B0.transpose *ᵥ stdVec d (S'.target k))) (M.transpose *ᵥ (S'.B0.transpose *ᵥ stdVec d (S'.target k))) := by have htrans := gram_diff_transport S S' hM hΘ0 hΘ k rw [latent_key_identity, latent_key_identity] at htrans rw [htrans, Matrix.mul_sub, Matrix.sub_mul, Matrix.mul_smul, Matrix.smul_mul, conj_vecMulVec_transpose, conj_vecMulVec_transpose] -
transpose_mulVec_stdVectheorem — Mᵀ *ᵥ eᵢ is the i-th row of M, viewed as a vector: (Mᵀ *ᵥ eᵢ) j = Mᵢⱼ. This is the bridge that turns the transported outer products of central_rank2_eq into statements about the rows of M.hypothesesconclusionM.transpose *ᵥ stdVec n i = (fun j => M i j) -
B0_source_rowtheorem — (R3 ingredient) The iₖ-th row of B₀ at a source. If iₖ is a *source* node (no parents: (B₀)_{iₖ,j} = 0 for every j ≠ iₖ), then wₖ = B₀ᵀ *ᵥ e_{iₖ} = β e_{iₖ} with β = (B₀)_{iₖ,iₖ} > 0. This collapses the latent key identity (C) to the rank-one Δₖ = (λₖ² − β²) e_{iₖ} e_{iₖ}ᵀ, the base case of the monomial induction (R3): the transported equation then forces the i'ₖ-th row of M to be a multiple of e_{iₖ}.hypothesesProof (Lean source)
theorem B0_source_row (S : Solution d p K) (i : Fin d) (hsrc : ∀ j, j ≠ i → S.B0 i j = 0) : S.B0.transpose *ᵥ stdVec d i = (S.B0 i i) • stdVec d i := by funext j rw [Matrix.mulVec_transpose, Matrix.vecMul_eq_sum] simp only [stdVec, Finset.sum_apply, Pi.smul_apply, smul_eq_mul] rw [Finset.sum_eq_single i] · rw [Pi.single_eq_same, one_mul] by_cases hj : j = i · subst hj; rw [Pi.single_eq_same, mul_one] · rw [Pi.single_eq_of_ne hj, mul_zero]; exact hsrc j hj · intro x _ hx; rw [Pi.single_eq_of_ne hx, zero_mul] · intro hx; exact absurd (Finset.mem_univ _) hx -
permMat_mulVec_stdVectheorem — permMat σ *ᵥ eᵢ = e_{σ i}: the permutation matrix sends the i-th basis vector to the σ(i)-th.hypotheses -
diag_permMat_mulVec_stdVectheorem — A signed permutation matrix sends eᵢ to the signed basis vector ν (σ i) • e_{σ i}.hypothesesProof (Lean source)
theorem diag_permMat_mulVec_stdVec (σ : Perm (Fin d)) (ν : Fin d → ℝ) (i : Fin d) : (diagonal ν * permMat σ) *ᵥ stdVec d i = (ν (σ i)) • stdVec d (σ i) := by rw [← Matrix.mulVec_mulVec, permMat_mulVec_stdVec] funext a rw [Matrix.mulVec_diagonal] simp only [Pi.smul_apply, smul_eq_mul] by_cases ha : a = σ i · subst ha rw [stdVec, Pi.single_eq_same, mul_one] · rw [stdVec, Pi.single_eq_of_ne ha, mul_zero, mul_zero] -
target_readofftheorem — Signed target read-off. Suppose the collapse holds for context k and the observational context: B'ₖ M = diagonal ν permMat σ Bₖ and B'₀ M = diagonal ν permMat σ B₀, with Θₖ ≠ Θ₀. Then the primed target equals the relabelled target: i'ₖ = σ(iₖ).hypothesesd :sharedℕp :sharedℕK :sharedℕS S' :Solution d p Kν :Fin d → ℝk :Fin Khk :S.Theta k ≠ S.Theta0hν :∀ i, ν i = 1 ∨ ν i = -1conclusionS'.target k = σ (S.target k)Proof (Lean source)
theorem target_readoff (S S' : Solution d p K) {M : Matrix (Fin d) (Fin d) ℝ} {σ : Perm (Fin d)} {ν : Fin d → ℝ} (k : Fin K) (hk : S.Theta k ≠ S.Theta0) (hν : ∀ i, ν i = 1 ∨ ν i = -1) (hBk : S'.Bint k * M = diagonal ν * permMat σ * S.Bint k) (hB0 : S'.B0 * M = diagonal ν * permMat σ * S.B0) : S'.target k = σ (S.target k) := by -- Subtract the observational relation: -- `(B'ₖ − B'₀) M = diagonal ν permMat σ (Bₖ − B₀)`. have hsub : (S'.Bint k - S'.B0) * M = diagonal ν * permMat σ * (S.Bint k - S.B0) := by rw [Matrix.sub_mul, Matrix.mul_sub, hBk, hB0] -- Rewrite both sides as rank-one (outer-product) matrices. rw [Bint_sub_B0, Bint_sub_B0, Matrix.vecMulVec_mul, Matrix.mul_vecMulVec, diag_permMat_mulVec_stdVec] at hsub -- Pick an index `b` where `cₖ` is non-zero. obtain ⟨b, hb⟩ := Function.ne_iff.mp (cvec_ne_zero S k hk) rw [Pi.zero_apply] at hb -- Compare the `(σ iₖ, b)` entries of the two rank-one matrices. have hentry := congrFun (congrFun hsub (σ (S.target k))) b simp only [Matrix.vecMulVec_apply, Pi.smul_apply, smul_eq_mul, stdVec, Pi.single_eq_same] at hentry have hνne : ν (σ (S.target k)) ≠ 0 := by rcases hν (σ (S.target k)) with h | h <;> rw [h] <;> norm_num -- LHS `(e_{i'ₖ})_{σ iₖ} · (Mᵀ c'ₖ)_b = (cₖ)_b ≠ 0` forces `(e_{i'ₖ})_{σ iₖ} ≠ 0`. by_contra hne rw [Pi.single_eq_of_ne (fun h => hne h.symm), zero_mul] at hentry exact (mul_ne_zero (mul_ne_zero hνne one_ne_zero) hb) hentry.symm -
sum_smul_vecMulVec_stdVec_eq_diagonaltheorem — ∑ n, (c n) • (e_n e_nᵀ) = diagonal c (the rank-one standard-basis outer products sum to a diagonal matrix).hypothesesn :ℕc :Fin n → ℝProof (Lean source)
theorem sum_smul_vecMulVec_stdVec_eq_diagonal {n : ℕ} (c : Fin n → ℝ) : (∑ i, (c i) • vecMulVec (stdVec n i) (stdVec n i)) = diagonal c := by ext a b simp only [Matrix.sum_apply, Matrix.smul_apply, Matrix.vecMulVec_apply, stdVec, Pi.single_apply, smul_eq_mul, Matrix.diagonal_apply] rw [Finset.sum_eq_single a] · by_cases hab : a = b · subst hab; simp · simp [hab, Ne.symm hab] · intro x _ hx; simp [Ne.symm hx] · intro hx; exact absurd (Finset.mem_univ a) hx -
sum_latent_diff_unprimedtheorem — (S1) The unprimed SUM TRICK. Let kof be a section of the surjective target map (S.target (kof n) = n). Summing the latent key identity over kof gives ∑ₙ (B_{kof n}ᵀ B_{kof n} − B₀ᵀB₀) = diagonal(d) − B₀ᵀB₀ with d n = (λ_{kof n})².hypothesesProof (Lean source)
theorem sum_latent_diff_unprimed (S : Solution d p K) (kof : Fin d → Fin K) (hkof : ∀ n, S.target (kof n) = n) : (∑ n, ((S.Bint (kof n)).transpose * S.Bint (kof n) - S.B0.transpose * S.B0)) = diagonal (fun n => (S.lam (kof n)) ^ 2) - S.B0.transpose * S.B0 := by -- Rewrite each summand by the latent key identity. have hterm : ∀ n, (S.Bint (kof n)).transpose * S.Bint (kof n) - S.B0.transpose * S.B0 = (S.lam (kof n)) ^ 2 • vecMulVec (stdVec d n) (stdVec d n) - vecMulVec (S.B0.transpose *ᵥ stdVec d n) (S.B0.transpose *ᵥ stdVec d n) := by intro n rw [latent_key_identity S (kof n), hkof n] rw [Finset.sum_congr rfl (fun n _ => hterm n)] have hdistrib : (∑ n, ((S.lam (kof n)) ^ 2 • vecMulVec (stdVec d n) (stdVec d n) - vecMulVec (S.B0.transpose *ᵥ stdVec d n) (S.B0.transpose *ᵥ stdVec d n))) = (∑ n, (S.lam (kof n)) ^ 2 • vecMulVec (stdVec d n) (stdVec d n)) - ∑ n, vecMulVec (S.B0.transpose *ᵥ stdVec d n) (S.B0.transpose *ᵥ stdVec d n) := Finset.sum_sub_distrib .. rw [hdistrib, sum_smul_vecMulVec_stdVec_eq_diagonal, ← fact_transpose_mul S.B0] -
orthogonal_of_diag_conjtheorem — (S2) Diagonal conjugation ⟹ orthogonal rescaling. From Mᵀ diag(d') M = diag(d) with d, d' strictly positive, the matrix O = diag(fun i => √(d' i)) * M * diag(fun i => (√(d i))⁻¹) is orthogonal: Oᵀ O = 1.hypotheseshd :∀ i, 0 < dv ihd' :∀ i, 0 < dv' iProof (Lean source)
theorem orthogonal_of_diag_conj {q : ℕ} {M : Matrix (Fin q) (Fin q) ℝ} {dv dv' : Fin q → ℝ} (hd : ∀ i, 0 < dv i) (hd' : ∀ i, 0 < dv' i) (hconj : M.transpose * diagonal dv' * M = diagonal dv) : (diagonal (fun i => sqrt (dv' i)) * M * diagonal (fun i => (sqrt (dv i))⁻¹)).transpose * (diagonal (fun i => sqrt (dv' i)) * M * diagonal (fun i => (sqrt (dv i))⁻¹)) = 1 := by -- `diag(√d')ᵀ diag(√d') = diag(d')` and `diag(1/√d) diag(d) diag(1/√d) = 1`. have hsqrt' : diagonal (fun i => sqrt (dv' i)) * diagonal (fun i => sqrt (dv' i)) = diagonal dv' := by rw [Matrix.diagonal_mul_diagonal] congr 1; funext i exact Real.mul_self_sqrt (le_of_lt (hd' i)) have hdpos : ∀ i, sqrt (dv i) ≠ 0 := fun i => (Real.sqrt_pos.mpr (hd i)).ne' have hkill : diagonal (fun i => (sqrt (dv i))⁻¹) * diagonal dv * diagonal (fun i => (sqrt (dv i))⁻¹) = 1 := by rw [Matrix.diagonal_mul_diagonal, Matrix.diagonal_mul_diagonal] rw [show (fun i => (sqrt (dv i))⁻¹ * dv i * (sqrt (dv i))⁻¹) = (fun _ => (1 : ℝ)) from ?_, Matrix.diagonal_one] funext i have hsq : sqrt (dv i) * sqrt (dv i) = dv i := Real.mul_self_sqrt (le_of_lt (hd i)) have : (sqrt (dv i))⁻¹ * dv i * (sqrt (dv i))⁻¹ = (sqrt (dv i))⁻¹ * (sqrt (dv i) * sqrt (dv i)) * (sqrt (dv i))⁻¹ := by rw [hsq] rw [this] field_simp rw [div_self (hdpos i)] rw [Matrix.transpose_mul, Matrix.transpose_mul, Matrix.diagonal_transpose, Matrix.diagonal_transpose] -- Regroup everything right-associated, insert `D₁ D₁ = diag(d')`, then `Mᵀ diag(d') M = diag(d)`. -- Target: D₂ (Mᵀ (D₁ D₁) M) D₂ = D₂ (Mᵀ diag(d') M) D₂ = D₂ diag(d) D₂ = 1. have key : diagonal (fun i => (sqrt (dv i))⁻¹) * (M.transpose * diagonal dv' * M) * diagonal (fun i => (sqrt (dv i))⁻¹) = 1 := by rw [hconj]; exact hkill -- Normalize `key` to right-associated form, insert `diag(d') = D₁ D₁`, finish. have key' := key simp only [Matrix.mul_assoc] at key' ⊢ rw [← hsqrt'] at key' simp only [Matrix.mul_assoc] at key' exact key' -
permMat_apply_symmtheorem — (permMat σ) a c = 1 iff c = σ.symm a, else 0 (column read-off of permMat).hypothesesconclusionpermMat σ a c = if c = σ.symm a then (1 : ℝ) else 0Proof (Lean source)
theorem permMat_apply_symm (σ : Perm (Fin d)) (a c : Fin d) : permMat σ a c = if c = σ.symm a then (1 : ℝ) else 0 := by simp only [permMat, Matrix.of_apply] by_cases h : c = σ.symm a · subst h; simp [Equiv.apply_symm_apply] · rw [if_neg h, if_neg] exact fun hac => h (by rw [hac, Equiv.symm_apply_apply]) -
permMat_conj_applytheorem — Permutation conjugation entry. (permMat σ * X * (permMat σ)ᵀ) a b = X (σ.symm a) (σ.symm b): conjugating X by permMat σ relabels rows and columns by σ.symm.hypothesesProof (Lean source)
theorem permMat_conj_apply (σ : Perm (Fin d)) (X : Matrix (Fin d) (Fin d) ℝ) (a b : Fin d) : (permMat σ * X * (permMat σ).transpose) a b = X (σ.symm a) (σ.symm b) := by rw [Matrix.mul_apply] have hstep : ∀ c, (permMat σ * X) a c = X (σ.symm a) c := by intro c rw [Matrix.mul_apply] rw [Finset.sum_eq_single (σ.symm a)] · rw [permMat_apply_symm, if_pos rfl, one_mul] · intro x _ hx; rw [permMat_apply_symm, if_neg hx, zero_mul] · intro h; exact absurd (Finset.mem_univ _) h simp_rw [hstep, Matrix.transpose_apply, permMat_apply_symm] rw [Finset.sum_eq_single (σ.symm b)] · rw [if_pos rfl, mul_one] · intro x _ hx; rw [if_neg hx, mul_zero] · intro h; exact absurd (Finset.mem_univ _) h -
exists_orderPermtheorem — (L4) Orthogonal correctness (full statement).hypothesesd :sharedℕp :sharedℕK :sharedℕS S' :Solution d p Khcov :Bijective S.targethcov' :Bijective S'.targethNondeg :∀ k, S.Theta k ≠ S.Theta0hΘ0 :S.Theta0 = S'.Theta0hΘ :∀ k, S.Theta k = S'.Theta khM :S'.H = M * S.Hconclusionconclusion 1i :μ i ≠ 0conclusion 2i :ν i = 1 ∨ ν i = -1conclusion 6k :S'.target k = σ (S.target k)Proof (Lean source)
theorem exists_orderPerm (S S' : Solution d p K) (hcov : Bijective S.target) (hcov' : Bijective S'.target) (hNondeg : ∀ k, S.Theta k ≠ S.Theta0) (hΘ0 : S.Theta0 = S'.Theta0) (hΘ : ∀ k, S.Theta k = S'.Theta k) {M : Matrix (Fin d) (Fin d) ℝ} (hM : S'.H = M * S.H) : ∃ (σ : Perm (Fin d)) (μ ν : Fin d → ℝ), S.InSG σ ∧ (∀ i, μ i ≠ 0) ∧ (∀ i, ν i = 1 ∨ ν i = -1) ∧ M = diagonal μ * permMat σ ∧ S'.B0 * M = diagonal ν * permMat σ * S.B0 ∧ (∀ k, S'.Bint k * M = diagonal ν * permMat σ * S.Bint k) ∧ (∀ k, S'.target k = σ (S.target k)) := by obtain ⟨σ, μ, ν, hσ, hμ, hν, hMeq, hB0rel, hBintrel⟩ := orthogonal_collapse S S' hcov hcov' hNondeg hΘ0 hΘ hM exact ⟨σ, μ, ν, hσ, hμ, hν, hMeq, hB0rel, hBintrel, fun k => target_readoff S S' k (hNondeg k) hν (hBintrel k) hB0rel⟩